Here it is, the new thread interface.
authorDave West <davew@uncensored.citadel.org>
Sun, 25 Nov 2007 22:15:18 +0000 (22:15 +0000)
committerDave West <davew@uncensored.citadel.org>
Sun, 25 Nov 2007 22:15:18 +0000 (22:15 +0000)
The code to handle threads is in sysdep.c
This new thread interface has caused a change to the way modules are
initialised. A modules init function is now called twice. First time
threading==0, second time threading==1. threading is a parameter passed
to the init function.
You should not create a thread until your init function has been called
with threading==1. See serv_fulltext.c as an example.
All of the modules init functions have been updated for this change.
The old RegisterThread stuff has gone away.
time_to_die has gone as it was used to tell threads to exit, we now use
CtdlThreadCheckStop() instead which return non zero if the thread should
exit.
The server will exit when all threads have stopped.
CtdlThreadCreate() handles creation of threads in a safe manner.
CtdlThreadSleep() is used to do a sleep in a thread.
CtdlThreadStop() is used to stop a thread.
CtdlThreadStopAll() stops all threads and thus causes the server to
exit.
Threads are cleanup when they die by the main server process (every 10
seconds) which originally did nothing useful.
CtdlThreadGC() will force a garbage collection now.
CtdlThreadGetCount() return the number of threads in the system not just
the number of workers.
CtdlThreadSelf() returns a pointer to this threads thread structure.
CtdlThreadName() returns a strdup'd string that is the threads name, you
need to free this. It also allows you to change a threads name.
CtdlThreadCancel() does the same as pthread_cancel except it also
informs our thread system. Don't use this if you can help it.

There are a lot of debug messages at the moment, they will go away once
stability is proven.

43 files changed:
citadel/citserver.c
citadel/database.h
citadel/database_sleepycat.c
citadel/housekeeping.c
citadel/include/ctdl_module.h
citadel/mk_module_init.sh
citadel/modules/autocompletion/serv_autocompletion.c
citadel/modules/bio/serv_bio.c
citadel/modules/calendar/serv_calendar.c
citadel/modules/chat/serv_chat.c
citadel/modules/checkpoint/serv_checkpoint.c [new file with mode: 0644]
citadel/modules/expire/serv_expire.c
citadel/modules/fulltext/serv_fulltext.c
citadel/modules/funambol/serv_funambol.c
citadel/modules/imap/serv_imap.c
citadel/modules/inetcfg/serv_inetcfg.c
citadel/modules/ldap/serv_ldap.c
citadel/modules/listsub/serv_listsub.c
citadel/modules/managesieve/serv_managesieve.c
citadel/modules/mrtg/serv_mrtg.c
citadel/modules/netfilter/serv_netfilter.c
citadel/modules/network/serv_network.c
citadel/modules/newuser/serv_newuser.c
citadel/modules/notes/serv_notes.c
citadel/modules/pager/serv_pager.c
citadel/modules/pas2/serv_pas2.c
citadel/modules/pop3/serv_pop3.c
citadel/modules/pop3client/serv_pop3client.c
citadel/modules/rssclient/serv_rssclient.c
citadel/modules/rwho/serv_rwho.c
citadel/modules/sieve/serv_sieve.c
citadel/modules/smtp/serv_smtp.c
citadel/modules/spam/serv_spam.c
citadel/modules/test/serv_test.c
citadel/modules/upgrade/serv_upgrade.c
citadel/modules/vandelay/serv_vandelay.c
citadel/modules/vcard/serv_vcard.c
citadel/serv_extensions.c
citadel/serv_extensions.h
citadel/server_main.c
citadel/sysconfig.h
citadel/sysdep.c
citadel/sysdep_decls.h

index 6a85744a55ce04d0a653223c7af813b2d0bc07f4..cc27e4363c2d923dfd21c6f787a5f3b5ddc09359 100644 (file)
@@ -62,6 +62,9 @@
 #include "snprintf.h"
 #endif
 
+#include "ctdl_module.h"
+
+
 struct CitContext *ContextList = NULL;
 struct CitContext* next_session = NULL;
 char *unique_session_numbers;
@@ -176,7 +179,6 @@ void master_startup(void) {
  */
 void master_cleanup(int exitcode) {
        struct CleanupFunctionHook *fcn;
-       struct MaintenanceThreadHook *m_fcn;
        static int already_cleaning_up = 0;
 
        if (already_cleaning_up) while(1) sleep(1);
@@ -190,12 +192,6 @@ void master_cleanup(int exitcode) {
        /* Close the AdjRefCount queue file */
        AdjRefCount(-1, 0);
 
-       for (m_fcn = MaintenanceThreadHookTable; m_fcn != NULL; m_fcn = m_fcn->next) {
-               lprintf(CTDL_INFO, "Waiting for maintenance thread \"%s\" to shut down\n", m_fcn->name);
-               pthread_join(m_fcn->MaintenanceThread_tid, NULL);
-       }
-       
-
        /* Close databases */
        lprintf(CTDL_INFO, "Closing databases\n");
        close_databases();
@@ -826,7 +822,7 @@ void cmd_down(char *argbuf) {
        {
                cprintf(Reply, CIT_OK + SERVER_SHUTTING_DOWN);
        }
-       time_to_die = 1;
+       CtdlThreadStopAll();
 }
 
 /*
@@ -837,7 +833,7 @@ void cmd_halt(void) {
        if (CtdlAccessCheck(ac_aide)) return;
 
        cprintf("%d Halting server.  Goodbye.\n", CIT_OK);
-       time_to_die = 1;
+       CtdlThreadStopAll();
        shutdown_and_halt = 1;
 }
 
index b913faa87048e0b6f602d148841ac01801f82578..c7fe3833eca7e18707a193ae8e663e6eb18f2456 100644 (file)
@@ -17,6 +17,7 @@ void cdb_check_handles(void);
 void cdb_trunc(int cdb);
 void *checkpoint_thread(void *arg);
 void cdb_chmod_data(void);
+void cdb_checkpoint(void);
 
 /*
  * Database records beginning with this magic number are assumed to
index 2ca3bb9223e829085ddc3d27fdef167b62b58a03..ddd8edb12b407725f25c6304278c792369a84b7e 100644 (file)
@@ -280,16 +280,20 @@ void cmd_cull(char *argbuf) {
 /*
  * Request a checkpoint of the database.
  */
-static void cdb_checkpoint(void)
+void cdb_checkpoint(void)
 {
        int ret;
-       static time_t last_run = 0L;
+//     static time_t last_run = 0L;
 
        /* Only do a checkpoint once per minute. */
+/*
+ * Don't need this any more, since the thread that calls us sleeps for 60 seconds between calls
        if ((time(NULL) - last_run) < 60L) {
                return;
        }
        last_run = time(NULL);
+*/
 
        lprintf(CTDL_DEBUG, "-- db checkpoint --\n");
        ret = dbenv->txn_checkpoint(dbenv,
@@ -309,29 +313,6 @@ static void cdb_checkpoint(void)
 }
 
 
-/*
- * Main loop for the checkpoint thread.
- */
-void *checkpoint_thread(void *arg) {
-       struct CitContext checkpointCC;
-
-       lprintf(CTDL_DEBUG, "checkpoint_thread() initializing\n");
-
-       memset(&checkpointCC, 0, sizeof(struct CitContext));
-       checkpointCC.internal_pgm = 1;
-       checkpointCC.cs_pid = 0;
-       pthread_setspecific(MyConKey, (void *)&checkpointCC );
-
-       cdb_allocate_tsd();
-
-       while (!time_to_die) {
-               cdb_checkpoint();
-               sleep(1);
-       }
-
-       lprintf(CTDL_DEBUG, "checkpoint_thread() exiting\n");
-       pthread_exit(NULL);
-}
 
 /*
  * Open the various databases we'll be using.  Any database which
@@ -461,7 +442,6 @@ void open_databases(void)
 
        cdb_allocate_tsd();
        
-       CtdlRegisterMaintenanceThread ("checkpoint", checkpoint_thread);
 }
 
 
index cbc8a1c42c5c70506e2f79bad4b2d75c93d45fff..1dd18d61e82532a12556f58baf8cba923eaa128a 100644 (file)
@@ -43,6 +43,9 @@
 #include "msgbase.h"
 #include "journaling.h"
 
+#include "ctdl_module.h"
+
+
 /*
  * Terminate idle sessions.  This function pounds through the session table
  * comparing the current time to each session's time-of-last-command.  If an
@@ -76,8 +79,7 @@ void terminate_idle_sessions(void) {
 void check_sched_shutdown(void) {
        if ((ScheduledShutdown == 1) && (ContextList == NULL)) {
                lprintf(CTDL_NOTICE, "Scheduled shutdown initiating.\n");
-               time_to_die = 1;
-               master_cleanup(0);
+               CtdlThreadStopAll();
        }
 }
 
@@ -168,8 +170,6 @@ void do_housekeeping(void) {
        JournalRunQueue();
 
        PerformSessionHooks(EVT_HOUSE); /* perform as needed housekeeping */
-       
-       ctdl_internal_thread_gc(0);
 
        /* Then, do the "once per minute" stuff... */
        if (do_perminute_housekeeping_now) {
index 51d5c9c7f88f537c55943b94fdafcf4c8b345e43..587adb4a81f007816e9f4e95f36501ef2da720fc 100644 (file)
@@ -11,9 +11,9 @@
  * define macros for module init stuff
  */
  
-#define CTDL_MODULE_INIT(module_name) char *ctdl_module_##module_name##_init (void)
+#define CTDL_MODULE_INIT(module_name) char *ctdl_module_##module_name##_init (int threading)
 
-#define CTDL_INIT_CALL(module_name) ctdl_module_##module_name##_init ()
+#define CTDL_INIT_CALL(module_name) ctdl_module_##module_name##_init (threading)
 
 
 /*
@@ -104,4 +104,19 @@ int CtdlDoDirectoryServiceFunc(char *cn, char *ou, void **object, char *module,
  */
 void CtdlModuleStartCryptoMsgs(char *ok_response, char *nosup_response, char *error_response);
 
+
+/*
+ * Citadel Threads API
+ */
+struct CtdlThreadNode *CtdlThreadCreate(char *name, long flags, void *(*thread_func) (void *arg), void *args);
+void CtdlThreadSleep(int secs);
+void CtdlThreadStop(struct CtdlThreadNode *thread);
+int CtdlThreadCheckStop(void);
+void CtdlThreadCancel(struct CtdlThreadNode *thread);
+char *CtdlThreadName(struct CtdlThreadNode *thread, char *name);
+struct CtdlThreadNode *CtdlThreadSelf(void);
+int CtdlThreadGetCount(void);
+void CtdlThreadGC(void);
+void CtdlThreadStopAll(void);
+
 #endif /* CTDL_MODULE_H */
index b75365be3cd05e9d95d092a7c337122959382d7a..aaa13f145b7e037b82585f1d4e4fce54211a3c4e 100755 (executable)
@@ -79,12 +79,15 @@ extern long DetailErrorFlags;
 
 
 
-void initialise_modules (void)
+void initialise_modules (int threading)
 {
     long filter;
     nSizErrmsg = 0;
 
-    lprintf (CTDL_INFO, "New citadel module init proceedure.\n");
+    if (threading)
+        CtdlLogPrintf (CTDL_INFO, "Initialise modules, CtdlThreads enabled.\n");
+    else
+        CtdlLogPrintf (CTDL_INFO, "Initialise modules, CtdlThreads not yet enabled.\n");
 EOF
 
 
@@ -100,7 +103,7 @@ cat <<EOF > $H_FILE
 #define MODULES_INIT_H
 #include "ctdl_module.h"
 extern size_t nSizErrmsg;
-void initialise_modules (void);
+void initialise_modules (int threading);
 
 EOF
 
index 02f09969c8ec916b856df617d82ac66ea0c5cf14..9faebfe9d2d3ae1bb76dbf0095ee7996fd4150c7 100644 (file)
@@ -249,8 +249,10 @@ void cmd_auto(char *argbuf) {
 
 
 CTDL_MODULE_INIT(autocompletion) {
-       CtdlRegisterProtoHook(cmd_auto, "AUTO", "Do recipient autocompletion");
-
+       if (!threading)
+       {
+               CtdlRegisterProtoHook(cmd_auto, "AUTO", "Do recipient autocompletion");
+       }
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index 8f875a43520fba1df0577404404ddd43b8f8d147..276e7d9811baebb88c87c05b36891335f0b257dd 100644 (file)
@@ -134,10 +134,12 @@ void cmd_lbio(char *cmdbuf) {
 
 CTDL_MODULE_INIT(bio)
 {
-        CtdlRegisterProtoHook(cmd_ebio, "EBIO", "Enter your bio");
-        CtdlRegisterProtoHook(cmd_rbio, "RBIO", "Read a user's bio");
-        CtdlRegisterProtoHook(cmd_lbio, "LBIO", "List users with bios");
-
+       if (!threading)
+       {
+               CtdlRegisterProtoHook(cmd_ebio, "EBIO", "Enter your bio");
+               CtdlRegisterProtoHook(cmd_rbio, "RBIO", "Read a user's bio");
+               CtdlRegisterProtoHook(cmd_lbio, "LBIO", "List users with bios");
+       }
        /* return our Subversion id for the Log */
         return "$Id$";
 }
index cd55a1339789224d74c61397c130d15f474d5e67..a560993376eddc6e92a9d8e82deb1e47e38bcf81 100644 (file)
@@ -2167,16 +2167,19 @@ void ical_fixed_output(char *ptr, int len) {
  */
 CTDL_MODULE_INIT(calendar)
 {
+       if (!threading)
+       {
 #ifdef CITADEL_WITH_CALENDAR_SERVICE
-       CtdlRegisterMessageHook(ical_obj_beforesave, EVT_BEFORESAVE);
-       CtdlRegisterMessageHook(ical_obj_aftersave, EVT_AFTERSAVE);
-       CtdlRegisterSessionHook(ical_create_room, EVT_LOGIN);
-       CtdlRegisterProtoHook(cmd_ical, "ICAL", "Citadel iCal commands");
-       CtdlRegisterSessionHook(ical_session_startup, EVT_START);
-       CtdlRegisterSessionHook(ical_session_shutdown, EVT_STOP);
-       CtdlRegisterFixedOutputHook("text/calendar", ical_fixed_output);
+               CtdlRegisterMessageHook(ical_obj_beforesave, EVT_BEFORESAVE);
+               CtdlRegisterMessageHook(ical_obj_aftersave, EVT_AFTERSAVE);
+               CtdlRegisterSessionHook(ical_create_room, EVT_LOGIN);
+               CtdlRegisterProtoHook(cmd_ical, "ICAL", "Citadel iCal commands");
+               CtdlRegisterSessionHook(ical_session_startup, EVT_START);
+               CtdlRegisterSessionHook(ical_session_shutdown, EVT_STOP);
+               CtdlRegisterFixedOutputHook("text/calendar", ical_fixed_output);
 #endif
-
+       }
+       
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index b62f48524c626538b712a09d7521e7291a20618e..c77b36ab902f7cc700d7ded0eb3d5c8fc866c7ba 100644 (file)
@@ -815,16 +815,19 @@ void cmd_reqt(char *argbuf) {
 
 CTDL_MODULE_INIT(chat)
 {
-       CtdlRegisterProtoHook(cmd_chat, "CHAT", "Begin real-time chat");
-       CtdlRegisterProtoHook(cmd_pexp, "PEXP", "Poll for instant messages");
-       CtdlRegisterProtoHook(cmd_gexp, "GEXP", "Get instant messages");
-       CtdlRegisterProtoHook(cmd_sexp, "SEXP", "Send an instant message");
-       CtdlRegisterProtoHook(cmd_dexp, "DEXP", "Disable instant messages");
-       CtdlRegisterProtoHook(cmd_reqt, "REQT", "Request client termination");
-       CtdlRegisterSessionHook(cmd_gexp_async, EVT_ASYNC);
-       CtdlRegisterSessionHook(delete_instant_messages, EVT_STOP);
-       CtdlRegisterXmsgHook(send_instant_message, XMSG_PRI_LOCAL);
-
+       if (!threading)
+       {
+               CtdlRegisterProtoHook(cmd_chat, "CHAT", "Begin real-time chat");
+               CtdlRegisterProtoHook(cmd_pexp, "PEXP", "Poll for instant messages");
+               CtdlRegisterProtoHook(cmd_gexp, "GEXP", "Get instant messages");
+               CtdlRegisterProtoHook(cmd_sexp, "SEXP", "Send an instant message");
+               CtdlRegisterProtoHook(cmd_dexp, "DEXP", "Disable instant messages");
+               CtdlRegisterProtoHook(cmd_reqt, "REQT", "Request client termination");
+               CtdlRegisterSessionHook(cmd_gexp_async, EVT_ASYNC);
+               CtdlRegisterSessionHook(delete_instant_messages, EVT_STOP);
+               CtdlRegisterXmsgHook(send_instant_message, XMSG_PRI_LOCAL);
+       }
+       
        /* return our Subversion id for the Log */
        return "$Id$";
 }
diff --git a/citadel/modules/checkpoint/serv_checkpoint.c b/citadel/modules/checkpoint/serv_checkpoint.c
new file mode 100644 (file)
index 0000000..819f198
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * $Id: serv_checkpoint.c 5756 2007-11-16 17:15:22Z ajc $
+ *
+ * checkpointing module for the database
+ */
+#include "sysdep.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#ifdef HAVE_DB_H
+#include <db.h>
+#elif defined(HAVE_DB4_DB_H)
+#include <db4/db.h>
+#else
+#error Neither <db.h> nor <db4/db.h> was found by configure. Install db4-devel.
+#endif
+
+
+#if DB_VERSION_MAJOR < 4 || DB_VERSION_MINOR < 1
+#error Citadel requires Berkeley DB v4.1 or newer.  Please upgrade.
+#endif
+
+#include "citadel.h"
+#include "server.h"
+#include "citserver.h"
+#include "database.h"
+#include "msgbase.h"
+#include "sysdep_decls.h"
+#include "config.h"
+
+#include "ctdl_module.h"
+/*
+ * Main loop for the checkpoint thread.
+ */
+void *checkpoint_thread(void *arg) {
+       struct CitContext checkpointCC;
+
+       CtdlLogPrintf(CTDL_DEBUG, "checkpoint_thread() initializing\n");
+
+       memset(&checkpointCC, 0, sizeof(struct CitContext));
+       checkpointCC.internal_pgm = 1;
+       checkpointCC.cs_pid = 0;
+       pthread_setspecific(MyConKey, (void *)&checkpointCC );
+
+       cdb_allocate_tsd();
+
+       while (!CtdlThreadCheckStop()) {
+               cdb_checkpoint();
+               CtdlThreadSleep(60);
+       }
+
+       CtdlLogPrintf(CTDL_DEBUG, "checkpoint_thread() exiting\n");
+       return NULL;
+}
+
+
+CTDL_MODULE_INIT(checkpoint) {
+       if (threading)
+       {
+               CtdlThreadCreate ("checkpoint", CTDLTHREAD_BIGSTACK, checkpoint_thread, NULL);
+       }
+       /* return our Subversion id for the Log */
+       return "$Id: serv_autocompletion.c 5756 2007-11-16 17:15:22Z ajc $";
+}
index 254ee5a10fbdd97d1e3ad17dd47b5874a114abab..4902af16b0a4d0aad4c3e74f6a2d99f930a95082 100644 (file)
@@ -844,9 +844,12 @@ void cmd_fsck(char *argbuf) {
 
 CTDL_MODULE_INIT(expire)
 {
-       CtdlRegisterSessionHook(purge_databases, EVT_TIMER);
-       CtdlRegisterProtoHook(cmd_fsck, "FSCK", "Check message ref counts");
-
+       if (!threading)
+       {
+               CtdlRegisterSessionHook(purge_databases, EVT_TIMER);
+               CtdlRegisterProtoHook(cmd_fsck, "FSCK", "Check message ref counts");
+       }
+       
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index 5ba8b5a37c74d21fee67fa7b2885b54ede4ff208..4a8bdc6440e03b8695ddacd4005cc22b69964901 100644 (file)
@@ -233,9 +233,13 @@ void do_fulltext_indexing(void) {
         * Make sure we don't run the indexer too frequently.
         * FIXME move the setting into config
         */
+/*
+ * The thread sleeps for 300 seconds so we don't need this here any more
        if ( (time(NULL) - last_index) < 300L) {
                return;
        }
+*/
 
        /*
         * Check to see whether the fulltext index is up to date; if there
@@ -293,7 +297,7 @@ void do_fulltext_indexing(void) {
                        ft_index_message(ft_newmsgs[i], 1);
 
                        /* Check to see if we need to quit early */
-                       if (time_to_die) {
+                       if (CtdlThreadCheckStop()) {
                                lprintf(CTDL_DEBUG, "Indexer quitting early\n");
                                ft_newhighest = ft_newmsgs[i];
                                break;
@@ -344,13 +348,13 @@ void *indexer_thread(void *arg) {
 
        cdb_allocate_tsd();
 
-       while (!time_to_die) {
+       while (!CtdlThreadCheckStop()) {
                do_fulltext_indexing();
-               sleep(1);
+               CtdlThreadSleep(300);
        }
 
        lprintf(CTDL_DEBUG, "indexer_thread() exiting\n");
-       pthread_exit(NULL);
+       return NULL;
 }
 
 
@@ -486,12 +490,17 @@ void ft_delete_remove(char *room, long msgnum)
 
 CTDL_MODULE_INIT(fulltext)
 {
-       initialize_ft_cache();
-       CtdlRegisterProtoHook(cmd_srch, "SRCH", "Full text search");
-       CtdlRegisterDeleteHook(ft_delete_remove);
-       CtdlRegisterSearchFuncHook(ft_search, "fulltext");
-       CtdlRegisterMaintenanceThread ("indexer", indexer_thread);
-
+       if (!threading)
+       {
+               initialize_ft_cache();
+               CtdlRegisterProtoHook(cmd_srch, "SRCH", "Full text search");
+               CtdlRegisterDeleteHook(ft_delete_remove);
+               CtdlRegisterSearchFuncHook(ft_search, "fulltext");
+       }
+       else
+       {
+               CtdlThreadCreate("indexer", CTDLTHREAD_BIGSTACK, indexer_thread, NULL);
+       }
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index 23b17b47099e3933be1d7831943270ec6003dbe2..e60c64a699c1c6056be891784b7c58bf459598b5 100644 (file)
@@ -249,9 +249,11 @@ int funambol_isAllowedByPrefs(long configMsgNum) {
 
 CTDL_MODULE_INIT(funambol)
 {
-       create_notify_queue();
-       CtdlRegisterSessionHook(do_notify_queue, EVT_TIMER);
-
+       if (!threading)
+       {
+               create_notify_queue();
+               CtdlRegisterSessionHook(do_notify_queue, EVT_TIMER);
+       }
        /* return our Subversion id for the Log */
         return "$Id$";
 }
index cd138b86d355d6cde0910581815e9d38843f367d..31b3e5c96fb9cad2f3c677e48a3892064c2c7902 100644 (file)
@@ -1596,14 +1596,17 @@ const char *CitadelServiceIMAPS="IMAPS";
  */
 CTDL_MODULE_INIT(imap)
 {
-       CtdlRegisterServiceHook(config.c_imap_port,
-                               NULL, imap_greeting, imap_command_loop, NULL, CitadelServiceIMAP);
+       if (!threading)
+       {
+               CtdlRegisterServiceHook(config.c_imap_port,
+                                       NULL, imap_greeting, imap_command_loop, NULL, CitadelServiceIMAP);
 #ifdef HAVE_OPENSSL
-       CtdlRegisterServiceHook(config.c_imaps_port,
-                               NULL, imaps_greeting, imap_command_loop, NULL, CitadelServiceIMAPS);
+               CtdlRegisterServiceHook(config.c_imaps_port,
+                                       NULL, imaps_greeting, imap_command_loop, NULL, CitadelServiceIMAPS);
 #endif
-       CtdlRegisterSessionHook(imap_cleanup_function, EVT_STOP);
-
+               CtdlRegisterSessionHook(imap_cleanup_function, EVT_STOP);
+       }
+       
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index 8fb48f19aec40551a50a82944dd4e6f18c56515e..06e61c88c75e337a86de45a0d6094db3c1e67127 100644 (file)
@@ -178,9 +178,12 @@ void inetcfg_init(void) {
 
 CTDL_MODULE_INIT(inetcfg)
 {
-       CtdlRegisterMessageHook(inetcfg_aftersave, EVT_AFTERSAVE);
-       inetcfg_init();
-
+       if (!threading)
+       {
+               CtdlRegisterMessageHook(inetcfg_aftersave, EVT_AFTERSAVE);
+               inetcfg_init();
+       }
+       
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index c2b786529fbb40b65025325f2b4497bb7a5d6fdb..ea84e6cdd7f5d72c88f6adda171f26b2d79edc6a 100644 (file)
@@ -539,32 +539,35 @@ void ldap_disconnect_timer(void)
  */
 CTDL_MODULE_INIT(ldap)
 {
+       if (!threading)
+       {
 #ifdef HAVE_LDAP
-       if (!IsEmptyStr(config.c_ldap_base_dn)) {
-               CtdlRegisterCleanupHook(serv_ldap_cleanup);
-               CtdlRegisterSessionHook(ldap_disconnect_timer, EVT_TIMER);
-               CtdlRegisterDirectoryServiceFunc(delete_from_ldap,
-                                                DIRECTORY_USER_DEL,
-                                                "ldap");
-               CtdlRegisterDirectoryServiceFunc(create_ldap_host_OU,
-                                                DIRECTORY_CREATE_HOST,
-                                                "ldap");
-               CtdlRegisterDirectoryServiceFunc(create_ldap_object,
-                                                DIRECTORY_CREATE_OBJECT,
-                                                "ldap");
-               CtdlRegisterDirectoryServiceFunc(add_ldap_object,
-                                                DIRECTORY_ATTRIB_ADD,
-                                                "ldap");
-               CtdlRegisterDirectoryServiceFunc(save_ldap_object,
-                                                DIRECTORY_SAVE_OBJECT,
-                                                "ldap");
-               CtdlRegisterDirectoryServiceFunc(free_ldap_object,
-                                                DIRECTORY_FREE_OBJECT,
-                                                "ldap");
-               create_ldap_root();
-       }
+               if (!IsEmptyStr(config.c_ldap_base_dn)) {
+                       CtdlRegisterCleanupHook(serv_ldap_cleanup);
+                       CtdlRegisterSessionHook(ldap_disconnect_timer, EVT_TIMER);
+                       CtdlRegisterDirectoryServiceFunc(delete_from_ldap,
+                                                        DIRECTORY_USER_DEL,
+                                                        "ldap");
+                       CtdlRegisterDirectoryServiceFunc(create_ldap_host_OU,
+                                                        DIRECTORY_CREATE_HOST,
+                                                        "ldap");
+                       CtdlRegisterDirectoryServiceFunc(create_ldap_object,
+                                                        DIRECTORY_CREATE_OBJECT,
+                                                        "ldap");
+                       CtdlRegisterDirectoryServiceFunc(add_ldap_object,
+                                                        DIRECTORY_ATTRIB_ADD,
+                                                        "ldap");
+                       CtdlRegisterDirectoryServiceFunc(save_ldap_object,
+                                                        DIRECTORY_SAVE_OBJECT,
+                                                        "ldap");
+                       CtdlRegisterDirectoryServiceFunc(free_ldap_object,
+                                                        DIRECTORY_FREE_OBJECT,
+                                                        "ldap");
+                       create_ldap_root();
+               }
 #endif                         /* HAVE_LDAP */
-
+       }
+       
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index 0eb2300f2247c241f327a0990d556ac7b28588f0..615bcc5b59685ed6ae7f9af456714d819b4d4b4e 100644 (file)
@@ -570,8 +570,11 @@ void cmd_subs(char *cmdbuf) {
  */
 CTDL_MODULE_INIT(listsub)
 {
-       CtdlRegisterProtoHook(cmd_subs, "SUBS", "List subscribe/unsubscribe");
-
+       if (!threading)
+       {
+               CtdlRegisterProtoHook(cmd_subs, "SUBS", "List subscribe/unsubscribe");
+       }
+       
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index e40007d3fa152f6ca747562c31d7d578bb12f041..f05966c82b63f363a4aef3631eb90280f0f4c13a 100644 (file)
@@ -585,22 +585,24 @@ void managesieve_cleanup_function(void) {
 const char* CitadelServiceManageSieve = "ManageSieve";
 CTDL_MODULE_INIT(managesieve)
 {
-
+       if (!threading)
+       {
 #ifdef HAVE_LIBSIEVE
-       CtdlRegisterServiceHook(config.c_managesieve_port,
-                               NULL,
-                               managesieve_greeting,
-                               managesieve_command_loop,
-                               NULL, 
-                               CitadelServiceManageSieve);
-       CtdlRegisterSessionHook(managesieve_cleanup_function, EVT_STOP);
+               CtdlRegisterServiceHook(config.c_managesieve_port,
+                                       NULL,
+                                       managesieve_greeting,
+                                       managesieve_command_loop,
+                                       NULL, 
+                                       CitadelServiceManageSieve);
+               CtdlRegisterSessionHook(managesieve_cleanup_function, EVT_STOP);
 
 #else  /* HAVE_LIBSIEVE */
 
-       lprintf(CTDL_INFO, "This server is missing libsieve.  Managesieve protocol is disabled..\n");
+               lprintf(CTDL_INFO, "This server is missing libsieve.  Managesieve protocol is disabled..\n");
 
 #endif /* HAVE_LIBSIEVE */
-
+       }
+       
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index dab0ab7b809ad90f33eaba51e503b37d08d85af6..dc3adfc3090ab02fa057c8635b52238ac81a942c 100644 (file)
@@ -130,8 +130,11 @@ void cmd_mrtg(char *argbuf) {
 
 CTDL_MODULE_INIT(mrtg)
 {
-        CtdlRegisterProtoHook(cmd_mrtg, "MRTG", "Supply stats to MRTG");
-
+       if (!threading)
+       {
+               CtdlRegisterProtoHook(cmd_mrtg, "MRTG", "Supply stats to MRTG");
+       }
+       
        /* return our Subversion id for the Log */
         return "$Id$";
 }
index 09fe8c0f990ab9d33b38c8baded797d78018c4da..026df8ffcca465983e3fad3a8ea460583b6f6ef4 100644 (file)
@@ -107,8 +107,11 @@ int filter_the_idiots(struct CtdlMessage *msg, char *target_room) {
 
 CTDL_MODULE_INIT(netfilter)
 {
-       CtdlRegisterNetprocHook(filter_the_idiots);
-
+       if (!threading)
+       {
+               CtdlRegisterNetprocHook(filter_the_idiots);
+       }
+       
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index 06363b92d3d8565fadfdd40923005f1e48f179e6..ad8618406e351ed120894159016974d340e04942 100644 (file)
@@ -2112,15 +2112,17 @@ int network_room_handler (struct ctdlroom *room)
  */
 CTDL_MODULE_INIT(network)
 {
-       create_spool_dirs();
-       CtdlRegisterProtoHook(cmd_gnet, "GNET", "Get network config");
-       CtdlRegisterProtoHook(cmd_snet, "SNET", "Set network config");
-       CtdlRegisterProtoHook(cmd_netp, "NETP", "Identify as network poller");
-       CtdlRegisterProtoHook(cmd_nsyn, "NSYN", "Synchronize room to node");
-       CtdlRegisterSessionHook(network_do_queue, EVT_TIMER);
-        CtdlRegisterRoomHook(network_room_handler);
-       CtdlRegisterCleanupHook(destroy_network_queue_room);
-       
+       if (!threading)
+       {
+               create_spool_dirs();
+               CtdlRegisterProtoHook(cmd_gnet, "GNET", "Get network config");
+               CtdlRegisterProtoHook(cmd_snet, "SNET", "Set network config");
+               CtdlRegisterProtoHook(cmd_netp, "NETP", "Identify as network poller");
+               CtdlRegisterProtoHook(cmd_nsyn, "NSYN", "Synchronize room to node");
+               CtdlRegisterSessionHook(network_do_queue, EVT_TIMER);
+               CtdlRegisterRoomHook(network_room_handler);
+               CtdlRegisterCleanupHook(destroy_network_queue_room);
+       }
 
        /* return our Subversion id for the Log */
        return "$Id$";
index ac47feb102d71a7971e6f9184dd6d54b7844eb2b..afcea7e541b0d991c9ddc7a776473bfa30ff0990 100644 (file)
@@ -97,8 +97,11 @@ void CopyNewUserGreetings(void) {
 
 CTDL_MODULE_INIT(newuser)
 {
-   CtdlRegisterSessionHook(CopyNewUserGreetings, EVT_LOGIN);
-
-   /* return our Subversion id for the Log */
-   return "$Id$";
+       if (!threading)
+       {
+               CtdlRegisterSessionHook(CopyNewUserGreetings, EVT_LOGIN);
+       }
+       
+       /* return our Subversion id for the Log */
+       return "$Id$";
 }
index 0dedda9e323c13d026377f8e0ea541620dea0728..c7a613c044ab3a1a704b2c8d21d83404c28a88c7 100644 (file)
@@ -106,8 +106,11 @@ int serv_notes_beforesave(struct CtdlMessage *msg)
 
 CTDL_MODULE_INIT(notes)
 {
-       CtdlRegisterMessageHook(serv_notes_beforesave, EVT_BEFORESAVE);
-
+       if (!threading)
+       {
+               CtdlRegisterMessageHook(serv_notes_beforesave, EVT_BEFORESAVE);
+       }
+       
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index bdafbc85f3dee67a1804fe3e4d78798b58ecead2..3570856e435d27d5b7f45faa1376c0d18b10572f 100644 (file)
@@ -228,9 +228,12 @@ char *pager_getUserPhoneNumber(long configMsgNum) {
 }
 CTDL_MODULE_INIT(pager)
 {
-       create_pager_queue();
-       CtdlRegisterSessionHook(do_pager_queue, EVT_TIMER);
-
+       if (!threading)
+       {
+               create_pager_queue();
+               CtdlRegisterSessionHook(do_pager_queue, EVT_TIMER);
+       }
+       
        /* return our Subversion id for the Log */
         return "$Id: serv_pager.c $";
 }
index 7df51d60dfcd19786d91a53e871b85b59a0f1c98..63bd213ae17d3ff3c12fdfc78985cfd7bc67d207 100644 (file)
@@ -88,8 +88,11 @@ void cmd_pas2(char *argbuf)
 
 CTDL_MODULE_INIT(pas2)
 {
-        CtdlRegisterProtoHook(cmd_pas2, "PAS2", "APOP-based login");
-
+       if (!threading)
+       {
+               CtdlRegisterProtoHook(cmd_pas2, "PAS2", "APOP-based login");
+       }
+       
        /* return our Subversion id for the Log */
         return "$Id$";
 }
index dcdbb8ec6d8b2c581ed164e883719ce0bfa35759..336926c5868c473a2e8e97672630813ec9293bb0 100644 (file)
@@ -716,22 +716,25 @@ const char *CitadelServicePop3S="POP3S";
 
 CTDL_MODULE_INIT(pop3)
 {
-       CtdlRegisterServiceHook(config.c_pop3_port,
-                               NULL,
-                               pop3_greeting,
-                               pop3_command_loop,
-                               NULL,
-                               CitadelServicePop3);
+       if(!threading)
+       {
+               CtdlRegisterServiceHook(config.c_pop3_port,
+                                       NULL,
+                                       pop3_greeting,
+                                       pop3_command_loop,
+                                       NULL,
+                                       CitadelServicePop3);
 #ifdef HAVE_OPENSSL
-       CtdlRegisterServiceHook(config.c_pop3s_port,
-                               NULL,
-                               pop3s_greeting,
-                               pop3_command_loop,
-                               NULL,
-                               CitadelServicePop3S);
+               CtdlRegisterServiceHook(config.c_pop3s_port,
+                                       NULL,
+                                       pop3s_greeting,
+                                       pop3_command_loop,
+                                       NULL,
+                                       CitadelServicePop3S);
 #endif
-       CtdlRegisterSessionHook(pop3_cleanup_function, EVT_STOP);
-
+               CtdlRegisterSessionHook(pop3_cleanup_function, EVT_STOP);
+       }
+       
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index 5046a985d4ff0aa4790b335c466bb6be2a52883d..b3227707b9495b9566ee720ae58f0c4471df68fb 100644 (file)
@@ -287,8 +287,11 @@ void pop3client_scan(void) {
 
 CTDL_MODULE_INIT(pop3client)
 {
-       CtdlRegisterSessionHook(pop3client_scan, EVT_TIMER);
-
+       if (!threading)
+       {
+               CtdlRegisterSessionHook(pop3client_scan, EVT_TIMER);
+       }
+       
        /* return our Subversion id for the Log */
         return "$Id$";
 }
index 868516907a7bbefa6dab1a9c3d1f86b4bb225fdf..c9461a673934ed8d45ad0231aa3abd9b3e36ee1d 100644 (file)
@@ -622,11 +622,15 @@ void rssclient_scan(void) {
 
 CTDL_MODULE_INIT(rssclient)
 {
+       if (!threading)
+       {
 #ifdef HAVE_EXPAT
-       CtdlRegisterSessionHook(rssclient_scan, EVT_TIMER);
+               CtdlRegisterSessionHook(rssclient_scan, EVT_TIMER);
 #else
-        lprintf(CTDL_INFO, "This server is missing the Expat XML parser.  RSS client will be disabled.\n");
+               lprintf(CTDL_INFO, "This server is missing the Expat XML parser.  RSS client will be disabled.\n");
 #endif
+       }
+       
        /* return our Subversion id for the Log */
         return "$Id: serv_rssclient.c 5652 2007-10-29 20:14:48Z ajc $";
 }
index 1c9f7a7a48e9fb59db3974287d2a14535fcf9484..16746dfe9f00d082a784c3504817f1ad28e9b3ff 100644 (file)
@@ -255,12 +255,15 @@ void cmd_stel(char *cmdbuf)
 
 CTDL_MODULE_INIT(rwho)
 {
-        CtdlRegisterProtoHook(cmd_rwho, "RWHO", "Display who is online");
-        CtdlRegisterProtoHook(cmd_hchg, "HCHG", "Masquerade hostname");
-        CtdlRegisterProtoHook(cmd_rchg, "RCHG", "Masquerade roomname");
-        CtdlRegisterProtoHook(cmd_uchg, "UCHG", "Masquerade username");
-        CtdlRegisterProtoHook(cmd_stel, "STEL", "Enter/exit stealth mode");
-
+       if(!threading)
+       {
+               CtdlRegisterProtoHook(cmd_rwho, "RWHO", "Display who is online");
+               CtdlRegisterProtoHook(cmd_hchg, "HCHG", "Masquerade hostname");
+               CtdlRegisterProtoHook(cmd_rchg, "RCHG", "Masquerade roomname");
+               CtdlRegisterProtoHook(cmd_uchg, "UCHG", "Masquerade username");
+               CtdlRegisterProtoHook(cmd_stel, "STEL", "Enter/exit stealth mode");
+       }
+       
        /* return our Subversion id for the Log */
         return "$Id$";
 }
index e92ebdc8f24b1e36622c81daf5ad632dd6632f5d..e6cf9aebf9ab6d05476a134c7196e2d9687f1c3c 100644 (file)
@@ -1292,22 +1292,24 @@ int serv_sieve_room(struct ctdlroom *room)
 
 CTDL_MODULE_INIT(sieve)
 {
-
+       if (!threading)
+       {
 #ifdef HAVE_LIBSIEVE
 
-       ctdl_sieve_init();
-       CtdlRegisterProtoHook(cmd_msiv, "MSIV", "Manage Sieve scripts");
+               ctdl_sieve_init();
+               CtdlRegisterProtoHook(cmd_msiv, "MSIV", "Manage Sieve scripts");
 
-        CtdlRegisterRoomHook(serv_sieve_room);
+               CtdlRegisterRoomHook(serv_sieve_room);
 
-        CtdlRegisterSessionHook(perform_sieve_processing, EVT_HOUSE);
+               CtdlRegisterSessionHook(perform_sieve_processing, EVT_HOUSE);
 
 #else  /* HAVE_LIBSIEVE */
 
-       lprintf(CTDL_INFO, "This server is missing libsieve.  Mailbox filtering will be disabled.\n");
+               lprintf(CTDL_INFO, "This server is missing libsieve.  Mailbox filtering will be disabled.\n");
 
 #endif /* HAVE_LIBSIEVE */
-
+       }
+       
         /* return our Subversion id for the Log */
        return "$Id$";
 }
index 77b2618ea055df4b82f474e6db1205d138ba1540..0376c1e47d2077f162d53e550e9182f4a84c1de9 100644 (file)
@@ -1814,48 +1814,51 @@ const char *CitadelServiceSMTP_LMTP_UNF="LMTP-UnF";
 
 CTDL_MODULE_INIT(smtp)
 {
-       CtdlRegisterServiceHook(config.c_smtp_port,     /* SMTP MTA */
-                               NULL,
-                               smtp_mta_greeting,
-                               smtp_command_loop,
-                               NULL, 
-                               CitadelServiceSMTP_MTA);
+       if (!threading)
+       {
+               CtdlRegisterServiceHook(config.c_smtp_port,     /* SMTP MTA */
+                                       NULL,
+                                       smtp_mta_greeting,
+                                       smtp_command_loop,
+                                       NULL, 
+                                       CitadelServiceSMTP_MTA);
 
 #ifdef HAVE_OPENSSL
-       CtdlRegisterServiceHook(config.c_smtps_port,
-                               NULL,
-                               smtps_greeting,
-                               smtp_command_loop,
-                               NULL,
-                               CitadelServiceSMTPS_MTA);
+               CtdlRegisterServiceHook(config.c_smtps_port,
+                                       NULL,
+                                       smtps_greeting,
+                                       smtp_command_loop,
+                                       NULL,
+                                       CitadelServiceSMTPS_MTA);
 #endif
 
-       CtdlRegisterServiceHook(config.c_msa_port,      /* SMTP MSA */
-                               NULL,
-                               smtp_msa_greeting,
-                               smtp_command_loop,
-                               NULL,
-                               CitadelServiceSMTP_MSA);
-
-       CtdlRegisterServiceHook(0,                      /* local LMTP */
-                               file_lmtp_socket,
-                               lmtp_greeting,
-                               smtp_command_loop,
-                               NULL,
-                               CitadelServiceSMTP_LMTP);
-
-       CtdlRegisterServiceHook(0,                      /* local LMTP */
-                               file_lmtp_unfiltered_socket,
-                               lmtp_unfiltered_greeting,
-                               smtp_command_loop,
-                               NULL,
-                               CitadelServiceSMTP_LMTP_UNF);
-
-       smtp_init_spoolout();
-       CtdlRegisterSessionHook(smtp_do_queue, EVT_TIMER);
-       CtdlRegisterSessionHook(smtp_cleanup_function, EVT_STOP);
-       CtdlRegisterProtoHook(cmd_smtp, "SMTP", "SMTP utility commands");
-
+               CtdlRegisterServiceHook(config.c_msa_port,      /* SMTP MSA */
+                                       NULL,
+                                       smtp_msa_greeting,
+                                       smtp_command_loop,
+                                       NULL,
+                                       CitadelServiceSMTP_MSA);
+
+               CtdlRegisterServiceHook(0,                      /* local LMTP */
+                                       file_lmtp_socket,
+                                       lmtp_greeting,
+                                       smtp_command_loop,
+                                       NULL,
+                                       CitadelServiceSMTP_LMTP);
+
+               CtdlRegisterServiceHook(0,                      /* local LMTP */
+                                       file_lmtp_unfiltered_socket,
+                                       lmtp_unfiltered_greeting,
+                                       smtp_command_loop,
+                                       NULL,
+                                       CitadelServiceSMTP_LMTP_UNF);
+
+               smtp_init_spoolout();
+               CtdlRegisterSessionHook(smtp_do_queue, EVT_TIMER);
+               CtdlRegisterSessionHook(smtp_cleanup_function, EVT_STOP);
+               CtdlRegisterProtoHook(cmd_smtp, "SMTP", "SMTP utility commands");
+       }
+       
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index 415f03cae768a71752953298fab621998b304c80..6ad7029441f3e0d7c3d157d93c4c66e68122f8c3 100644 (file)
@@ -148,8 +148,11 @@ bail:      close(sock);
 
 CTDL_MODULE_INIT(spam)
 {
-       CtdlRegisterMessageHook(spam_assassin, EVT_SMTPSCAN);
-
+       if (!threading)
+       {
+               CtdlRegisterMessageHook(spam_assassin, EVT_SMTPSCAN);
+       }
+       
        /* return our Subversion id for the Log */
         return "$Id$";
 }
index 356b167b5607c0d54dfd7435992ffd8a135aa89f..af49e8d322e6fbf0d0711fb38a4f3ad196253882 100644 (file)
@@ -59,11 +59,14 @@ void LoginTest(void) {
 CTDL_MODULE_INIT(test)
 {
 #if 0
-   CtdlRegisterCleanupHook(CleanupTest);
-   CtdlRegisterSessionHook(NewRoomTest, EVT_NEWROOM);
-   CtdlRegisterSessionHook(SessionStartTest, EVT_START);
-   CtdlRegisterSessionHook(SessionStopTest, EVT_STOP);
-   CtdlRegisterSessionHook(LoginTest, EVT_LOGIN);
+       if (!threading)
+       {
+               CtdlRegisterCleanupHook(CleanupTest);
+               CtdlRegisterSessionHook(NewRoomTest, EVT_NEWROOM);
+               CtdlRegisterSessionHook(SessionStartTest, EVT_START);
+               CtdlRegisterSessionHook(SessionStopTest, EVT_STOP);
+               CtdlRegisterSessionHook(LoginTest, EVT_LOGIN);
+       }
 #endif
 
    /* return our Subversion id for the Log */
index 8676ab9ae6146b9b27241c0b22a40f92755bc018..7188365563bbdaa095180af15dff312ba519c90f 100644 (file)
@@ -228,8 +228,11 @@ void check_server_upgrades(void) {
 
 CTDL_MODULE_INIT(upgrade)
 {
-       check_server_upgrades();
-
+       if (!threading)
+       {
+               check_server_upgrades();
+       }
+       
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index 576089f3ccd9492fb2bacd760cf80e3505411813..2464d9e3976e6c4d5bbc56fcf80fd98aec7b4213 100644 (file)
@@ -806,8 +806,11 @@ void cmd_artv(char *cmdbuf) {
 
 CTDL_MODULE_INIT(vandelay)
 {
-       CtdlRegisterProtoHook(cmd_artv, "ARTV", "import/export data store");
-
+       if (!threading)
+       {
+               CtdlRegisterProtoHook(cmd_artv, "ARTV", "import/export data store");
+       }
+       
        /* return our Subversion id for the Log */
        return "$Id$";
 }
index 7cb8d6d531f65b9506cf9ad96db26cbcc0c660ec..7580c0d2a864a8cffe70a0d4187f23d6ff6f4ec2 100644 (file)
@@ -1527,53 +1527,56 @@ CTDL_MODULE_INIT(vcard)
        char filename[256];
        FILE *fp;
 
-       CtdlRegisterSessionHook(vcard_session_login_hook, EVT_LOGIN);
-       CtdlRegisterMessageHook(vcard_upload_beforesave, EVT_BEFORESAVE);
-       CtdlRegisterMessageHook(vcard_upload_aftersave, EVT_AFTERSAVE);
-       CtdlRegisterDeleteHook(vcard_delete_remove);
-       CtdlRegisterProtoHook(cmd_regi, "REGI", "Enter registration info");
-       CtdlRegisterProtoHook(cmd_greg, "GREG", "Get registration info");
-       CtdlRegisterProtoHook(cmd_igab, "IGAB",
-                                       "Initialize Global Address Book");
-       CtdlRegisterProtoHook(cmd_qdir, "QDIR", "Query Directory");
-       CtdlRegisterProtoHook(cmd_gvsn, "GVSN", "Get Valid Screen Names");
-       CtdlRegisterProtoHook(cmd_gvea, "GVEA", "Get Valid Email Addresses");
-       CtdlRegisterProtoHook(cmd_dvca, "DVCA", "Dump VCard Addresses");
-       CtdlRegisterUserHook(vcard_newuser, EVT_NEWUSER);
-       CtdlRegisterUserHook(vcard_purge, EVT_PURGEUSER);
-       CtdlRegisterNetprocHook(vcard_extract_from_network);
-       CtdlRegisterSessionHook(store_harvested_addresses, EVT_TIMER);
-       CtdlRegisterFixedOutputHook("text/x-vcard", vcard_fixed_output);
-       CtdlRegisterFixedOutputHook("text/vcard", vcard_fixed_output);
-
-       /* Create the Global ADdress Book room if necessary */
-       create_room(ADDRESS_BOOK_ROOM, 3, "", 0, 1, 0, VIEW_ADDRESSBOOK);
+       if (!threading)
+       {
+               CtdlRegisterSessionHook(vcard_session_login_hook, EVT_LOGIN);
+               CtdlRegisterMessageHook(vcard_upload_beforesave, EVT_BEFORESAVE);
+               CtdlRegisterMessageHook(vcard_upload_aftersave, EVT_AFTERSAVE);
+               CtdlRegisterDeleteHook(vcard_delete_remove);
+               CtdlRegisterProtoHook(cmd_regi, "REGI", "Enter registration info");
+               CtdlRegisterProtoHook(cmd_greg, "GREG", "Get registration info");
+               CtdlRegisterProtoHook(cmd_igab, "IGAB",
+                                               "Initialize Global Address Book");
+               CtdlRegisterProtoHook(cmd_qdir, "QDIR", "Query Directory");
+               CtdlRegisterProtoHook(cmd_gvsn, "GVSN", "Get Valid Screen Names");
+               CtdlRegisterProtoHook(cmd_gvea, "GVEA", "Get Valid Email Addresses");
+               CtdlRegisterProtoHook(cmd_dvca, "DVCA", "Dump VCard Addresses");
+               CtdlRegisterUserHook(vcard_newuser, EVT_NEWUSER);
+               CtdlRegisterUserHook(vcard_purge, EVT_PURGEUSER);
+               CtdlRegisterNetprocHook(vcard_extract_from_network);
+               CtdlRegisterSessionHook(store_harvested_addresses, EVT_TIMER);
+               CtdlRegisterFixedOutputHook("text/x-vcard", vcard_fixed_output);
+               CtdlRegisterFixedOutputHook("text/vcard", vcard_fixed_output);
+
+               /* Create the Global ADdress Book room if necessary */
+               create_room(ADDRESS_BOOK_ROOM, 3, "", 0, 1, 0, VIEW_ADDRESSBOOK);
+
+               /* Set expiration policy to manual; otherwise objects will be lost! */
+               if (!lgetroom(&qr, ADDRESS_BOOK_ROOM)) {
+                       qr.QRep.expire_mode = EXPIRE_MANUAL;
+                       qr.QRdefaultview = VIEW_ADDRESSBOOK;    /* 2 = address book view */
+                       lputroom(&qr);
 
-       /* Set expiration policy to manual; otherwise objects will be lost! */
-       if (!lgetroom(&qr, ADDRESS_BOOK_ROOM)) {
-               qr.QRep.expire_mode = EXPIRE_MANUAL;
-               qr.QRdefaultview = VIEW_ADDRESSBOOK;    /* 2 = address book view */
-               lputroom(&qr);
-
-               /*
-                * Also make sure it has a netconfig file, so the networker runs
-                * on this room even if we don't share it with any other nodes.
-                * This allows the CANCEL messages (i.e. "Purge this vCard") to be
-                * purged.
-                */
-               assoc_file_name(filename, sizeof filename, &qr, ctdl_netcfg_dir);
-               fp = fopen(filename, "a");
-               if (fp != NULL) fclose(fp);
-               chown(filename, CTDLUID, (-1));
-       }
+                       /*
+                        * Also make sure it has a netconfig file, so the networker runs
+                        * on this room even if we don't share it with any other nodes.
+                        * This allows the CANCEL messages (i.e. "Purge this vCard") to be
+                        * purged.
+                        */
+                       assoc_file_name(filename, sizeof filename, &qr, ctdl_netcfg_dir);
+                       fp = fopen(filename, "a");
+                       if (fp != NULL) fclose(fp);
+                       chown(filename, CTDLUID, (-1));
+               }
 
-       /* for postfix tcpdict */
-       CtdlRegisterServiceHook(config.c_pftcpdict_port,        /* Postfix */
-                               NULL,
-                               check_get_greeting,
-                               check_get,
-                               NULL,
-                               CitadelServiceDICT_TCP);
+               /* for postfix tcpdict */
+               CtdlRegisterServiceHook(config.c_pftcpdict_port,        /* Postfix */
+                                       NULL,
+                                       check_get_greeting,
+                                       check_get,
+                                       NULL,
+                                       CitadelServiceDICT_TCP);
+       }
        
        /* return our Subversion id for the Log */
        return "$Id$";
index 5f65dbc7b466ecab49c0ca47c8d7bff9ea685230..18e42583002fd618c03dfb93c030575860226b85 100644 (file)
@@ -42,7 +42,6 @@ struct DeleteFunctionHook *DeleteHookTable = NULL;
 struct ServiceFunctionHook *ServiceHookTable = NULL;
 struct FixedOutputHook *FixedOutputTable = NULL;
 struct RoomFunctionHook *RoomHookTable = NULL;
-struct MaintenanceThreadHook *MaintenanceThreadHookTable = NULL;
 struct SearchFunctionHook *SearchFunctionHookTable = NULL;
 
 struct ProtoFunctionHook {
@@ -1044,19 +1043,6 @@ int PerformXmsgHooks(char *sender, char *recp, char *msg)
        return total_sent;
 }
 
-void CtdlRegisterMaintenanceThread(char *name, void *(*thread_proc)(void *arg))
-{
-       struct MaintenanceThreadHook *newfcn;
-
-       newfcn = (struct MaintenanceThreadHook *)
-           malloc(sizeof(struct MaintenanceThreadHook));
-       newfcn->name = name;
-       newfcn->next = MaintenanceThreadHookTable;
-       newfcn->fcn_ptr = thread_proc;
-       MaintenanceThreadHookTable = newfcn;
-
-       lprintf(CTDL_INFO, "Registered a new maintenance thread function\n");
-}
 
 
 
index a9e150b975ef69112d8d519d48b7595d0d5306e7..39cb0c92f0bc97cd434a668216d5936c6b931a30 100644 (file)
@@ -149,14 +149,6 @@ struct RoomFunctionHook {
 extern struct RoomFunctionHook *RoomHookTable;
 
 
-struct MaintenanceThreadHook {
-       struct MaintenanceThreadHook *next;
-       char *name;
-       void *(*fcn_ptr) (void *arg);
-       pthread_t MaintenanceThread_tid;
-};
-extern struct MaintenanceThreadHook *MaintenanceThreadHookTable;
-
 
 struct SearchFunctionHook {
        struct SearchFunctionHook *next;
index 7edc6ad16e78134f34e33153dcfd8197cd545a6d..b553904f0d08922bce0cb88805ece323cb24c199 100644 (file)
@@ -276,11 +276,7 @@ int main(int argc, char **argv)
        lprintf(CTDL_INFO, "Initializing server extensions\n");
        size = strlen(ctdl_home_directory) + 9;
        
-/*
-       initialize_server_extensions();
-*/
-       
-       initialise_modules();
+       initialise_modules(0);
        
        
 
@@ -325,26 +321,35 @@ int main(int argc, char **argv)
        /* We want to check for idle sessions once per minute */
        CtdlRegisterSessionHook(terminate_idle_sessions, EVT_TIMER);
 
+       /*
+        * Initialise the thread system
+        */
+       ctdl_thread_internal_init();
+       
        /*
         * Now create a bunch of worker threads.
         */
-       lprintf(CTDL_DEBUG, "Starting %d worker threads\n",
+       CtdlLogPrintf(CTDL_DEBUG, "Starting %d worker threads\n",
                config.c_min_workers-1);
-       begin_critical_section(S_WORKER_LIST);
+       begin_critical_section(S_THREAD_LIST);
        for (i=0; i<(config.c_min_workers-1); ++i) {
-               create_worker();
+               ctdl_internal_create_thread("Worker Thread", CTDLTHREAD_BIGSTACK + CTDLTHREAD_WORKER, worker_thread, NULL);
        }
-       end_critical_section(S_WORKER_LIST);
+       end_critical_section(S_THREAD_LIST);
 
-       /* Create the maintenance threads. */
-       create_maintenance_threads();
+       /* Second call to module init functions now that threading is up */
+       initialise_modules(1);
 
-       /* This thread is now useless.  It can't be turned into a worker
-        * thread because its stack is too small, but it can't be killed
-        * either because the whole server process would exit.  So we just
-        * join to the first worker thread and exit when it exits.
+       /*
+        * This thread is now used for garbage collection of other threads in the thread list
+        */
+       CtdlLogPrintf(CTDL_INFO, "Startup thread %d becoming garbage collector,\n", pthread_self());
+       while (CtdlThreadGetCount())
+               ctdl_internal_thread_gc();
+       /*
+        * If the above loop exits we must be shutting down since we obviously have no threads
         */
-       pthread_join(worker_list->tid, NULL);
-       master_cleanup(0);
+               
+       master_cleanup(exit_signal);
        return(0);
 }
index 62a16757064b374a7fb14a5c79c4edff546a0f57..98dc149cf554de3596678a53e2ac823089e4be78 100644 (file)
 /*
  * The size of per-thread stacks.  If set too low, citserver will randomly crash.
  */
-#define THREADSTACKSIZE                1048576
+#define THREADSTACKSIZE                0x100000
 
 /*
  * How many messages may the full text indexer scan before flushing its
index 43a4bdec27ebc165d277027cabd405736d4161f0..87c7a9e8d0428f8ab61effb3cbcdd40f7daf1133 100644 (file)
@@ -72,6 +72,7 @@
 #include "snprintf.h"
 #endif
 
+#include "ctdl_module.h"
 
 #ifdef DEBUG_MEMORY_LEAKS
 struct igheap {
@@ -93,13 +94,12 @@ int verbosity = DEFAULT_VERBOSITY;          /* Logging level */
 struct CitContext masterCC;
 time_t last_purge = 0;                         /* Last dead session purge */
 static int num_threads = 0;                    /* Current number of threads */
+static int num_workers = 0;                    /* Current number of worker threads */
 int num_sessions = 0;                          /* Current number of sessions */
 
 int syslog_facility = LOG_DAEMON;
 int enable_syslog = 0;
 
-void DestroyWorkerList(void);
-
 
 /*
  * Create an interface to lprintf that follows the coding convention.
@@ -173,15 +173,15 @@ void vlprintf(enum LogLevel loglevel, const char *format, va_list arg_ptr)
  * Signal handler to shut down the server.
  */
 
-volatile int time_to_die = 0;
+volatile int exit_signal = 0;
 volatile int shutdown_and_halt = 0;
 volatile int restart_server = 0;
 volatile int running_as_daemon = 0;
 
 static RETSIGTYPE signal_cleanup(int signum) {
-       lprintf(CTDL_DEBUG, "Caught signal %d; shutting down.\n", signum);
-       time_to_die = 1;
-       master_cleanup(signum);
+       CtdlLogPrintf(CTDL_DEBUG, "Caught signal %d; shutting down.\n", signum);
+       CtdlThreadStopAll();
+       exit_signal = signum;
 }
 
 
@@ -228,7 +228,7 @@ void init_sysdep(void) {
         * session to which the calling thread is currently bound.
         */
        if (pthread_key_create(&MyConKey, NULL) != 0) {
-               lprintf(CTDL_CRIT, "Can't create TSD key: %s\n",
+               CtdlLogPrintf(CTDL_CRIT, "Can't create TSD key: %s\n",
                        strerror(errno));
        }
 
@@ -268,7 +268,7 @@ void init_sysdep(void) {
  */
 void begin_critical_section(int which_one)
 {
-       /* lprintf(CTDL_DEBUG, "begin_critical_section(%d)\n", which_one); */
+       /* CtdlLogPrintf(CTDL_DEBUG, "begin_critical_section(%d)\n", which_one); */
 
        /* For all types of critical sections except those listed here,
         * ensure nobody ever tries to do a critical section within a
@@ -330,7 +330,7 @@ int ig_tcp_server(char *ip_addr, int port_number, int queue_len, char **errormes
                snprintf(*errormessage, SIZ, 
                                 "citserver: Can't create a socket: %s",
                                 strerror(errno));
-               lprintf(CTDL_EMERG, "%s\n", *errormessage);
+               CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
                return(-1);
        }
 
@@ -342,7 +342,7 @@ int ig_tcp_server(char *ip_addr, int port_number, int queue_len, char **errormes
                snprintf(*errormessage, SIZ, 
                                 "citserver: Can't bind: %s",
                                 strerror(errno));
-               lprintf(CTDL_EMERG, "%s\n", *errormessage);
+               CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
                close(s);
                return(-1);
        }
@@ -353,7 +353,7 @@ int ig_tcp_server(char *ip_addr, int port_number, int queue_len, char **errormes
                snprintf(*errormessage, SIZ, 
                                 "citserver: Can't set socket to non-blocking: %s",
                                 strerror(errno));
-               lprintf(CTDL_EMERG, "%s\n", *errormessage);
+               CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
                close(s);
                return(-1);
        }
@@ -363,7 +363,7 @@ int ig_tcp_server(char *ip_addr, int port_number, int queue_len, char **errormes
                snprintf(*errormessage, SIZ, 
                                 "citserver: Can't listen: %s",
                                 strerror(errno));
-               lprintf(CTDL_EMERG, "%s\n", *errormessage);
+               CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
                close(s);
                return(-1);
        }
@@ -391,7 +391,7 @@ int ig_uds_server(char *sockpath, int queue_len, char **errormessage)
                *errormessage = (char*) malloc(SIZ + 1);
                snprintf(*errormessage, SIZ, "citserver: can't unlink %s: %s",
                        sockpath, strerror(errno));
-               lprintf(CTDL_EMERG, "%s\n", *errormessage);
+               CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
                return(-1);
        }
 
@@ -405,7 +405,7 @@ int ig_uds_server(char *sockpath, int queue_len, char **errormessage)
                snprintf(*errormessage, SIZ, 
                         "citserver: Can't create a socket: %s",
                         strerror(errno));
-               lprintf(CTDL_EMERG, "%s\n", *errormessage);
+               CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
                return(-1);
        }
 
@@ -414,7 +414,7 @@ int ig_uds_server(char *sockpath, int queue_len, char **errormessage)
                snprintf(*errormessage, SIZ, 
                         "citserver: Can't bind: %s",
                         strerror(errno));
-               lprintf(CTDL_EMERG, "%s\n", *errormessage);
+               CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
                return(-1);
        }
 
@@ -424,7 +424,7 @@ int ig_uds_server(char *sockpath, int queue_len, char **errormessage)
                snprintf(*errormessage, SIZ, 
                         "citserver: Can't set socket to non-blocking: %s",
                         strerror(errno));
-               lprintf(CTDL_EMERG, "%s\n", *errormessage);
+               CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
                close(s);
                return(-1);
        }
@@ -434,7 +434,7 @@ int ig_uds_server(char *sockpath, int queue_len, char **errormessage)
                snprintf(*errormessage, SIZ, 
                         "citserver: Can't listen: %s",
                         strerror(errno));
-               lprintf(CTDL_EMERG, "%s\n", *errormessage);
+               CtdlLogPrintf(CTDL_EMERG, "%s\n", *errormessage);
                return(-1);
        }
 
@@ -473,7 +473,7 @@ struct CitContext *CreateNewContext(void) {
 
        me = (struct CitContext *) malloc(sizeof(struct CitContext));
        if (me == NULL) {
-               lprintf(CTDL_ALERT, "citserver: can't allocate memory!!\n");
+               CtdlLogPrintf(CTDL_ALERT, "citserver: can't allocate memory!!\n");
                return NULL;
        }
        memset(me, 0, sizeof(struct CitContext));
@@ -628,12 +628,12 @@ void client_write(char *buf, int nbytes)
                retval = write(Ctx->client_socket, &buf[bytes_written],
                        nbytes - bytes_written);
                if (retval < 1) {
-                       lprintf(CTDL_ERR,
+                       CtdlLogPrintf(CTDL_ERR,
                                "client_write(%d bytes) failed: %s (%d)\n",
                                nbytes - bytes_written,
                                strerror(errno), errno);
                        cit_backtrace();
-                       // lprintf(CTDL_DEBUG, "Tried to send: %s",  &buf[bytes_written]);
+                       // CtdlLogPrintf(CTDL_DEBUG, "Tried to send: %s",  &buf[bytes_written]);
                        Ctx->kill_me = 1;
                        return;
                }
@@ -761,7 +761,6 @@ int client_getln(char *buf, int bufsize)
 void sysdep_master_cleanup(void) {
        struct ServiceFunctionHook *serviceptr;
 
-/////  DestroyWorkerList();
        /*
         * close all protocol master sockets
         */
@@ -769,11 +768,11 @@ void sysdep_master_cleanup(void) {
            serviceptr = serviceptr->next ) {
 
                if (serviceptr->tcp_port > 0)
-                       lprintf(CTDL_INFO, "Closing listener on port %d\n",
+                       CtdlLogPrintf(CTDL_INFO, "Closing listener on port %d\n",
                                serviceptr->tcp_port);
 
                if (serviceptr->sockpath != NULL)
-                       lprintf(CTDL_INFO, "Closing listener on '%s'\n",
+                       CtdlLogPrintf(CTDL_INFO, "Closing listener on '%s'\n",
                                serviceptr->sockpath);
 
                close(serviceptr->msock);
@@ -961,159 +960,470 @@ int convert_login(char NameToConvert[]) {
  * remove the need for the calls to eCrashRegisterThread and friends
  */
 
-// FIXME: these defines should be else where
-#define CTDLTHREAD_BIGSTACK    0x0001
 
 struct CtdlThreadNode *CtdlThreadList = NULL;
-static pthread_mutex_t ThreadWaiterMutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t ThreadWaiterCond = PTHREAD_COND_INITIALIZER;
+
+/*
+ * Condition variable and Mutex for thread garbage collection
+ */
+static pthread_mutex_t thread_gc_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t thread_gc_cond = PTHREAD_COND_INITIALIZER;
+static pthread_t GC_thread;
+static char *CtdlThreadStates[CTDL_THREAD_LAST_STATE];
+/*
+ * Pinched the following bits regarding signals from Kannel.org
+ */
+/*
+ * Change this thread's signal mask to block user-visible signals
+ * (HUP, TERM, QUIT, INT), and store the old signal mask in
+ * *old_set_storage.
+ * Return 0 for success, or -1 if an error occurred.
+ */
+ /* 
+  * This does not work in Darwin alias MacOS X alias Mach kernel,
+  * however. So we define a dummy function doing nothing.
+  */
+#if defined(DARWIN_OLD)
+    static int pthread_sigmask();
+#endif
+  
+static int ctdl_thread_internal_block_signals(sigset_t *old_set_storage)
+{
+    int ret;
+    sigset_t block_signals;
+
+    ret = sigemptyset(&block_signals);
+    if (ret != 0) {
+        CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC. Couldn't initialize signal set\n");
+           return -1;
+    }
+    ret = sigaddset(&block_signals, SIGHUP);
+    ret |= sigaddset(&block_signals, SIGTERM);
+    ret |= sigaddset(&block_signals, SIGQUIT);
+    ret |= sigaddset(&block_signals, SIGINT);
+    if (ret != 0) {
+        CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC. Couldn't add signal to signal set.\n");
+           return -1;
+    }
+    ret = pthread_sigmask(SIG_BLOCK, &block_signals, old_set_storage);
+    if (ret != 0) {
+        CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC. Couldn't disable signals for thread creation\n");
+        return -1;
+    }
+    return 0;
+}
+
+static void ctdl_thread_internal_restore_signals(sigset_t *old_set)
+{
+    int ret;
+
+    ret = pthread_sigmask(SIG_SETMASK, old_set, NULL);
+    if (ret != 0) {
+        CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC. Couldn't restore signal set.\n");
+    }
+}
+
+
+void ctdl_thread_internal_init(void)
+{
+       GC_thread = pthread_self();
+       CtdlThreadStates[CTDL_THREAD_INVALID] = strdup ("Invalid Thread");
+       CtdlThreadStates[CTDL_THREAD_VALID] = strdup("Valid Thread");
+       CtdlThreadStates[CTDL_THREAD_CREATE] = strdup("Thread being Created");
+       CtdlThreadStates[CTDL_THREAD_CANCELLED] = strdup("Thread Cancelled");
+       CtdlThreadStates[CTDL_THREAD_EXITED] = strdup("Thread Exited");
+       CtdlThreadStates[CTDL_THREAD_STOPPING] = strdup("Thread Stopping");
+       CtdlThreadStates[CTDL_THREAD_STOP_REQ] = strdup("Thread Stop Requested");
+       CtdlThreadStates[CTDL_THREAD_SLEEPING] = strdup("Thread Sleeping");
+       CtdlThreadStates[CTDL_THREAD_RUNNING] = strdup("Thread Running");
+}
+
+/*
+ * A function to tell all threads to exit
+ */
+void CtdlThreadStopAll(void)
+{
+       struct CtdlThreadNode *this_thread;
+       
+       begin_critical_section(S_THREAD_LIST);
+       this_thread = CtdlThreadList;
+       while(this_thread)
+       {
+               pthread_mutex_lock(&this_thread->ThreadMutex); /* To prevent race condition of a sleeping thread */
+               if (this_thread->state > CTDL_THREAD_STOP_REQ)
+                       this_thread->state = CTDL_THREAD_STOP_REQ;
+               pthread_mutex_unlock(&this_thread->ThreadMutex);
+               pthread_cond_signal(&this_thread->ThreadCond);
+               CtdlLogPrintf(CTDL_DEBUG, "Thread system stopping thread \"%s\" (%ld).\n", this_thread->name, this_thread->tid);
+               this_thread = this_thread->next;
+       }
+       end_critical_section(S_THREAD_LIST);
+}
+
+
+/*
+ * A function to signal that we need to do garbage collection on the thread list
+ */
+void CtdlThreadGC(void)
+{
+       pthread_cond_signal(&thread_gc_cond);
+}
 
 
+/*
+ * A function to return the number of threads running in the system
+ */
+int CtdlThreadGetCount(void)
+{
+       return num_threads;
+}
+
+/*
+ * A function to find the thread structure for this thread
+ */
+struct CtdlThreadNode *CtdlThreadSelf(void)
+{
+       pthread_t self_tid;
+       struct CtdlThreadNode *this_thread;
+       
+       self_tid = pthread_self();
+       
+       begin_critical_section(S_THREAD_LIST);
+       this_thread = CtdlThreadList;
+       while(this_thread)
+       {
+               if (pthread_equal(self_tid, this_thread->tid))
+               {
+                       end_critical_section(S_THREAD_LIST);
+                       return this_thread;
+               }
+               this_thread = this_thread->next;
+       }
+       end_critical_section(S_THREAD_LIST);
+       return NULL;
+}
+
+
+
+
+/*
+ * A function to rename a thread
+ * Returns a char * and the caller owns the memory and should free it
+ */
+char *CtdlThreadName(struct CtdlThreadNode *thread, char *name)
+{
+       struct CtdlThreadNode *this_thread;
+       char *old_name;
+       
+       if (!thread)
+               this_thread = CtdlThreadSelf();
+       else
+               this_thread = thread;
+       if (!this_thread)
+       {
+               CtdlLogPrintf(CTDL_WARNING, "Thread system WARNING. Attempt to CtdlThreadRename() a non thread.\n");
+               return NULL;
+       }
+       begin_critical_section(S_THREAD_LIST);
+       if (name)
+       {
+               old_name = this_thread->name;
+               this_thread->name = strdup (name);
+               free(old_name);
+       }
+       old_name = strdup(this_thread->name);
+       end_critical_section (S_THREAD_LIST);
+       return (old_name);
+}      
+
+
+/*
+ * A function to force a thread to exit
+ */
+void CtdlThreadCancel(struct CtdlThreadNode *thread)
+{
+       struct CtdlThreadNode *this_thread;
+       
+       if (!thread)
+               this_thread = CtdlThreadSelf();
+       else
+               this_thread = thread;
+       if (!this_thread)
+       {
+               CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC. Attempt to CtdlThreadCancel() a non thread.\n");
+               CtdlThreadStopAll();
+               return;
+       }
+       begin_critical_section(S_THREAD_LIST);
+       this_thread->state = CTDL_THREAD_CANCELLED;
+       pthread_cancel(this_thread->tid);
+       end_critical_section (S_THREAD_LIST);
+}
+
+
+
+/*
+ * A function for a thread to check if it has been asked to stop
+ */
+int CtdlThreadCheckStop(void)
+{
+       struct CtdlThreadNode *this_thread;
+       
+       this_thread = CtdlThreadSelf();
+       if (!this_thread)
+       {
+               CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC, CtdlThreadCheckStop() called by a non thread.\n");
+               CtdlThreadStopAll();
+               return -1;
+       }
+       if(this_thread->state == CTDL_THREAD_STOP_REQ)
+       {
+               this_thread->state = CTDL_THREAD_STOPPING;
+               return -1;
+       }
+       else if(this_thread->state < CTDL_THREAD_STOP_REQ)
+               return -1;
+               
+       return 0;
+}
+
+
+/*
+ * A function to ask a thread to exit
+ * The thread must call CtdlThreadCheckStop() periodically to determine if it should exit
+ */
+void CtdlThreadStop(struct CtdlThreadNode *thread)
+{
+       struct CtdlThreadNode *this_thread;
+       
+       if (!thread)
+               this_thread = CtdlThreadSelf();
+       else
+               this_thread = thread;
+       if (!this_thread)
+               return;
+               
+       begin_critical_section (S_THREAD_LIST);
+       pthread_mutex_lock(&this_thread->ThreadMutex); /* To prevent race condition of a sleeping thread */
+       if (this_thread->state > CTDL_THREAD_STOP_REQ)
+               this_thread->state = CTDL_THREAD_STOP_REQ;
+       pthread_mutex_unlock(&this_thread->ThreadMutex);
+       pthread_cond_signal(&this_thread->ThreadCond);
+       end_critical_section(S_THREAD_LIST);
+}
+
 /*
  * So we now have a sleep command that works with threads but it is in seconds
  */
 void CtdlThreadSleep(int secs)
 {
-
        struct timespec wake_time;
        struct timeval time_now;
+       struct CtdlThreadNode *self;
+       int state;
        
        
+       self = CtdlThreadSelf();
+       if (!self)
+       {
+               CtdlLogPrintf(CTDL_WARNING, "CtdlThreadSleep() called by something that is not a thread. Should we die?\n");
+               return;
+       }
+       
+       begin_critical_section(S_THREAD_LIST);
+       pthread_mutex_lock(&self->ThreadMutex); /* Prevent something asking us to awaken before we've gone to sleep */
+       state = self->state;
+       if (state == CTDL_THREAD_RUNNING)
+               self->state = CTDL_THREAD_SLEEPING;
+       end_critical_section(S_THREAD_LIST);
+       
+       if(state != CTDL_THREAD_RUNNING)
+       {
+               CtdlLogPrintf(CTDL_DEBUG, "CtdlThreadSleep() called by a thread that is not running.\n");
+               pthread_mutex_unlock(&self->ThreadMutex);
+               return;
+       }
+       
        memset (&wake_time, 0, sizeof(struct timespec));
        gettimeofday(&time_now, NULL);
        wake_time.tv_sec = time_now.tv_sec + secs;
-       pthread_cond_timedwait(&ThreadWaiterCond, &ThreadWaiterMutex, &wake_time);
+       wake_time.tv_nsec = time_now.tv_usec * 10;
+       pthread_cond_timedwait(&self->ThreadCond, &self->ThreadMutex, &wake_time);
+       begin_critical_section(S_THREAD_LIST);
+       if (self->state == CTDL_THREAD_SLEEPING) /* Don't change state if something else changed it while we were asleep */
+               self->state = state;
+       pthread_mutex_unlock(&self->ThreadMutex);
+       end_critical_section(S_THREAD_LIST);
 }
 
 
 /*
  * Routine to clean up our thread function on exit
  */
-void ctdl_internal_thread_cleanup(void *arg)
+static void ctdl_internal_thread_cleanup(void *arg)
 {
        struct CtdlThreadNode *this_thread;
-       // arg is a pointer to our thread structure
-       this_thread = (struct CtdlThreadNode *) arg;
-       if (this_thread->valid)
-       {
-               /*
-                * In here we were called by the current thread because it is exiting
-                * NB. WE ARE THE CURRENT THREAD
-                */
-               CtdlLogPrintf(CTDL_NOTICE, "Thread \"%s\" (%ld) exited.\n", this_thread->name, this_thread->tid);
-               this_thread->running = FALSE;
-               this_thread->valid = FALSE;     // needs to be last thing else house keeping will unlink us too early
-               /*
-                * Our thread is exiting either because it wanted to end or because the server is stopping
-                * We need to clean up
-                */
-               #ifdef HAVE_BACKTRACE
-               eCrash_UnregisterThread();
-               #endif
-       }
-       else
-       {
-               if (this_thread->tid == pthread_self())
-               {
-                       CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC a thread is trying to clean up after itself.\n");
-                       time_to_die = -1;
-                       return;
-               }
-               /*
-                * In here we were called by some other thread that wants to clean up any dead threads
-                * NB. WE ARE NOT THE THREAD BEING CLEANED
-                */
-               // We probably got called by house keeping or master shutdown so we unlink the dead threads here
-               num_threads--;
-               
-               begin_critical_section(S_THREAD_LIST);
-               if(this_thread->name)
-                       free(this_thread->name);
-               if(this_thread->prev)
-                       this_thread->prev->next = this_thread->next;
-               if(this_thread->next)
-                       this_thread->next->prev = this_thread->next;
-               end_critical_section(S_THREAD_LIST);
-               free(this_thread);
-       }
+       this_thread = CtdlThreadSelf();
+       /*
+        * In here we were called by the current thread because it is exiting
+        * NB. WE ARE THE CURRENT THREAD
+        */
+       CtdlLogPrintf(CTDL_NOTICE, "Thread \"%s\" (%ld) exited.\n", this_thread->name, this_thread->tid);
+       begin_critical_section(S_THREAD_LIST);
+       #ifdef HAVE_BACKTRACE
+       eCrash_UnregisterThread();
+       #endif
+       this_thread->state = CTDL_THREAD_EXITED;        // needs to be last thing else house keeping will unlink us too early
+       end_critical_section(S_THREAD_LIST);
 }
 
 
+
+
 /*
  * Garbage collection routine.
- * Gets called by do_housekeeping() and in master_cleanup() to clean up the thread list
+ * Gets called by main() in a loop to clean up the thread list periodically.
  */
-void ctdl_internal_thread_gc (int shutdown)
+void ctdl_internal_thread_gc (void)
 {
        struct CtdlThreadNode *this_thread, *that_thread;
+       struct timespec wake_time;
+       struct timeval time_now;
+       int workers = 0;
        
+       /* 
+        * Wait on the condition variable that tells us garbage collection is needed
+        * We wake up every 10 seconds just in case someone forgot to inform us of a thread exiting
+        */
+       pthread_mutex_lock(&thread_gc_mutex);
+       memset (&wake_time, 0, sizeof(struct timespec));
+       gettimeofday(&time_now, NULL);
+       wake_time.tv_sec = time_now.tv_sec + 10;
+       pthread_cond_timedwait(&thread_gc_cond, &thread_gc_mutex, &wake_time);
+       
+       CtdlLogPrintf(CTDL_DEBUG, "Thread system running garbage collection.\n");
+       /*
+        * Woke up to do garbage collection
+        */
+       begin_critical_section(S_THREAD_LIST);
        this_thread = CtdlThreadList;
        while(this_thread)
        {
                that_thread = this_thread;
                this_thread = this_thread->next;
                
-               if(shutdown && that_thread->valid)
-               {       // We want the threads to shutdown so first ask it nicely
-                       that_thread->running = FALSE;
-                       // Wait for it to exit
-                       CtdlThreadSleep(1);
-                       
-                       if(that_thread->valid)  // Be more brutal about it
-                               pthread_cancel (that_thread->tid);
-                       // Wait for it to exit
-                       CtdlThreadSleep(1);
+               CtdlLogPrintf(CTDL_DEBUG, "CtdlThread, \"%s\" (%ld) \"%s\".\n", that_thread->name, that_thread->tid, CtdlThreadStates[that_thread->state]);
+               /* Do we need to clean up this thread? */
+               if (that_thread->state != CTDL_THREAD_EXITED)
+               {
+                       if(that_thread->flags & CTDLTHREAD_WORKER)
+                               workers++;      /* Sanity check on number of worker threads */
+                       continue;
                }
                
-               if (that_thread->valid == FALSE)
-               {
-                       CtdlLogPrintf(CTDL_NOTICE, "Joining thread \"%s\" (%ld)\n", that_thread->name, that_thread->tid);
-                       pthread_join(that_thread->tid, NULL);
-                       ctdl_internal_thread_cleanup(that_thread);
+               if (pthread_equal(that_thread->tid, pthread_self()))
+               {       /* Sanity check */
+                       end_critical_section(S_THREAD_LIST);
+                       CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC, a thread is trying to clean up after itself.\n");
+                       pthread_mutex_unlock(&thread_gc_mutex);
+                       CtdlThreadStopAll();
+                       return;
+               }
+               
+               if (num_threads <= 0)
+               {       /* Sanity check */
+                       end_critical_section (S_THREAD_LIST);
+                       CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC, num_threads <= 0 and trying to do Garbage Collection.\n");
+                       pthread_mutex_unlock(&thread_gc_mutex);
+                       CtdlThreadStopAll();
+                       return;
                }
+
+               /* If we are unlinking the list head then the next becomes the list head */
+               if (that_thread == CtdlThreadList)
+                       CtdlThreadList = that_thread->next;
+               if(that_thread->prev)
+                       that_thread->prev->next = that_thread->next;
+               if(that_thread->next)
+                       that_thread->next->prev = that_thread->next;
+               num_threads--;
+               if(that_thread->flags & CTDLTHREAD_WORKER)
+                       num_workers--;  /* This is a wroker thread so reduce the count. */
+               
+               /*
+                * Join on the thread to do clean up and prevent memory leaks
+                * Also makes sure the thread has cleaned up after itself before we remove it from the list
+                */
+               pthread_join (that_thread->tid, NULL);
+               
+               /*
+                * Now we own that thread entry
+                */
+               CtdlLogPrintf(CTDL_INFO, "Garbage Collection for thread \"%s\" (%ld).\n", that_thread->name, that_thread->tid);
+               if(that_thread->name)
+                       free(that_thread->name);
+               pthread_mutex_destroy(&that_thread->ThreadMutex);
+               pthread_cond_destroy(&that_thread->ThreadCond);
+               pthread_attr_destroy(&that_thread->attr);
+               free(that_thread);
+       }
+       
+       /* Sanity check number of worker threads */
+       if (workers != num_workers)
+       {
+               end_critical_section(S_THREAD_LIST);
+               CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC, discrepancy in number of worker threads. Counted %d, should be %d.\n", workers, num_workers);
+               pthread_mutex_unlock(&thread_gc_mutex);
+//             CtdlThreadStopAll();
+               return;
        }
+       pthread_mutex_unlock(&thread_gc_mutex);
+
+       end_critical_section(S_THREAD_LIST);
 }
+
+
+
  
 /*
  * Runtime function for a Citadel Thread.
  * This initialises the threads environment and then calls the user supplied thread function
  * Note that this is the REAL thread function and wraps the users thread function.
  */ 
-void *ctdl_internal_thread_func (void *arg)
+static void *ctdl_internal_thread_func (void *arg)
 {
        struct CtdlThreadNode *this_thread;
        void *ret = NULL;
 
+       /* lock and unlock the thread list.
+        * This causes this thread to wait until all its creation stuff has finished before it
+        * can continue its execution.
+        */
+       begin_critical_section(S_THREAD_LIST);
        // Get our thread data structure
        this_thread = (struct CtdlThreadNode *) arg;
+       this_thread->state = CTDL_THREAD_RUNNING;
+       this_thread->pid = getpid();
+       end_critical_section(S_THREAD_LIST);
+               
        // Tell the world we are here
-       CtdlLogPrintf(CTDL_NOTICE, "Spawned a new thread \"%s\" (%ld). \n", this_thread->name, this_thread->tid);
-
-       num_threads++;  // Increase the count of threads in the system.
-       
-       // Register for tracing
-       #ifdef HAVE_BACKTRACE
-       eCrash_RegisterThread(this_thread->name, 0);
-       #endif
+       CtdlLogPrintf(CTDL_NOTICE, "Created a new thread \"%s\" (%ld). \n", this_thread->name, this_thread->tid);
 
        // Register the cleanup function to take care of when we exit.
-       pthread_cleanup_push(ctdl_internal_thread_cleanup, arg);
+       pthread_cleanup_push(ctdl_internal_thread_cleanup, NULL);
        
-       this_thread->running = TRUE;
        
-       while ((!time_to_die) && (this_thread->running))
-       {       // Call the users thread function
-               ret = (this_thread->thread_func)(this_thread->user_args);
-       }
+       /*
+        * run the thread to do the work
+        */
+       ret = (this_thread->thread_func)(this_thread->user_args);
        
        /*
         * Our thread is exiting either because it wanted to end or because the server is stopping
         * We need to clean up
         */
-       #ifdef HAVE_BACKTRACE
-       eCrash_UnregisterThread();
-       #endif
-       
        pthread_cleanup_pop(1); // Execute our cleanup routine and remove it
        
        return(ret);
@@ -1125,30 +1435,33 @@ void *ctdl_internal_thread_func (void *arg)
  * Internal function to create a thread.
  * Must be called from within a S_THREAD_LIST critical section
  */ 
-int ctdl_internal_create_thread(char *name, int flags, void *(*thread_func) (void *arg), void *arg, struct CtdlThreadNode **new_thread)
+struct CtdlThreadNode *ctdl_internal_create_thread(char *name, long flags, void *(*thread_func) (void *arg), void *args)
 {
        int ret = 0;
-       pthread_attr_t attr;
        struct CtdlThreadNode *this_thread;
-       
-       if (*new_thread)
+       int sigtrick = 0;
+       sigset_t old_signal_set;
+
+       if (num_threads >= 32767)
        {
-               lprintf(CTDL_EMERG, "Possible attempt to overwrite an existing thread!!!\n");
-               return -1;
+               CtdlLogPrintf(CTDL_EMERG, "Thread system. Thread list full.\n");
+               return NULL;
        }
-       
+               
        this_thread = malloc(sizeof(struct CtdlThreadNode));
        if (this_thread == NULL) {
-               lprintf(CTDL_EMERG, "can't allocate CtdlThreadNode, exiting\n");
-               return ret;
+               CtdlLogPrintf(CTDL_EMERG, "Thread system, can't allocate CtdlThreadNode, exiting\n");
+               return NULL;
        }
        // Ensuring this is zero'd means we make sure the thread doesn't start doing its thing until we are ready.
        memset (this_thread, 0, sizeof(struct CtdlThreadNode));
        
-       if ((ret = pthread_attr_init(&attr))) {
-               lprintf(CTDL_EMERG, "pthread_attr_init: %s\n", strerror(ret));
+       this_thread->state = CTDL_THREAD_CREATE;
+       
+       if ((ret = pthread_attr_init(&this_thread->attr))) {
+               CtdlLogPrintf(CTDL_EMERG, "Thread system, pthread_attr_init: %s\n", strerror(ret));
                free(this_thread);
-               return ret;
+               return NULL;
        }
 
        /* Our per-thread stacks need to be bigger than the default size,
@@ -1157,12 +1470,13 @@ int ctdl_internal_create_thread(char *name, int flags, void *(*thread_func) (voi
         */
        if (flags & CTDLTHREAD_BIGSTACK)
        {
-               if ((ret = pthread_attr_setstacksize(&attr, THREADSTACKSIZE))) {
-                       lprintf(CTDL_EMERG, "pthread_attr_setstacksize: %s\n",
+               CtdlLogPrintf(CTDL_INFO, "Thread system. Creating BIG STACK thread.\n");
+               if ((ret = pthread_attr_setstacksize(&this_thread->attr, THREADSTACKSIZE))) {
+                       CtdlLogPrintf(CTDL_EMERG, "Thread system, pthread_attr_setstacksize: %s\n",
                                strerror(ret));
-                       pthread_attr_destroy(&attr);
+                       pthread_attr_destroy(&this_thread->attr);
                        free(this_thread);
-                       return ret;
+                       return NULL;
                }
        }
 
@@ -1177,34 +1491,64 @@ int ctdl_internal_create_thread(char *name, int flags, void *(*thread_func) (voi
        }
        else
        {
-               this_thread->name = strdup("Unknown Thread");
+               this_thread->name = strdup("Un-named Thread");
        }
+       
        this_thread->flags = flags;
        this_thread->thread_func = thread_func;
-       this_thread->user_args = arg;
-       this_thread->valid = 1; // Need this to prevent house keeping unlinking us from the list
+       this_thread->user_args = args;
+       pthread_mutex_init (&(this_thread->ThreadMutex), NULL);
+       pthread_cond_init (&(this_thread->ThreadCond), NULL);
+       
+       /*
+        * We want to make sure that only the main thread handles signals,
+        * so that each signal is handled exactly once.  To do this, we
+        * make sure that each new thread has all the signals that we
+        * handle blocked.  To avoid race conditions, we block them in 
+        * the spawning thread first, then create the new thread (which
+        * inherits the settings), and then restore the old settings in
+        * the spawning thread.  This means that there is a brief period
+        * when no signals will be processed, but during that time they
+        * should be queued by the operating system.
+        */
+       if (pthread_equal(GC_thread, pthread_self())) 
+           sigtrick = ctdl_thread_internal_block_signals(&old_signal_set) == 0;
+
        /*
         * We pass this_thread into the thread as its args so that it can find out information
         * about itself and it has a bit of storage space for itself, not to mention that the REAL
         * thread function needs to finish off the setup of the structure
         */
-       if ((ret = pthread_create(&this_thread->tid, &attr, ctdl_internal_thread_func, this_thread) != 0))
+       if ((ret = pthread_create(&this_thread->tid, &this_thread->attr, ctdl_internal_thread_func, this_thread) != 0))
        {
 
-               lprintf(CTDL_ALERT, "Can't create thread: %s\n",
+               CtdlLogPrintf(CTDL_ALERT, "Thread system, Can't create thread: %s\n",
                        strerror(ret));
                if (this_thread->name)
                        free (this_thread->name);
+               pthread_mutex_destroy(&(this_thread->ThreadMutex));
+               pthread_cond_destroy(&(this_thread->ThreadCond));
+               pthread_attr_destroy(&this_thread->attr);
                free(this_thread);
-               pthread_attr_destroy(&attr);
-               return ret;
+               if (sigtrick)
+                       ctdl_thread_internal_restore_signals(&old_signal_set);
+               return NULL;
        }
        
+       if (sigtrick)
+               ctdl_thread_internal_restore_signals(&old_signal_set);
+       
+       num_threads++;  // Increase the count of threads in the system.
+       if(this_thread->flags & CTDLTHREAD_WORKER)
+               num_workers++;
+
        this_thread->next = CtdlThreadList;
        CtdlThreadList = this_thread;
-       *new_thread = this_thread;
-       pthread_attr_destroy(&attr);
-       return 0;
+       // Register for tracing
+       #ifdef HAVE_BACKTRACE
+       eCrash_RegisterThread(this_thread->name, 0);
+       #endif
+       return this_thread;
 }
 
 /*
@@ -1213,154 +1557,17 @@ int ctdl_internal_create_thread(char *name, int flags, void *(*thread_func) (voi
  * char *name = name to give to thread, if NULL, use generic name
  * int flags = flags to determine type of thread and standard facilities
  */
-int CtdlCreateThread(char *name, int flags, void *(*thread_func) (void *arg), void *arg,  struct CtdlThreadNode **new_thread)
+struct CtdlThreadNode *CtdlThreadCreate(char *name, long flags, void *(*thread_func) (void *arg), void *args)
 {
-       int ret;
+       struct CtdlThreadNode *ret = NULL;
        
        begin_critical_section(S_THREAD_LIST);
-       ret = ctdl_internal_create_thread(name, flags, thread_func, arg, new_thread);
+       ret = ctdl_internal_create_thread(name, flags, thread_func, args);
        end_critical_section(S_THREAD_LIST);
        return ret;
 }
 
 
-       
-/*
- * Old thread interface.
- */
-
-
-struct worker_node *worker_list = NULL;
-
-
-/*
- * create a worker thread. this function must always be called from within
- * an S_WORKER_LIST critical section!
- */
-void create_worker(void) {
-       int ret;
-       struct worker_node *n;
-       pthread_attr_t attr;
-
-       n = malloc(sizeof(struct worker_node));
-       if (n == NULL) {
-               lprintf(CTDL_EMERG, "can't allocate worker_node, exiting\n");
-               time_to_die = -1;
-               return;
-       }
-
-       if ((ret = pthread_attr_init(&attr))) {
-               lprintf(CTDL_EMERG, "pthread_attr_init: %s\n", strerror(ret));
-               time_to_die = -1;
-               free(n);
-               return;
-       }
-
-       /* Our per-thread stacks need to be bigger than the default size,
-        * otherwise the MIME parser crashes on FreeBSD, and the IMAP service
-        * crashes on 64-bit Linux.
-        */
-       if ((ret = pthread_attr_setstacksize(&attr, THREADSTACKSIZE))) {
-               lprintf(CTDL_EMERG, "pthread_attr_setstacksize: %s\n",
-                       strerror(ret));
-               time_to_die = -1;
-               pthread_attr_destroy(&attr);
-               free(n);
-               return;
-       }
-
-       if ((ret = pthread_create(&n->tid, &attr, worker_thread, NULL) != 0))
-       {
-
-               lprintf(CTDL_ALERT, "Can't create worker thread: %s\n",
-                       strerror(ret));
-               time_to_die = -1;
-               pthread_attr_destroy(&attr);
-               free(n);
-               return;
-       }
-
-       n->next = worker_list;
-       worker_list = n;
-       pthread_attr_destroy(&attr);
-}
-
-void DestroyWorkerList(void)
-{
-       struct CitContext *ptr;         /* general-purpose utility pointer */
-       struct CitContext *rem = NULL;  /* list of sessions to be destroyed */
-
-       begin_critical_section(S_SESSION_TABLE);
-       ptr = ContextList;
-       while (ptr != NULL){
-               /* Remove the session from the active list */
-               rem = ptr->next;
-               --num_sessions;
-               
-               lprintf(CTDL_DEBUG, "Purging session %d\n", rem->cs_pid);
-               end_critical_section(S_SESSION_TABLE);
-               RemoveContext(ptr);
-               begin_critical_section(S_SESSION_TABLE);
-               free (ptr);
-               ptr = rem;
-       }
-       end_critical_section(S_SESSION_TABLE);
-
-       struct worker_node *cur, *p;
-       cur = worker_list;
-       while (cur != NULL)
-       {
-               p = cur->next;
-               free (cur);
-               cur = p;
-       }
-       worker_list = NULL;
-}
-
-/*
- * Create the maintenance threads and begin their operation.
- */
-void create_maintenance_threads(void) {
-       int ret;
-       pthread_attr_t attr;
-
-       if ((ret = pthread_attr_init(&attr))) {
-               lprintf(CTDL_EMERG, "pthread_attr_init: %s\n", strerror(ret));
-               time_to_die = -1;
-               return;
-       }
-
-       /* Our per-thread stacks need to be bigger than the default size,
-        * otherwise the MIME parser crashes on FreeBSD, and the IMAP service
-        * crashes on 64-bit Linux.
-        */
-       if ((ret = pthread_attr_setstacksize(&attr, THREADSTACKSIZE))) {
-               lprintf(CTDL_EMERG, "pthread_attr_setstacksize: %s\n",
-                       strerror(ret));
-               time_to_die = -1;
-               pthread_attr_destroy(&attr);
-               return;
-       }
-       
-       struct MaintenanceThreadHook *fcn;
-
-       lprintf(CTDL_DEBUG, "Performing startup of maintenance thread hooks\n");
-
-       for (fcn = MaintenanceThreadHookTable; fcn != NULL; fcn = fcn->next) {
-               if ((ret = pthread_create(&(fcn->MaintenanceThread_tid), &attr, fcn->fcn_ptr, NULL) != 0)) {
-                       lprintf(CTDL_ALERT, "Can't create thread: %s\n", strerror(ret));
-               }
-               else
-               {
-                       lprintf(CTDL_NOTICE, "Spawned a new maintenance thread \"%s\" (%ld). \n", fcn->name,
-                               fcn->MaintenanceThread_tid);
-               }
-       }
-
-
-       pthread_attr_destroy(&attr);
-}
-
 
 
 /*
@@ -1415,7 +1622,7 @@ void dead_session_purge(int force) {
         * is allocated privately on this thread's stack.
         */
        while (rem != NULL) {
-               lprintf(CTDL_DEBUG, "Purging session %d\n", rem->cs_pid);
+               CtdlLogPrintf(CTDL_DEBUG, "Purging session %d\n", rem->cs_pid);
                RemoveContext(rem);
                ptr = rem;
                rem = rem->next;
@@ -1423,12 +1630,13 @@ void dead_session_purge(int force) {
        }
 
        /* Raise the size of the worker thread pool if necessary. */
-       if ( (num_sessions > num_threads)
-          && (num_threads < config.c_max_workers) ) {
-               begin_critical_section(S_WORKER_LIST);
-               create_worker();
-               end_critical_section(S_WORKER_LIST);
+       begin_critical_section(S_THREAD_LIST);
+       if ( (num_sessions > num_workers)
+          && (num_workers < config.c_max_workers) ) {
+               ctdl_internal_create_thread(NULL, CTDLTHREAD_BIGSTACK + CTDLTHREAD_WORKER, worker_thread, NULL);
        }
+       end_critical_section(S_THREAD_LIST);
+       // FIXME: reduce the number of worker threads too
 }
 
 
@@ -1476,15 +1684,9 @@ void *worker_thread(void *arg) {
        int force_purge = 0;
        int m;
 
-       num_threads++;
-
        cdb_allocate_tsd();
 
-       // Register for tracing
-       #ifdef HAVE_BACKTRACE
-       eCrash_RegisterThread("WorkerThread", 0);
-       #endif
-       while (!time_to_die) {
+       while (!CtdlThreadCheckStop()) {
 
                /* make doubly sure we're not holding any stale db handles
                 * which might cause a deadlock.
@@ -1530,30 +1732,34 @@ do_select:      force_purge = 0;
                        }
                }
 
-               if (!time_to_die) {
+               if (!CtdlThreadCheckStop()) {
                        tv.tv_sec = 1;          /* wake up every second if no input */
                        tv.tv_usec = 0;
                        retval = select(highest + 1, &readfds, NULL, NULL, &tv);
                }
 
-               if (time_to_die) return(NULL);
+               if (CtdlThreadCheckStop()) return(NULL);
 
                /* Now figure out who made this select() unblock.
                 * First, check for an error or exit condition.
                 */
                if (retval < 0) {
                        if (errno == EBADF) {
-                               lprintf(CTDL_NOTICE, "select() failed: (%s)\n",
+                               CtdlLogPrintf(CTDL_NOTICE, "select() failed: (%s)\n",
                                        strerror(errno));
                                goto do_select;
                        }
                        if (errno != EINTR) {
-                               lprintf(CTDL_EMERG, "Exiting (%s)\n", strerror(errno));
-                               time_to_die = 1;
-                       } else if (!time_to_die)
+                               CtdlLogPrintf(CTDL_EMERG, "Exiting (%s)\n", strerror(errno));
+                               CtdlThreadStopAll();
+                       } else if (!CtdlThreadCheckStop()) {
+                               CtdlLogPrintf(CTDL_DEBUG, "Un handled select failure.\n");
                                goto do_select;
+                       }
+               }
+               else if(retval == 0) {
+                       goto SKIP_SELECT;
                }
-
                /* Next, check to see if it's a new client connecting
                 * on a master socket.
                 */
@@ -1563,7 +1769,7 @@ do_select:        force_purge = 0;
                        if (FD_ISSET(serviceptr->msock, &readfds)) {
                                ssock = accept(serviceptr->msock, NULL, 0);
                                if (ssock >= 0) {
-                                       lprintf(CTDL_DEBUG,
+                                       CtdlLogPrintf(CTDL_DEBUG,
                                                "New client socket %d\n",
                                                ssock);
 
@@ -1572,7 +1778,7 @@ do_select:        force_purge = 0;
                                         * operations barf on FreeBSD.  Not a fatal error.
                                         */
                                        if (fcntl(ssock, F_SETFL, 0) < 0) {
-                                               lprintf(CTDL_EMERG,
+                                               CtdlLogPrintf(CTDL_EMERG,
                                                        "citserver: Can't set socket to blocking: %s\n",
                                                        strerror(errno));
                                        }
@@ -1663,9 +1869,8 @@ SKIP_SELECT:
        }
        if (con != NULL) free (con);//// TODO: could this harm other threads? 
        /* If control reaches this point, the server is shutting down */        
-       #ifdef HAVE_BACKTRACE
-       eCrash_UnregisterThread();
-       #endif
+       begin_critical_section(S_THREAD_LIST);
+       end_critical_section(S_THREAD_LIST);
        return(NULL);
 }
 
@@ -1814,7 +2019,7 @@ void dump_heap(void) {
        struct igheap *thisheap;
 
        for (thisheap = igheap; thisheap != NULL; thisheap = thisheap->next) {
-               lprintf(CTDL_CRIT, "UNFREED: %30s : %d\n",
+               CtdlLogPrintf(CTDL_CRIT, "UNFREED: %30s : %d\n",
                        thisheap->file, thisheap->line);
        }
 }
index ab8745c790c5e0ee1073ddc3b0190c287d441bc9..3adcf61f6b3ca1a9db664f3f4b771fd5a2bd057a 100644 (file)
@@ -84,11 +84,10 @@ void InitializeMasterCC(void);
 void init_master_fdset(void);
 void create_worker(void);
 void InitialiseSemaphores(void);
-void ctdl_internal_thread_gc (int shutdown);
 
 
 extern int num_sessions;
-extern volatile int time_to_die;
+extern volatile int exit_signal;
 extern volatile int shutdown_and_halt;
 extern volatile int running_as_daemon;
 extern volatile int restart_server;
@@ -102,16 +101,47 @@ extern struct worker_node {
 } *worker_list;
 
 
+
+/*
+ * Thread stuff
+ */
+#define CTDLTHREAD_BIGSTACK    0x0001
+#define CTDLTHREAD_WORKER      0x0002
+
+void ctdl_internal_thread_gc (void);
+void ctdl_thread_internal_init(void);
+struct CtdlThreadNode *ctdl_internal_create_thread(char *name, long flags, void *(*thread_func) (void *arg), void *args);
+
+enum CtdlThreadState {
+       CTDL_THREAD_INVALID,
+       CTDL_THREAD_VALID,
+       CTDL_THREAD_CREATE,
+       CTDL_THREAD_CANCELLED,
+       CTDL_THREAD_EXITED,
+       CTDL_THREAD_STOPPING,
+       CTDL_THREAD_STOP_REQ,   /* Do NOT put any running states before this state */
+       CTDL_THREAD_SLEEPING,
+       CTDL_THREAD_RUNNING,
+       CTDL_THREAD_LAST_STATE
+};
+
 extern struct CtdlThreadNode {
-       pthread_t tid;
-       char *name;
-       void *(*thread_func) (void *arg);
-       void *user_args;
-       int flags;
-       int running;
-       int valid;
-       struct CtdlThreadNode *prev;
-       struct CtdlThreadNode *next;
+       pthread_t tid;                          /* id as returned by pthread_create() */
+       pid_t pid;                              /* pid, as best the OS will let us determine */
+       struct CitConext *Context;              /* The session context that this thread mught be working on or NULL if none */
+       long number;                            /* A unigue number for this thread (not implimented yet) */
+       int wakefd_recv;                        /* An fd that this thread can sleep on (not implimented yet) */
+       int wakefd_send;                        /* An fd that this thread can send out on (Not implimented yet) */
+       char *name;                             /* A name for this thread */
+       void *(*thread_func) (void *arg);       /* The actual function that does this threads work */
+       void *user_args;                        /* Arguments passed to this threads work function */
+       long flags;                             /* Flags that describe this thread */
+       enum CtdlThreadState state;                             /* Flag to show state of this thread */
+       pthread_mutex_t ThreadMutex;            /* A mutex to sync this thread to others if this thread allows (also used for sleeping) */
+       pthread_cond_t ThreadCond;              /* A condition variable to sync this thread with others (also used for sleeping) */
+       pthread_attr_t attr;                    /* Attributes of this thread */
+       struct CtdlThreadNode *prev;            /* Previous thread in the thread table */
+       struct CtdlThreadNode *next;            /* Next thread in the thread table */
 } *CtdlThreadList;
 
 extern int SyslogFacility(char *name);