]> code.citadel.org Git - citadel.git/blob - citadel/threads.c
Moved all of the background tasks back to the old EVT_TIMER style
[citadel.git] / citadel / threads.c
1 /*
2  * Thread handling stuff for Citadel server
3  *
4  * Copyright (c) 1987-2011 by the citadel.org team
5  *
6  * This program is open source software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <errno.h>
26 #include <sys/socket.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <syslog.h>
31
32 #include "sysdep.h"
33 #if TIME_WITH_SYS_TIME
34 # include <sys/time.h>
35 # include <time.h>
36 #else
37 # if HAVE_SYS_TIME_H
38 #  include <sys/time.h>
39 # else
40 #  include <time.h>
41 # endif
42 #endif
43
44 #ifdef HAVE_SYSCALL_H
45 # include <syscall.h>
46 #else 
47 # if HAVE_SYS_SYSCALL_H
48 #  include <sys/syscall.h>
49 # endif
50 #endif
51
52 #include <libcitadel.h>
53
54 #include "threads.h"
55 #include "ctdl_module.h"
56 #include "modules_init.h"
57 #include "housekeeping.h"
58 #include "config.h"
59 #include "citserver.h"
60 #include "sysdep_decls.h"
61 #include "context.h"
62
63 /*
64  * define this to use the new worker_thread method of handling connections
65  */
66 //#define NEW_WORKER
67
68 /*
69  * New thread interface.
70  * To create a thread you must call one of the create thread functions.
71  * You must pass it the address of (a pointer to a CtdlThreadNode initialised to NULL) like this
72  * struct CtdlThreadNode *node = NULL;
73  * pass in &node
74  * If the thread is created *node will point to the thread control structure for the created thread.
75  * If the thread creation fails *node remains NULL
76  * Do not free the memory pointed to by *node, it doesn't belong to you.
77  * This new interface duplicates much of the eCrash stuff. We should go for closer integration since that would
78  * remove the need for the calls to eCrashRegisterThread and friends
79  */
80
81 static int num_threads = 0;                     /* Current number of threads */
82 static int num_workers = 0;                     /* Current number of worker threads */
83
84 CtdlThreadNode *CtdlThreadList = NULL;
85 CtdlThreadNode *CtdlThreadSchedList = NULL;
86
87 static CtdlThreadNode *GC_thread = NULL;
88 static char *CtdlThreadStates[CTDL_THREAD_LAST_STATE];
89 double CtdlThreadLoadAvg = 0;
90 double CtdlThreadWorkerAvg = 0;
91 citthread_key_t ThreadKey;
92
93 citthread_mutex_t Critters[MAX_SEMAPHORES];     /* Things needing locking */
94
95
96
97 void InitialiseSemaphores(void)
98 {
99         int i;
100
101         /* Set up a bunch of semaphores to be used for critical sections */
102         for (i=0; i<MAX_SEMAPHORES; ++i) {
103                 citthread_mutex_init(&Critters[i], NULL);
104         }
105 }
106
107
108
109
110 /*
111  * Obtain a semaphore lock to begin a critical section.
112  * but only if no one else has one
113  */
114 int try_critical_section(int which_one)
115 {
116         /* For all types of critical sections except those listed here,
117          * ensure nobody ever tries to do a critical section within a
118          * transaction; this could lead to deadlock.
119          */
120         if (    (which_one != S_FLOORCACHE)
121 #ifdef DEBUG_MEMORY_LEAKS
122                 && (which_one != S_DEBUGMEMLEAKS)
123 #endif
124                 && (which_one != S_RPLIST)
125         ) {
126                 cdb_check_handles();
127         }
128         return (citthread_mutex_trylock(&Critters[which_one]));
129 }
130
131
132 /*
133  * Obtain a semaphore lock to begin a critical section.
134  */
135 void begin_critical_section(int which_one)
136 {
137         /* syslog(LOG_DEBUG, "begin_critical_section(%d)\n", which_one); */
138
139         /* For all types of critical sections except those listed here,
140          * ensure nobody ever tries to do a critical section within a
141          * transaction; this could lead to deadlock.
142          */
143         if (    (which_one != S_FLOORCACHE)
144 #ifdef DEBUG_MEMORY_LEAKS
145                 && (which_one != S_DEBUGMEMLEAKS)
146 #endif
147                 && (which_one != S_RPLIST)
148         ) {
149                 cdb_check_handles();
150         }
151         citthread_mutex_lock(&Critters[which_one]);
152 }
153
154 /*
155  * Release a semaphore lock to end a critical section.
156  */
157 void end_critical_section(int which_one)
158 {
159         citthread_mutex_unlock(&Critters[which_one]);
160 }
161
162
163 /*
164  * A function to destroy the TSD
165  */
166 static void ctdl_thread_internal_dest_tsd(void *arg)
167 {
168         if (arg != NULL) {
169                 check_handles(arg);
170                 free(arg);
171         }
172 }
173
174
175 /*
176  * A function to initialise the thread TSD
177  */
178 void ctdl_thread_internal_init_tsd(void)
179 {
180         int ret;
181         
182         if ((ret = citthread_key_create(&ThreadKey, ctdl_thread_internal_dest_tsd))) {
183                 syslog(LOG_EMERG, "citthread_key_create: %s\n", strerror(ret));
184                 exit(CTDLEXIT_DB);
185         }
186 }
187
188 /*
189  * Ensure that we have a key for thread-specific data. 
190  *
191  * This should be called immediately after startup by any thread 
192  * 
193  */
194 void CtdlThreadAllocTSD(void)
195 {
196         ThreadTSD *tsd;
197
198         if (citthread_getspecific(ThreadKey) != NULL)
199                 return;
200
201         tsd = malloc(sizeof(ThreadTSD));
202
203         tsd->tid = NULL;
204
205         memset(tsd->cursors, 0, sizeof tsd->cursors);
206         tsd->self = NULL;
207         
208         citthread_setspecific(ThreadKey, tsd);
209 }
210
211
212 void ctdl_thread_internal_free_tsd(void)
213 {
214         ctdl_thread_internal_dest_tsd(citthread_getspecific(ThreadKey));
215         citthread_setspecific(ThreadKey, NULL);
216 }
217
218
219 void ctdl_thread_internal_cleanup(void)
220 {
221         int i;
222         CtdlThreadNode *this_thread, *that_thread;
223         
224         for (i=0; i<CTDL_THREAD_LAST_STATE; i++)
225         {
226                 free (CtdlThreadStates[i]);
227         }
228         
229         /* Clean up the scheduled thread list */
230         this_thread = CtdlThreadSchedList;
231         while (this_thread)
232         {
233                 that_thread = this_thread;
234                 this_thread = this_thread->next;
235                 citthread_mutex_destroy(&that_thread->ThreadMutex);
236                 citthread_cond_destroy(&that_thread->ThreadCond);
237                 citthread_mutex_destroy(&that_thread->SleepMutex);
238                 citthread_cond_destroy(&that_thread->SleepCond);
239                 citthread_attr_destroy(&that_thread->attr);
240                 free(that_thread);
241         }
242         ctdl_thread_internal_free_tsd();
243 }
244
245 void ctdl_thread_internal_init(void)
246 {
247         CtdlThreadNode *this_thread;
248         int ret = 0;
249         
250         CtdlThreadStates[CTDL_THREAD_INVALID] = strdup ("Invalid Thread");
251         CtdlThreadStates[CTDL_THREAD_VALID] = strdup("Valid Thread");
252         CtdlThreadStates[CTDL_THREAD_CREATE] = strdup("Thread being Created");
253         CtdlThreadStates[CTDL_THREAD_CANCELLED] = strdup("Thread Cancelled");
254         CtdlThreadStates[CTDL_THREAD_EXITED] = strdup("Thread Exited");
255         CtdlThreadStates[CTDL_THREAD_STOPPING] = strdup("Thread Stopping");
256         CtdlThreadStates[CTDL_THREAD_STOP_REQ] = strdup("Thread Stop Requested");
257         CtdlThreadStates[CTDL_THREAD_SLEEPING] = strdup("Thread Sleeping");
258         CtdlThreadStates[CTDL_THREAD_RUNNING] = strdup("Thread Running");
259         CtdlThreadStates[CTDL_THREAD_BLOCKED] = strdup("Thread Blocked");
260         
261         /* Get ourself a thread entry */
262         this_thread = malloc(sizeof(CtdlThreadNode));
263         if (this_thread == NULL) {
264                 syslog(LOG_EMERG, "Thread system, can't allocate CtdlThreadNode, exiting\n");
265                 return;
266         }
267         // Ensuring this is zero'd means we make sure the thread doesn't start doing its thing until we are ready.
268         memset (this_thread, 0, sizeof(CtdlThreadNode));
269         
270         citthread_mutex_init (&(this_thread->ThreadMutex), NULL);
271         citthread_cond_init (&(this_thread->ThreadCond), NULL);
272         citthread_mutex_init (&(this_thread->SleepMutex), NULL);
273         citthread_cond_init (&(this_thread->SleepCond), NULL);
274         
275         /* We are garbage collector so create us as running */
276         this_thread->state = CTDL_THREAD_RUNNING;
277         
278         if ((ret = citthread_attr_init(&this_thread->attr))) {
279                 syslog(LOG_EMERG, "Thread system, citthread_attr_init: %s\n", strerror(ret));
280                 free(this_thread);
281                 return;
282         }
283
284         this_thread->name = "Garbage Collection Thread";
285         
286         this_thread->tid = citthread_self();
287         GC_thread = this_thread;
288         CT = this_thread;
289         
290         num_threads++;  // Increase the count of threads in the system.
291
292         this_thread->next = CtdlThreadList;
293         CtdlThreadList = this_thread;
294         if (this_thread->next)
295                 this_thread->next->prev = this_thread;
296         /* Set up start times */
297         gettimeofday(&this_thread->start_time, NULL);           /* Time this thread started */
298         memcpy(&this_thread->last_state_change, &this_thread->start_time, sizeof (struct timeval));     /* Changed state so mark it. */
299 }
300
301
302 /*
303  * A function to update a threads load averages
304  */
305  void ctdl_thread_internal_update_avgs(CtdlThreadNode *this_thread)
306  {
307         struct timeval now, result;
308         double last_duration;
309
310         gettimeofday(&now, NULL);
311         timersub(&now, &(this_thread->last_state_change), &result);
312         /* I don't think these mutex's are needed here */
313         citthread_mutex_lock(&this_thread->ThreadMutex);
314         // result now has a timeval for the time we spent in the last state since we last updated
315         last_duration = (double)result.tv_sec + ((double)result.tv_usec / (double) 1000000);
316         if (this_thread->state == CTDL_THREAD_SLEEPING)
317                 this_thread->avg_sleeping += last_duration;
318         if (this_thread->state == CTDL_THREAD_RUNNING)
319                 this_thread->avg_running += last_duration;
320         if (this_thread->state == CTDL_THREAD_BLOCKED)
321                 this_thread->avg_blocked += last_duration;
322         memcpy (&this_thread->last_state_change, &now, sizeof (struct timeval));
323         citthread_mutex_unlock(&this_thread->ThreadMutex);
324 }
325
326 /*
327  * A function to chenge the state of a thread
328  */
329 void ctdl_thread_internal_change_state (CtdlThreadNode *this_thread, enum CtdlThreadState new_state)
330 {
331         /*
332          * Wether we change state or not we need update the load values
333          */
334         ctdl_thread_internal_update_avgs(this_thread);
335         /* This mutex not needed here? */
336         citthread_mutex_lock(&this_thread->ThreadMutex); /* To prevent race condition of a sleeping thread */
337         if ((new_state == CTDL_THREAD_STOP_REQ) && (this_thread->state > CTDL_THREAD_STOP_REQ))
338                 this_thread->state = new_state;
339         if (((new_state == CTDL_THREAD_SLEEPING) || (new_state == CTDL_THREAD_BLOCKED)) && (this_thread->state == CTDL_THREAD_RUNNING))
340                 this_thread->state = new_state;
341         if ((new_state == CTDL_THREAD_RUNNING) && ((this_thread->state == CTDL_THREAD_SLEEPING) || (this_thread->state == CTDL_THREAD_BLOCKED)))
342                 this_thread->state = new_state;
343         citthread_mutex_unlock(&this_thread->ThreadMutex);
344 }
345
346
347 /*
348  * A function to tell all threads to exit
349  */
350 void CtdlThreadStopAll(void)
351 {
352         /* First run any registered shutdown hooks.  This probably doesn't belong here. */
353         PerformSessionHooks(EVT_SHUTDOWN);
354         
355         /* then close all tcp ports so nobody else can talk to us anymore. */
356         CtdlShutdownServiceHooks();
357         //FIXME: The signalling of the condition should not be in the critical_section
358         // We need to build a list of threads we are going to signal and then signal them afterwards
359         
360         CtdlThreadNode *this_thread;
361         
362         begin_critical_section(S_THREAD_LIST);
363         this_thread = CtdlThreadList;
364         // Ask the GC thread to stop first so everything knows we are shutting down.
365         GC_thread->state = CTDL_THREAD_STOP_REQ;
366         while(this_thread)
367         {
368                 if (!citthread_equal(this_thread->tid, GC_thread->tid))
369                         citthread_kill(this_thread->tid, SIGHUP);
370
371                 ctdl_thread_internal_change_state (this_thread, CTDL_THREAD_STOP_REQ);
372                 citthread_cond_signal(&this_thread->ThreadCond);
373                 citthread_cond_signal(&this_thread->SleepCond);
374                 this_thread->stop_ticker = time(NULL);
375                 syslog(LOG_DEBUG, "Thread system stopping thread \"%s\" (0x%08lx).\n",
376                         this_thread->name, this_thread->tid);
377                 this_thread = this_thread->next;
378         }
379         end_critical_section(S_THREAD_LIST);
380 }
381
382
383 /*
384  * A function to wake up all sleeping threads
385  */
386 void CtdlThreadWakeAll(void)
387 {
388         CtdlThreadNode *this_thread;
389         
390         syslog(LOG_DEBUG, "Thread system waking all threads.\n");
391         
392         begin_critical_section(S_THREAD_LIST);
393         this_thread = CtdlThreadList;
394         while(this_thread)
395         {
396                 if (!this_thread->thread_func)
397                 {
398                         citthread_cond_signal(&this_thread->ThreadCond);
399                         citthread_cond_signal(&this_thread->SleepCond);
400                 }
401                 this_thread = this_thread->next;
402         }
403         end_critical_section(S_THREAD_LIST);
404 }
405
406
407 /*
408  * A function to return the number of threads running in the system
409  */
410 int CtdlThreadGetCount(void)
411 {
412         return  num_threads;
413 }
414
415 int CtdlThreadGetWorkers(void)
416 {
417         return  num_workers;
418 }
419
420 double CtdlThreadGetWorkerAvg(void)
421 {
422         double ret;
423         
424         begin_critical_section(S_THREAD_LIST);
425         ret =  CtdlThreadWorkerAvg;
426         end_critical_section(S_THREAD_LIST);
427         return ret;
428 }
429
430 double CtdlThreadGetLoadAvg(void)
431 {
432         double load_avg[3] = {0.0, 0.0, 0.0};
433
434         int ret = 0;
435         int smp_num_cpus;
436
437         /* Borrowed this straight from procps */
438         smp_num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
439         if(smp_num_cpus<1) smp_num_cpus=1; /* SPARC glibc is buggy */
440
441 #ifdef HAVE_GETLOADAVG
442         ret = getloadavg(load_avg, 3);
443 #endif
444         if (ret < 0)
445                 return 0;
446         return load_avg[0] / smp_num_cpus;
447 /*
448  * This old chunk of code return a value that indicated the load on citserver
449  * This value could easily reach 100 % even when citserver was doing very little and
450  * hence the machine has much more spare capacity.
451  * Because this value was used to determine if the machine was under heavy load conditions
452  * from other processes in the system then citserver could be strangled un-necesarily
453  * What we are actually trying to achieve is to strangle citserver if the machine is heavily loaded.
454  * So we have changed this.
455
456         begin_critical_section(S_THREAD_LIST);
457         ret =  CtdlThreadLoadAvg;
458         end_critical_section(S_THREAD_LIST);
459         return ret;
460 */
461 }
462
463
464
465
466 /*
467  * A function to rename a thread
468  * Returns a const char *
469  */
470 const char *CtdlThreadName(const char *name)
471 {
472         const char *old_name;
473         
474         if (!CT)
475         {
476                 syslog(LOG_WARNING, "Thread system WARNING. Attempt to CtdlThreadRename() a non thread. %s\n", name);
477                 return NULL;
478         }
479         old_name = CT->name;
480         if (name)
481                 CT->name = name;
482         return (old_name);
483 }       
484
485
486 /*
487  * A function to force a thread to exit
488  */
489 void CtdlThreadCancel(CtdlThreadNode *thread)
490 {
491         CtdlThreadNode *this_thread;
492         
493         if (!thread)
494                 this_thread = CT;
495         else
496                 this_thread = thread;
497         if (!this_thread)
498         {
499                 syslog(LOG_EMERG, "Thread system PANIC. Attempt to CtdlThreadCancel() a non thread.\n");
500                 CtdlThreadStopAll();
501                 return;
502         }
503         
504         if (!this_thread->thread_func)
505         {
506                 syslog(LOG_EMERG, "Thread system PANIC. Attempt to CtdlThreadCancel() the garbage collector.\n");
507                 CtdlThreadStopAll();
508                 return;
509         }
510         
511         ctdl_thread_internal_change_state (this_thread, CTDL_THREAD_CANCELLED);
512         citthread_cancel(this_thread->tid);
513 }
514
515
516 /*
517  * A function for a thread to check if it has been asked to stop
518  */
519 int CtdlThreadCheckStop(void)
520 {
521         int state;
522         
523         if (!CT)
524         {
525                 syslog(LOG_EMERG, "Thread system PANIC, CtdlThreadCheckStop() called by a non thread.\n");
526                 CtdlThreadStopAll();
527                 return -1;
528         }
529         
530         state = CT->state;
531
532         if (CT->signal)
533         {
534                 syslog(LOG_DEBUG, "Thread \"%s\" caught signal %d.\n", CT->name, CT->signal);
535                 if (CT->signal == SIGHUP)
536                         CT->state = CTDL_THREAD_STOP_REQ;
537                 CT->signal = 0;
538         }
539         if(state == CTDL_THREAD_STOP_REQ)
540         {
541                 CT->state = CTDL_THREAD_STOPPING;
542                 return -1;
543         }
544         else if((state < CTDL_THREAD_STOP_REQ) && (state > CTDL_THREAD_CREATE))
545         {
546                 return -1;
547         }
548         return 0;
549 }
550
551
552 /*
553  * A function to ask a thread to exit
554  * The thread must call CtdlThreadCheckStop() periodically to determine if it should exit
555  */
556 void CtdlThreadStop(CtdlThreadNode *thread)
557 {
558         CtdlThreadNode *this_thread;
559         
560         if (!thread)
561                 this_thread = CT;
562         else
563                 this_thread = thread;
564         if (!this_thread)
565                 return;
566         if (!(this_thread->thread_func))
567                 return;         // Don't stop garbage collector
568
569         if (!citthread_equal(this_thread->tid, GC_thread->tid))
570                 citthread_kill(this_thread->tid, SIGHUP);
571
572         ctdl_thread_internal_change_state (this_thread, CTDL_THREAD_STOP_REQ);
573         citthread_cond_signal(&this_thread->ThreadCond);
574         citthread_cond_signal(&this_thread->SleepCond);
575         this_thread->stop_ticker = time(NULL);
576 }
577
578 /*
579  * So we now have a sleep command that works with threads but it is in seconds
580  */
581 void CtdlThreadSleep(int secs)
582 {
583         struct timespec wake_time;
584         struct timeval time_now;
585         
586         
587         if (!CT)
588         {
589                 syslog(LOG_WARNING, "CtdlThreadSleep() called by something that is not a thread. Should we die?\n");
590                 return;
591         }
592         
593         memset (&wake_time, 0, sizeof(struct timespec));
594         gettimeofday(&time_now, NULL);
595         wake_time.tv_sec = time_now.tv_sec + secs;
596         wake_time.tv_nsec = time_now.tv_usec * 10;
597
598         ctdl_thread_internal_change_state (CT, CTDL_THREAD_SLEEPING);
599         
600         citthread_mutex_lock(&CT->ThreadMutex); /* Prevent something asking us to awaken before we've gone to sleep */
601         citthread_cond_timedwait(&CT->SleepCond, &CT->ThreadMutex, &wake_time);
602         citthread_mutex_unlock(&CT->ThreadMutex);
603         
604         ctdl_thread_internal_change_state (CT, CTDL_THREAD_RUNNING);
605 }
606
607
608 /*
609  * Routine to clean up our thread function on exit
610  */
611 static void ctdl_internal_thread_cleanup(void *arg)
612 {
613         /*
614          * In here we were called by the current thread because it is exiting
615          * NB. WE ARE THE CURRENT THREAD
616          */
617         if (CT)
618         {
619                 const char *name = CT->name;
620                 const pid_t tid = CT->tid;
621
622                 syslog(LOG_NOTICE, "Thread \"%s\" (0x%08lx) exited.\n", name, (unsigned long) tid);
623         }
624         else 
625         {
626                 syslog(LOG_NOTICE, "some ((unknown ? ? ?) Thread exited.\n");
627         }
628         
629         #ifdef HAVE_BACKTRACE
630 ///     eCrash_UnregisterThread();
631         #endif
632         
633         citthread_mutex_lock(&CT->ThreadMutex);
634         CT->state = CTDL_THREAD_EXITED; // needs to be last thing else house keeping will unlink us too early
635         citthread_mutex_unlock(&CT->ThreadMutex);
636 }
637
638 /*
639  * A quick function to show the load averages
640  */
641 void ctdl_thread_internal_calc_loadavg(void)
642 {
643         CtdlThreadNode *that_thread;
644         double load_avg, worker_avg;
645         int workers = 0;
646
647         that_thread = CtdlThreadList;
648         load_avg = 0;
649         worker_avg = 0;
650         while(that_thread)
651         {
652                 /* Update load averages */
653                 ctdl_thread_internal_update_avgs(that_thread);
654                 citthread_mutex_lock(&that_thread->ThreadMutex);
655                 that_thread->load_avg = (that_thread->avg_sleeping + that_thread->avg_running) / (that_thread->avg_sleeping + that_thread->avg_running + that_thread->avg_blocked) * 100;
656                 that_thread->avg_sleeping /= 2;
657                 that_thread->avg_running /= 2;
658                 that_thread->avg_blocked /= 2;
659                 load_avg += that_thread->load_avg;
660                 if (that_thread->flags & CTDLTHREAD_WORKER)
661                 {
662                         worker_avg += that_thread->load_avg;
663                         workers++;
664                 }
665 #ifdef WITH_THREADLOG
666                 syslog(LOG_DEBUG, "CtdlThread, \"%s\" (%lu) \"%s\" %.2f %.2f %.2f %.2f\n",
667                         that_thread->name,
668                         that_thread->tid,
669                         CtdlThreadStates[that_thread->state],
670                         that_thread->avg_sleeping,
671                         that_thread->avg_running,
672                         that_thread->avg_blocked,
673                         that_thread->load_avg);
674 #endif
675                 citthread_mutex_unlock(&that_thread->ThreadMutex);
676                 that_thread = that_thread->next;
677         }
678         CtdlThreadLoadAvg = load_avg/num_threads;
679         CtdlThreadWorkerAvg = worker_avg/workers;
680 #ifdef WITH_THREADLOG
681         syslog(LOG_INFO, "System load average %.2f, workers averag %.2f, threads %d, workers %d, sessions %d\n", CtdlThreadGetLoadAvg(), CtdlThreadWorkerAvg, num_threads, num_workers, num_sessions);
682 #endif
683 }
684
685
686 /*
687  * Garbage collection routine.
688  * Gets called by main() in a loop to clean up the thread list periodically.
689  */
690 void CtdlThreadGC (void)
691 {
692
693
694         return;
695         /* FIXME this is a big deal, but I think it's causing corruption */
696
697
698         CtdlThreadNode *this_thread, *that_thread;
699         int workers = 0, sys_workers;
700         int ret=0;
701
702         begin_critical_section(S_THREAD_LIST);
703         
704         /* Handle exiting of garbage collector thread */
705         if(num_threads == 1)
706                 CtdlThreadList->state = CTDL_THREAD_EXITED;
707         
708 #ifdef WITH_THREADLOG
709         syslog(LOG_DEBUG, "Thread system running garbage collection.\n");
710 #endif
711         /*
712          * Woke up to do garbage collection
713          */
714         this_thread = CtdlThreadList;
715         while(this_thread)
716         {
717                 that_thread = this_thread;
718                 this_thread = this_thread->next;
719                 
720                 if ((that_thread->state == CTDL_THREAD_STOP_REQ || that_thread->state == CTDL_THREAD_STOPPING)
721                         && (!citthread_equal(that_thread->tid, citthread_self())))
722                 {
723                         syslog(LOG_DEBUG, "Waiting for thread %s (0x%08lx) to exit.\n", that_thread->name, that_thread->tid);
724                         terminate_stuck_sessions();
725                 }
726                 else
727                 {
728                         /**
729                          * Catch the situation where a worker was asked to stop but couldn't and we are not
730                          * shutting down.
731                          */
732                         that_thread->stop_ticker = 0;
733                 }
734                 
735                 if (that_thread->stop_ticker + 5 == time(NULL))
736                 {
737                         syslog(LOG_DEBUG, "Thread System: The thread \"%s\" (0x%08lx) failed to self terminate within 5 ticks. It would be cancelled now.\n", that_thread->name, that_thread->tid);
738                         if ((that_thread->flags & CTDLTHREAD_WORKER) == 0)
739                                 syslog(LOG_INFO, "Thread System: A non worker thread would have been canceled this may cause message loss.\n");
740 //                      that_thread->state = CTDL_THREAD_CANCELLED;
741                         that_thread->stop_ticker++;
742 //                      citthread_cancel(that_thread->tid);
743 //                      continue;
744                 }
745                 
746                 /* Do we need to clean up this thread? */
747                 if ((that_thread->state != CTDL_THREAD_EXITED) && (that_thread->state != CTDL_THREAD_CANCELLED))
748                 {
749                         if(that_thread->flags & CTDLTHREAD_WORKER)
750                                 workers++;      /* Sanity check on number of worker threads */
751                         continue;
752                 }
753                 
754                 if (citthread_equal(that_thread->tid, citthread_self()) && that_thread->thread_func)
755                 {       /* Sanity check */
756                         end_critical_section(S_THREAD_LIST);
757                         syslog(LOG_EMERG, "Thread system PANIC, a thread is trying to clean up after itself.\n");
758                         abort();
759                         return;
760                 }
761                 
762                 if (num_threads <= 0)
763                 {       /* Sanity check */
764                         end_critical_section(S_THREAD_LIST);
765                         syslog(LOG_EMERG, "Thread system PANIC, num_threads <= 0 and trying to do Garbage Collection.\n");
766                         abort();
767                         return;
768                 }
769
770                 if(that_thread->flags & CTDLTHREAD_WORKER)
771                         num_workers--;  /* This is a wroker thread so reduce the count. */
772                 num_threads--;
773                 /* If we are unlinking the list head then the next becomes the list head */
774                 if(that_thread->prev)
775                         that_thread->prev->next = that_thread->next;
776                 else
777                         CtdlThreadList = that_thread->next;
778                 if(that_thread->next)
779                         that_thread->next->prev = that_thread->prev;
780                 
781                 citthread_cond_signal(&that_thread->ThreadCond);
782                 citthread_cond_signal(&that_thread->SleepCond); // Make sure this thread is awake
783                 citthread_mutex_lock(&that_thread->ThreadMutex);        // Make sure it has done what its doing
784                 citthread_mutex_unlock(&that_thread->ThreadMutex);
785                 /*
786                  * Join on the thread to do clean up and prevent memory leaks
787                  * Also makes sure the thread has cleaned up after itself before we remove it from the list
788                  * We can join on the garbage collector thread the join should just return EDEADLCK
789                  */
790                 ret = citthread_join (that_thread->tid, NULL);
791                 if (ret == EDEADLK)
792                         syslog(LOG_DEBUG, "Garbage collection on own thread.\n");
793                 else if (ret == EINVAL)
794                         syslog(LOG_DEBUG, "Garbage collection, that thread already joined on.\n");
795                 else if (ret == ESRCH)
796                         syslog(LOG_DEBUG, "Garbage collection, no thread to join on.\n");
797                 else if (ret != 0)
798                         syslog(LOG_DEBUG, "Garbage collection, citthread_join returned an unknown error(%d).\n", ret);
799                 /*
800                  * Now we own that thread entry
801                  */
802                 syslog(LOG_INFO, "Garbage Collection for thread \"%s\" (0x%08lx).\n",
803                         that_thread->name, that_thread->tid);
804                 citthread_mutex_destroy(&that_thread->ThreadMutex);
805                 citthread_cond_destroy(&that_thread->ThreadCond);
806                 citthread_mutex_destroy(&that_thread->SleepMutex);
807                 citthread_cond_destroy(&that_thread->SleepCond);
808                 citthread_attr_destroy(&that_thread->attr);
809                 free(that_thread);
810         }
811         sys_workers = num_workers;
812         end_critical_section(S_THREAD_LIST);
813         
814         /* Sanity check number of worker threads */
815         if (workers != sys_workers)
816         {
817                 syslog(LOG_EMERG,
818                         "Thread system PANIC, discrepancy in number of worker threads. Counted %d, should be %d.\n",
819                         workers, sys_workers
820                         );
821                 abort();
822         }
823 }
824
825
826
827  
828 /*
829  * Runtime function for a Citadel Thread.
830  * This initialises the threads environment and then calls the user supplied thread function
831  * Note that this is the REAL thread function and wraps the users thread function.
832  */ 
833 static void *ctdl_internal_thread_func (void *arg)
834 {
835         CtdlThreadNode *this_thread;
836         void *ret = NULL;
837
838         /* lock and unlock the thread list.
839          * This causes this thread to wait until all its creation stuff has finished before it
840          * can continue its execution.
841          */
842         begin_critical_section(S_THREAD_LIST);
843         this_thread = (CtdlThreadNode *) arg;
844         gettimeofday(&this_thread->start_time, NULL);           /* Time this thread started */
845         
846         // Register the cleanup function to take care of when we exit.
847         citthread_cleanup_push(ctdl_internal_thread_cleanup, NULL);
848         // Get our thread data structure
849         CtdlThreadAllocTSD();
850         CT = this_thread;
851         this_thread->pid = getpid();
852         memcpy(&this_thread->last_state_change, &this_thread->start_time, sizeof (struct timeval));     /* Changed state so mark it. */
853         /* Only change to running state if we weren't asked to stop during the create cycle
854          * Other wise there is a window to allow this threads creation to continue to full grown and
855          * therby prevent a shutdown of the server.
856          */
857         if (!CtdlThreadCheckStop())
858         {
859                 citthread_mutex_lock(&this_thread->ThreadMutex);
860                 this_thread->state = CTDL_THREAD_RUNNING;
861                 citthread_mutex_unlock(&this_thread->ThreadMutex);
862         }
863         end_critical_section(S_THREAD_LIST);
864         
865         // Register for tracing
866         #ifdef HAVE_BACKTRACE
867 ///     eCrash_RegisterThread(this_thread->name, 0);
868         #endif
869         
870         // Tell the world we are here
871 #if defined(HAVE_SYSCALL_H) && defined (SYS_gettid)
872         this_thread->reltid = syscall(SYS_gettid);
873 #endif
874         syslog(LOG_NOTICE, "Created a new thread \"%s\" (0x%08lx).\n",
875                 this_thread->name, this_thread->tid);
876         
877         /*
878          * run the thread to do the work but only if we haven't been asked to stop
879          */
880         if (!CtdlThreadCheckStop())
881                 ret = (this_thread->thread_func)(this_thread->user_args);
882         
883         /*
884          * Our thread is exiting either because it wanted to end or because the server is stopping
885          * We need to clean up
886          */
887         citthread_cleanup_pop(1);       // Execute our cleanup routine and remove it
888         
889         return(ret);
890 }
891
892
893
894
895 /*
896  * Function to initialise an empty thread structure
897  */
898 CtdlThreadNode *ctdl_internal_init_thread_struct(CtdlThreadNode *this_thread, long flags)
899 {
900         int ret = 0;
901         
902         // Ensuring this is zero'd means we make sure the thread doesn't start doing its thing until we are ready.
903         memset (this_thread, 0, sizeof(CtdlThreadNode));
904         
905         /* Create the mutex's early so we can use them */
906         citthread_mutex_init (&(this_thread->ThreadMutex), NULL);
907         citthread_cond_init (&(this_thread->ThreadCond), NULL);
908         citthread_mutex_init (&(this_thread->SleepMutex), NULL);
909         citthread_cond_init (&(this_thread->SleepCond), NULL);
910         
911         this_thread->state = CTDL_THREAD_CREATE;
912         
913         if ((ret = citthread_attr_init(&this_thread->attr))) {
914                 citthread_mutex_unlock(&this_thread->ThreadMutex);
915                 citthread_mutex_destroy(&(this_thread->ThreadMutex));
916                 citthread_cond_destroy(&(this_thread->ThreadCond));
917                 citthread_mutex_destroy(&(this_thread->SleepMutex));
918                 citthread_cond_destroy(&(this_thread->SleepCond));
919                 syslog(LOG_EMERG, "Thread system, citthread_attr_init: %s\n", strerror(ret));
920                 free(this_thread);
921                 return NULL;
922         }
923
924         /* Our per-thread stacks need to be bigger than the default size,
925          * otherwise the MIME parser crashes on FreeBSD, and the IMAP service
926          * crashes on 64-bit Linux.
927          */
928         if (flags & CTDLTHREAD_BIGSTACK)
929         {
930 #ifdef WITH_THREADLOG
931                 syslog(LOG_INFO, "Thread system. Creating BIG STACK thread.\n");
932 #endif
933                 if ((ret = citthread_attr_setstacksize(&this_thread->attr, THREADSTACKSIZE))) {
934                         citthread_mutex_unlock(&this_thread->ThreadMutex);
935                         citthread_mutex_destroy(&(this_thread->ThreadMutex));
936                         citthread_cond_destroy(&(this_thread->ThreadCond));
937                         citthread_mutex_destroy(&(this_thread->SleepMutex));
938                         citthread_cond_destroy(&(this_thread->SleepCond));
939                         citthread_attr_destroy(&this_thread->attr);
940                         syslog(LOG_EMERG, "Thread system, citthread_attr_setstacksize: %s\n",
941                                 strerror(ret));
942                         free(this_thread);
943                         return NULL;
944                 }
945         }
946
947         /* Set this new thread with an avg_blocked of 2. We do this so that its creation affects the
948          * load average for the system. If we don't do this then we create a mass of threads at the same time 
949          * because the creation didn't affect the load average.
950          */
951         this_thread->avg_blocked = 2;
952         
953         return (this_thread);
954 }
955
956
957
958  
959 /*
960  * Internal function to create a thread.
961  */ 
962 CtdlThreadNode *ctdl_internal_create_thread(char *name, long flags, void *(*thread_func) (void *arg), void *args)
963 {
964         int ret = 0;
965         CtdlThreadNode *this_thread;
966
967         if (num_threads >= 32767)
968         {
969                 syslog(LOG_EMERG, "Thread system. Thread list full.\n");
970                 return NULL;
971         }
972                 
973         this_thread = malloc(sizeof(CtdlThreadNode));
974         if (this_thread == NULL) {
975                 syslog(LOG_EMERG, "Thread system, can't allocate CtdlThreadNode, exiting\n");
976                 return NULL;
977         }
978         
979         /* Initialise the thread structure */
980         if (ctdl_internal_init_thread_struct(this_thread, flags) == NULL)
981         {
982                 free(this_thread);
983                 syslog(LOG_EMERG, "Thread system, can't initialise CtdlThreadNode, exiting\n");
984                 return NULL;
985         }
986         /*
987          * If we got here we are going to create the thread so we must initilise the structure
988          * first because most implimentations of threading can't create it in a stopped state
989          * and it might want to do things with its structure that aren't initialised otherwise.
990          */
991         if(name)
992         {
993                 this_thread->name = name;
994         }
995         else
996         {
997                 this_thread->name = "Un-named Thread";
998         }
999         
1000         this_thread->flags = flags;
1001         this_thread->thread_func = thread_func;
1002         this_thread->user_args = args;
1003         
1004         begin_critical_section(S_THREAD_LIST);
1005         /*
1006          * We pass this_thread into the thread as its args so that it can find out information
1007          * about itself and it has a bit of storage space for itself, not to mention that the REAL
1008          * thread function needs to finish off the setup of the structure
1009          */
1010         if ((ret = citthread_create(&this_thread->tid, &this_thread->attr, ctdl_internal_thread_func, this_thread) != 0))
1011         {
1012                 end_critical_section(S_THREAD_LIST);
1013                 syslog(LOG_ALERT, "Thread system, Can't create thread: %s\n",
1014                         strerror(ret));
1015                 citthread_mutex_unlock(&this_thread->ThreadMutex);
1016                 citthread_mutex_destroy(&(this_thread->ThreadMutex));
1017                 citthread_cond_destroy(&(this_thread->ThreadCond));
1018                 citthread_mutex_destroy(&(this_thread->SleepMutex));
1019                 citthread_cond_destroy(&(this_thread->SleepCond));
1020                 citthread_attr_destroy(&this_thread->attr);
1021                 free(this_thread);
1022                 return NULL;
1023         }
1024         num_threads++;  // Increase the count of threads in the system.
1025         if(this_thread->flags & CTDLTHREAD_WORKER)
1026                 num_workers++;
1027
1028         this_thread->next = CtdlThreadList;
1029         CtdlThreadList = this_thread;
1030         if (this_thread->next)
1031                 this_thread->next->prev = this_thread;
1032         ctdl_thread_internal_calc_loadavg();
1033         
1034         end_critical_section(S_THREAD_LIST);
1035         
1036         return this_thread;
1037 }
1038
1039 /*
1040  * Wrapper function to create a thread
1041  * ensures the critical section and other protections are in place.
1042  * char *name = name to give to thread, if NULL, use generic name
1043  * int flags = flags to determine type of thread and standard facilities
1044  */
1045 CtdlThreadNode *CtdlThreadCreate(char *name, long flags, void *(*thread_func) (void *arg), void *args)
1046 {
1047         CtdlThreadNode *ret = NULL;
1048         
1049         ret = ctdl_internal_create_thread(name, flags, thread_func, args);
1050         return ret;
1051 }
1052
1053
1054
1055 CtdlThreadNode *ctdl_thread_internal_start_scheduled (CtdlThreadNode *this_thread)
1056 {
1057         int ret = 0;
1058         
1059         begin_critical_section(S_THREAD_LIST);
1060         /*
1061          * We pass this_thread into the thread as its args so that it can find out information
1062          * about itself and it has a bit of storage space for itself, not to mention that the REAL
1063          * thread function needs to finish off the setup of the structure
1064          */
1065         if ((ret = citthread_create(&this_thread->tid, &this_thread->attr, ctdl_internal_thread_func, this_thread) != 0))
1066         {
1067                 end_critical_section(S_THREAD_LIST);
1068                 syslog(LOG_DEBUG, "Failed to start scheduled thread \"%s\": %s\n", this_thread->name, strerror(ret));
1069                 citthread_mutex_destroy(&(this_thread->ThreadMutex));
1070                 citthread_cond_destroy(&(this_thread->ThreadCond));
1071                 citthread_mutex_destroy(&(this_thread->SleepMutex));
1072                 citthread_cond_destroy(&(this_thread->SleepCond));
1073                 citthread_attr_destroy(&this_thread->attr);
1074                 free(this_thread);
1075                 return NULL;
1076         }
1077         
1078         
1079         num_threads++;  // Increase the count of threads in the system.
1080         if(this_thread->flags & CTDLTHREAD_WORKER)
1081                 num_workers++;
1082
1083         this_thread->next = CtdlThreadList;
1084         CtdlThreadList = this_thread;
1085         if (this_thread->next)
1086                 this_thread->next->prev = this_thread;
1087         
1088         ctdl_thread_internal_calc_loadavg();
1089         end_critical_section(S_THREAD_LIST);
1090         
1091         
1092         return this_thread;
1093 }
1094
1095
1096
1097 void ctdl_thread_internal_check_scheduled(void)
1098 {
1099         CtdlThreadNode *this_thread, *that_thread;
1100         time_t now;
1101         
1102         /* Don't start scheduled threads if the system wants single user mode */
1103         if (CtdlWantSingleUser())
1104                 return;
1105         
1106         if (try_critical_section(S_SCHEDULE_LIST))
1107                 return; /* If this list is locked we wait till the next chance */
1108         
1109         now = time(NULL);
1110         
1111 #ifdef WITH_THREADLOG
1112         syslog(LOG_DEBUG, "Checking for scheduled threads to start.\n");
1113 #endif
1114
1115         this_thread = CtdlThreadSchedList;
1116         while(this_thread)
1117         {
1118                 that_thread = this_thread;
1119                 this_thread = this_thread->next;
1120                 
1121                 if (now > that_thread->when)
1122                 {
1123                         /* Unlink from schedule list */
1124                         if (that_thread->prev)
1125                                 that_thread->prev->next = that_thread->next;
1126                         else
1127                                 CtdlThreadSchedList = that_thread->next;
1128                         if (that_thread->next)
1129                                 that_thread->next->prev = that_thread->prev;
1130                                 
1131                         that_thread->next = that_thread->prev = NULL;
1132 #ifdef WITH_THREADLOG
1133                         syslog(LOG_DEBUG, "About to start scheduled thread \"%s\".\n", that_thread->name);
1134 #endif
1135                         if (CT->state > CTDL_THREAD_STOP_REQ)
1136                         {       /* Only start it if the system is not stopping */
1137                                 if (ctdl_thread_internal_start_scheduled (that_thread))
1138                                 {
1139 #ifdef WITH_THREADLOG
1140                                         syslog(LOG_INFO, "Thread system, Started a scheduled thread \"%s\" (0x%08lx).\n",
1141                                                 that_thread->name, that_thread->tid);
1142 #endif
1143                                 }
1144                         }
1145                 }
1146 #ifdef WITH_THREADLOG
1147                 else
1148                 {
1149                         syslog(LOG_DEBUG, "Thread \"%s\" will start in %ld seconds.\n",
1150                                 that_thread->name, that_thread->when - time(NULL));
1151                 }
1152 #endif
1153         }
1154         end_critical_section(S_SCHEDULE_LIST);
1155 }
1156
1157
1158 /*
1159  * A warapper function for select so we can show a thread as blocked
1160  */
1161 int CtdlThreadSelect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
1162 {
1163         int ret = 0;
1164         
1165         ctdl_thread_internal_change_state(CT, CTDL_THREAD_BLOCKED);
1166         if (!CtdlThreadCheckStop())
1167                 ret = select(n, readfds, writefds, exceptfds, timeout);
1168         /**
1169          * If the select returned <= 0 then it failed due to an error
1170          * or timeout so this thread could stop if asked to do so.
1171          * Anything else means it needs to continue unless the system is shutting down
1172          */
1173         if (ret > 0)
1174         {
1175                 /**
1176                  * The select says this thread needs to do something useful.
1177                  * This thread was in an idle state so it may have been asked to stop
1178                  * but if the system isn't shutting down this thread is no longer
1179                  * idle and select has given it a task to do so it must not stop
1180                  * In this condition we need to force it into the running state.
1181                  * CtdlThreadGC will clear its ticker for us.
1182                  *
1183                  * FIXME: there is still a small hole here. It is possible for the sequence of locking
1184                  * to allow the state to get changed to STOP_REQ just after this code if the other thread
1185                  * has decided to change the state before this lock, it there fore has to wait till the lock
1186                  * completes but it will continue to change the state. We need something a bit better here.
1187                  */
1188                 citthread_mutex_lock(&CT->ThreadMutex); /* To prevent race condition of a sleeping thread */
1189                 if (GC_thread->state > CTDL_THREAD_STOP_REQ && CT->state <= CTDL_THREAD_STOP_REQ)
1190                 {
1191                         syslog(LOG_DEBUG, "Thread %s (0x%08lx) refused stop request.\n", CT->name, CT->tid);
1192                         CT->state = CTDL_THREAD_RUNNING;
1193                 }
1194                 citthread_mutex_unlock(&CT->ThreadMutex);
1195         }
1196
1197         ctdl_thread_internal_change_state(CT, CTDL_THREAD_RUNNING);
1198
1199         return ret;
1200 }
1201
1202
1203
1204 void *new_worker_thread(void *arg);
1205 extern void close_masters (void);
1206
1207
1208
1209 void go_threading(void)
1210 {
1211         int i;
1212         CtdlThreadNode *last_worker;
1213         struct timeval start, now, result;
1214         double last_duration;
1215
1216         /*
1217          * Initialise the thread system
1218          */
1219         ctdl_thread_internal_init();
1220
1221         /* Second call to module init functions now that threading is up */
1222         initialise_modules(1);
1223         CtdlThreadCreate("select_on_master", CTDLTHREAD_BIGSTACK, select_on_master, NULL);
1224
1225         /*
1226          * This thread is now used for garbage collection of other threads in the thread list
1227          */
1228         syslog(LOG_INFO, "Startup thread %ld becoming garbage collector,\n", (long) citthread_self());
1229
1230         /*
1231          * We do a lot of locking and unlocking of the thread list in here.
1232          * We do this so that we can repeatedly release time for other threads
1233          * that may be waiting on the thread list.
1234          * We are a low priority thread so we can afford to do this
1235          */
1236         
1237         while (CtdlThreadGetCount())
1238         {
1239                 if (CT->signal)
1240                         exit_signal = CT->signal;
1241                 if (exit_signal)
1242                 {
1243                         CtdlThreadStopAll();
1244                 }
1245                 check_sched_shutdown();
1246                 if (CT->state > CTDL_THREAD_STOP_REQ)
1247                 {
1248                         begin_critical_section(S_THREAD_LIST);
1249                         ctdl_thread_internal_calc_loadavg();
1250                         end_critical_section(S_THREAD_LIST);
1251                         
1252                         ctdl_thread_internal_check_scheduled(); /* start scheduled threads */
1253                 }
1254                 
1255                 /* Reduce the size of the worker thread pool if necessary. */
1256                 if ((CtdlThreadGetWorkers() > config.c_min_workers + 1) && (CtdlThreadWorkerAvg < 20) && (CT->state > CTDL_THREAD_STOP_REQ))
1257                 {
1258                         /* Ask a worker thread to stop as we no longer need it */
1259                         begin_critical_section(S_THREAD_LIST);
1260                         last_worker = CtdlThreadList;
1261                         while (last_worker)
1262                         {
1263                                 citthread_mutex_lock(&last_worker->ThreadMutex);
1264                                 if (last_worker->flags & CTDLTHREAD_WORKER && (last_worker->state > CTDL_THREAD_STOPPING) && (last_worker->Context == NULL))
1265                                 {
1266                                         citthread_mutex_unlock(&last_worker->ThreadMutex);
1267                                         break;
1268                                 }
1269                                 citthread_mutex_unlock(&last_worker->ThreadMutex);
1270                                 last_worker = last_worker->next;
1271                         }
1272                         end_critical_section(S_THREAD_LIST);
1273                         if (last_worker)
1274                         {
1275 #ifdef WITH_THREADLOG
1276                                 syslog(LOG_DEBUG, "Thread system, stopping excess worker thread \"%s\" (0x%08lx).\n",
1277                                         last_worker->name,
1278                                         last_worker->tid
1279                                         );
1280 #endif
1281                                 CtdlThreadStop(last_worker);
1282                         }
1283                 }
1284         
1285                 /*
1286                  * If all our workers are working hard, start some more to help out
1287                  * with things
1288                  */
1289                 /* FIXME: come up with a better way to dynamically alter the number of threads
1290                  * based on the system load
1291                  */
1292                 if (    (((CtdlThreadGetWorkers() < config.c_max_workers)
1293                         && (CtdlThreadGetWorkerAvg() > 60))
1294                         || CtdlThreadGetWorkers() < config.c_min_workers)
1295                         && (CT->state > CTDL_THREAD_STOP_REQ)
1296                 )
1297                 {
1298                         /* Only start new threads if we are not going to overload the machine */
1299                         /* Temporarily set to 10 should be enough to make sure we don't stranglew the server
1300                          * at least until we make this a config option */
1301                         if (CtdlThreadGetLoadAvg() < ((double)10.00)) {
1302                                 for (i=0; i<5 ; i++) {
1303                                         CtdlThreadCreate("Worker Thread",
1304                                                 CTDLTHREAD_BIGSTACK + CTDLTHREAD_WORKER,
1305                                                 worker_thread,
1306                                                 NULL
1307                                                 );
1308                                 }
1309                         }
1310                         else
1311                                 syslog(LOG_WARNING, "Server strangled due to machine load average too high.\n");
1312                 }
1313
1314                 CtdlThreadGC();
1315
1316                 if (CtdlThreadGetCount() <= 1) // Shutting down clean up the garbage collector
1317                 {
1318                         CtdlThreadGC();
1319                 }
1320                 
1321 #ifdef THREADS_USESIGNALS
1322                 if (CtdlThreadGetCount() && CT->state > CTDL_THREAD_STOP_REQ)
1323 #else
1324                 if (CtdlThreadGetCount())
1325 #endif
1326                         CtdlThreadSleep(1);
1327         }
1328         /*
1329          * If the above loop exits we must be shutting down since we obviously have no threads
1330          */
1331         ctdl_thread_internal_cleanup();
1332 }
1333
1334
1335
1336