~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/pbms/src/cslib/CSThread.cc

  • Committer: Brian Aker
  • Date: 2010-12-18 18:24:57 UTC
  • mfrom: (1999.6.3 trunk)
  • Revision ID: brian@tangent.org-20101218182457-yi1wd0so2hml1k1w
Merge in Lee's copyright header fix

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2008 PrimeBase Technologies GmbH, Germany
 
2
 *
 
3
 * PrimeBase Media Stream for MySQL
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 
18
 *
 
19
 * Original author: Paul McCullagh (H&G2JCtL)
 
20
 * Continued development: Barry Leslie
 
21
 *
 
22
 * 2007-05-20
 
23
 *
 
24
 * CORE SYSTEM:
 
25
 * A independently running thread.
 
26
 *
 
27
 */
 
28
 
 
29
#include "CSConfig.h"
 
30
 
 
31
#ifdef OS_WINDOWS
 
32
#include <signal.h>
 
33
//#include "uniwin.h"
 
34
#define SIGUSR1 30
 
35
#define SIGUSR2 31
 
36
 
 
37
#else
 
38
#include <signal.h>
 
39
#include <sys/signal.h>
 
40
#include <unistd.h>
 
41
#endif
 
42
#include <errno.h>
 
43
 
 
44
#include "CSGlobal.h"
 
45
#include "CSLog.h"
 
46
#include "CSException.h"
 
47
#include "CSThread.h"
 
48
#include "CSStrUtil.h"
 
49
#include "CSMemory.h"
 
50
 
 
51
/*
 
52
 * ---------------------------------------------------------------
 
53
 * SIGNAL HANDLERS
 
54
 */
 
55
 
 
56
extern "C" {
 
57
 
 
58
 
 
59
static void td_catch_signal(int sig)
 
60
{
 
61
        CSThread *self;
 
62
 
 
63
        if ((self = CSThread::getSelf())) {
 
64
                if (self->isMain()) {
 
65
                        /* The main thread will pass on a signal to all threads: */
 
66
                        if (self->myThreadList)
 
67
                                self->myThreadList->signalAllThreads(sig);
 
68
                        self->setSignalPending(sig);
 
69
                }
 
70
        }
 
71
        
 
72
}
 
73
 
 
74
static  void td_throw_signal(int sig)
 
75
{
 
76
        CSThread *self;
 
77
 
 
78
        if ((self = CSThread::getSelf())) {
 
79
                if (self->isMain()) {
 
80
                        /* The main thread will pass on a signal to all threads: */
 
81
                        if (self->myThreadList)
 
82
                                self->myThreadList->signalAllThreads(sig);
 
83
                }
 
84
                self->setSignalPending(sig);
 
85
                self->interrupted();
 
86
        }
 
87
}
 
88
 
 
89
static bool td_setup_signals(CSThread *thread)
 
90
{
 
91
#ifdef OS_WINDOWS
 
92
        return true;
 
93
#else
 
94
        struct sigaction action;
 
95
 
 
96
    sigemptyset(&action.sa_mask);
 
97
    action.sa_flags = 0;
 
98
 
 
99
    action.sa_handler = td_catch_signal;
 
100
 
 
101
        if (sigaction(SIGUSR2, &action, NULL) == -1)
 
102
                goto error_occurred;
 
103
 
 
104
    action.sa_handler = td_throw_signal;
 
105
 
 
106
        return true;
 
107
 
 
108
        error_occurred:
 
109
 
 
110
        if (thread) {
 
111
                thread->myException.initOSError(CS_CONTEXT, errno);
 
112
                thread->myException.setStackTrace(thread);
 
113
        }
 
114
        else
 
115
                CSException::throwOSError(CS_CONTEXT, errno);
 
116
        return false;
 
117
#endif
 
118
}
 
119
 
 
120
}
 
121
 
 
122
/*
 
123
 * ---------------------------------------------------------------
 
124
 * THREAD LISTS
 
125
 */
 
126
 
 
127
void CSThreadList::signalAllThreads(int sig)
 
128
{
 
129
        CSThread *ptr;
 
130
 
 
131
        enter_();
 
132
        lock_(this);
 
133
        ptr = (CSThread *) getBack();
 
134
        while (ptr) {
 
135
                if (ptr != self)
 
136
                        ptr->signal(sig);
 
137
                ptr = (CSThread *) ptr->getNextLink();
 
138
        }
 
139
        unlock_(this);
 
140
 
 
141
        exit_();
 
142
}
 
143
 
 
144
void CSThreadList::quitAllThreads()
 
145
{
 
146
        CSThread *ptr;
 
147
 
 
148
        enter_();
 
149
        lock_(this);
 
150
        
 
151
        ptr = (CSThread *) getBack();
 
152
        while (ptr) {
 
153
                if (ptr != self)
 
154
                        ptr->myMustQuit = true;
 
155
                ptr = (CSThread *) ptr->getNextLink();
 
156
        }
 
157
        
 
158
        unlock_(this);
 
159
        exit_();
 
160
}
 
161
 
 
162
void CSThreadList::stopAllThreads()
 
163
{
 
164
        CSThread *thread;
 
165
 
 
166
        enter_();
 
167
        for (;;) {
 
168
                /* Get a thread that is not self! */
 
169
                lock_(this);
 
170
                if ((thread = (CSThread *) getBack())) {
 
171
                        while (thread) {
 
172
                                if (thread != self)
 
173
                                        break;
 
174
                                thread = (CSThread *) thread->getNextLink();
 
175
                        }
 
176
                }
 
177
                if (thread)
 
178
                        thread->retain();
 
179
                unlock_(this);
 
180
                
 
181
                if (!thread)
 
182
                        break;
 
183
                        
 
184
                push_(thread);
 
185
                thread->stop();
 
186
                release_(thread);
 
187
        }
 
188
        exit_();
 
189
}
 
190
 
 
191
/*
 
192
 * ---------------------------------------------------------------
 
193
 * CSTHREAD
 
194
 */
 
195
 
 
196
void CSThread::addToList()
 
197
{
 
198
        if (myThreadList) {
 
199
                enter_();
 
200
                ASSERT(self == this);
 
201
                lock_(myThreadList);
 
202
                myThreadList->addFront(self);
 
203
                isRunning = true;
 
204
                unlock_(myThreadList);
 
205
                exit_();
 
206
        }
 
207
        else
 
208
                isRunning = true;
 
209
}
 
210
        
 
211
void CSThread::removeFromList()
 
212
{
 
213
        if (myThreadList && isRunning) {
 
214
                CSThread *myself = this; // pop_() wants to take a reference to its parameter.
 
215
                enter_();
 
216
                /* Retain the thread in order to ensure
 
217
                 * that after it is removed from the list,
 
218
                 * that it is not freed! This would make the
 
219
                 * unlock_() call invalid, because it requires
 
220
                 * on the thread.
 
221
                 */
 
222
                push_(myself);
 
223
                lock_(myThreadList);
 
224
                myThreadList->remove(RETAIN(myself));
 
225
                unlock_(myThreadList);
 
226
                pop_(myself);
 
227
                outer_();
 
228
        }
 
229
        this->release();
 
230
}
 
231
 
 
232
void *CSThread::dispatch(void *arg)
 
233
{
 
234
        CSThread                *self;
 
235
        void                    *return_data = NULL;
 
236
        int                             err;
 
237
 
 
238
        /* Get a reference to myself: */
 
239
        self = reinterpret_cast<CSThread*>(arg);
 
240
        ASSERT(self);
 
241
 
 
242
        /* Store my thread in the thread key: */
 
243
        if ((err = pthread_setspecific(CSThread::sThreadKey, self))) {
 
244
                CSException::logOSError(self, CS_CONTEXT, err);
 
245
                return NULL;
 
246
        }
 
247
 
 
248
        /*
 
249
         * Make sure the thread is not freed while we
 
250
         * are running:
 
251
         */
 
252
        self->retain();
 
253
 
 
254
        try_(a) {
 
255
                td_setup_signals(NULL);
 
256
 
 
257
                /* Add the thread to the list: */
 
258
                self->addToList();
 
259
 
 
260
                // Run the task from the correct context
 
261
                return_data = self->run();
 
262
        }
 
263
        catch_(a) {
 
264
                self->logException();
 
265
        }
 
266
        cont_(a);
 
267
 
 
268
        /*
 
269
         * Removing from the thread list will also release the thread.
 
270
         */
 
271
        self->removeFromList();
 
272
 
 
273
        // Exit the thread
 
274
        return return_data;
 
275
}
 
276
 
 
277
 
 
278
extern "C"
 
279
{
 
280
 
 
281
static void *dispatch_wrapper(void *arg)
 
282
{
 
283
        return CSThread::dispatch(arg);
 
284
}
 
285
 
 
286
}
 
287
 
 
288
void *CSThread::run()
 
289
{
 
290
        if (iRunFunc)
 
291
                return iRunFunc();
 
292
        return NULL;
 
293
}
 
294
 
 
295
void CSThread::start(bool detached)
 
296
{
 
297
        int err;
 
298
 
 
299
        err = pthread_create(&iThread, NULL, dispatch_wrapper, (void *) this);
 
300
        if (err)
 
301
                CSException::throwOSError(CS_CONTEXT, err);
 
302
        while (!isRunning) {
 
303
                /* Check if the thread is still alive,
 
304
                 * so we don't hang forever.
 
305
                 */
 
306
                if (pthread_kill(iThread, 0))
 
307
                        break;
 
308
                usleep(10);
 
309
        }
 
310
        
 
311
        isDetached = detached;
 
312
        if (detached)
 
313
                pthread_detach(iThread);
 
314
}
 
315
 
 
316
void CSThread::stop()
 
317
{
 
318
        signal(SIGTERM);
 
319
        join();
 
320
}
 
321
 
 
322
void *CSThread::join()
 
323
{
 
324
        void    *return_data = NULL;
 
325
        int             err;
 
326
 
 
327
        enter_();
 
328
        if (isDetached) {
 
329
                while (isRunning && !pthread_kill(iThread, 0)) 
 
330
                        usleep(100);
 
331
        } else if ((err = pthread_join(iThread, &return_data))) {
 
332
                CSException::throwOSError(CS_CONTEXT, err);
 
333
        }
 
334
 
 
335
        return_(return_data);
 
336
}
 
337
 
 
338
void CSThread::setSignalPending(unsigned int sig)
 
339
{
 
340
        if (sig == SIGTERM)
 
341
                /* The terminate signal takes priority: */
 
342
                signalPending = SIGTERM;
 
343
        else if (!signalPending)
 
344
                /* Otherwise, first signal wins... */
 
345
                signalPending = sig;
 
346
}
 
347
 
 
348
void CSThread::signal(unsigned int sig)
 
349
{
 
350
#ifndef OS_WINDOWS // Currently you cannot signal threads on windows.
 
351
        int err;
 
352
 
 
353
        setSignalPending(sig);
 
354
        if ((err = pthread_kill(iThread, SIGUSR2)))
 
355
        {
 
356
                /* Ignore the error if the process does not exist! */
 
357
                if (err != ESRCH) /* No such process */
 
358
                        CSException::throwOSError(CS_CONTEXT, err);
 
359
        }
 
360
#endif
 
361
}
 
362
 
 
363
void CSThread::throwSignal()
 
364
{
 
365
        int sig;
 
366
 
 
367
        if ((sig = signalPending) && !ignoreSignals) {
 
368
                signalPending = 0;
 
369
                CSException::throwSignal(CS_CONTEXT, sig);
 
370
        }
 
371
}
 
372
 
 
373
bool CSThread::isMain()
 
374
{
 
375
        return iIsMain;
 
376
}
 
377
 
 
378
/*
 
379
 * -----------------------------------------------------------------------
 
380
 * THROWING EXCEPTIONS
 
381
 */
 
382
 
 
383
/* 
 
384
 * When an exception is .
 
385
 */
 
386
 
 
387
void CSThread::releaseObjects(CSReleasePtr top)
 
388
{
 
389
        CSObject *obj;
 
390
 
 
391
        while (relTop > top) {
 
392
                /* Remove and release or unlock the object on the top of the stack: */
 
393
                relTop--;
 
394
                switch(relTop->r_type) {
 
395
                        case CS_RELEASE_OBJECT:
 
396
                                if ((obj = relTop->x.r_object))
 
397
                                        obj->release();
 
398
                                break;
 
399
                        case CS_RELEASE_MUTEX:
 
400
                                if (relTop->x.r_mutex)
 
401
                                        relTop->x.r_mutex->unlock();
 
402
                                break;
 
403
                        case CS_RELEASE_POOLED:
 
404
                                if (relTop->x.r_pooled)
 
405
                                        relTop->x.r_pooled->returnToPool();
 
406
                                break;
 
407
                        case CS_RELEASE_MEM:
 
408
                                if (relTop->x.r_mem)
 
409
                                        cs_free(relTop->x.r_mem);
 
410
                                break;
 
411
                        case CS_RELEASE_OBJECT_PTR:
 
412
                                if ((relTop->x.r_objectPtr) && (obj = *(relTop->x.r_objectPtr)))
 
413
                                        obj->release();
 
414
                                break;
 
415
                }
 
416
        }
 
417
}
 
418
 
 
419
/* Throw an already registered error: */
 
420
void CSThread::throwException()
 
421
{
 
422
        /* Record the stack trace: */
 
423
        if (this->jumpDepth > 0 && this->jumpDepth <= CS_JUMP_STACK_SIZE) {
 
424
                /*
 
425
                 * As recommended by Barry:
 
426
                 * release the objects before we jump!
 
427
                 * This has the advantage that the stack context is still
 
428
                 * valid when the resources are released.
 
429
                 */
 
430
                releaseObjects(this->jumpEnv[this->jumpDepth-1].jb_res_top);
 
431
 
 
432
                /* Then do the longjmp: */
 
433
                longjmp(this->jumpEnv[this->jumpDepth-1].jb_buffer, 1);
 
434
        }
 
435
}
 
436
 
 
437
void CSThread::logStack(int depth, const char *msg)
 
438
{
 
439
        char buffer[CS_EXC_CONTEXT_SIZE +1];
 
440
        CSL.lock();
 
441
        CSL.log(this, CSLog::Trace, msg);
 
442
        
 
443
        for (int i= callTop-1; i>=0 && depth; i--, depth--) {
 
444
                cs_format_context(CS_EXC_CONTEXT_SIZE, buffer,
 
445
                        callStack[i].cs_func, callStack[i].cs_file, callStack[i].cs_line);
 
446
                strcat(buffer, "\n");
 
447
                CSL.log(this, CSLog::Trace, buffer);
 
448
        }
 
449
        CSL.unlock();
 
450
}
 
451
 
 
452
void CSThread::logException()
 
453
{
 
454
        myException.log(this);
 
455
}
 
456
 
 
457
/*
 
458
 * This function is called when an exception is caught.
 
459
 * It restores the function call top and frees
 
460
 * any resource allocated by lower levels.
 
461
 */
 
462
void CSThread::caught()
 
463
{
 
464
        /* Restore the call top: */
 
465
        this->callTop = this->jumpEnv[this->jumpDepth].jb_call_top;
 
466
 
 
467
        /* 
 
468
         * Release all all objects that were pushed after
 
469
         * this jump position was set:
 
470
         */
 
471
        releaseObjects(this->jumpEnv[this->jumpDepth].jb_res_top);
 
472
}
 
473
 
 
474
/*
 
475
 * ---------------------------------------------------------------
 
476
 * STATIC METHODS
 
477
 */
 
478
 
 
479
pthread_key_t   CSThread::sThreadKey;
 
480
bool                    CSThread::isUp = false;
 
481
 
 
482
bool CSThread::startUp()
 
483
{
 
484
        int err;
 
485
 
 
486
        isUp = false;
 
487
        if ((err = pthread_key_create(&sThreadKey, NULL))) {
 
488
                CSException::logOSError(CS_CONTEXT, errno);
 
489
        } else
 
490
                isUp = true;
 
491
                
 
492
        return isUp;
 
493
}
 
494
 
 
495
void CSThread::shutDown()
 
496
{
 
497
        isUp = false;
 
498
}
 
499
 
 
500
bool CSThread::attach(CSThread *thread)
 
501
{
 
502
        ASSERT(!getSelf());
 
503
        
 
504
        if (!thread) {
 
505
                CSException::logOSError(CS_CONTEXT, ENOMEM);
 
506
                return false;
 
507
        }
 
508
 
 
509
        if (!setSelf(thread))
 
510
                return false;
 
511
 
 
512
        /* Now we are ready to receive signals: */
 
513
        if (!td_setup_signals(thread))
 
514
                return false;
 
515
 
 
516
        thread->addToList();
 
517
        thread->retain();
 
518
        return true;
 
519
}
 
520
 
 
521
void CSThread::detach(CSThread *thread)
 
522
{
 
523
        ASSERT(!getSelf() || getSelf() == thread);
 
524
        thread->removeFromList();
 
525
        thread->release();
 
526
        pthread_setspecific(sThreadKey, NULL);
 
527
}
 
528
 
 
529
CSThread* CSThread::getSelf()
 
530
{
 
531
        CSThread* self = NULL;
 
532
        
 
533
        if ((!isUp) || !(self = (CSThread*) pthread_getspecific(sThreadKey)))
 
534
                return (CSThread*) NULL;
 
535
                
 
536
#ifdef DEBUG
 
537
        /* PMC - Problem is, if this is called when releasing a
 
538
         * thread, then we have the reference count equal to
 
539
         * zero.
 
540
        if (self && !self->iRefCount) {
 
541
                pthread_setspecific(sThreadKey, NULL);
 
542
                CSException::throwAssertion(CS_CONTEXT, "Freed self pointer referenced.");
 
543
        }
 
544
        */
 
545
#endif
 
546
 
 
547
        return self;
 
548
}
 
549
 
 
550
bool CSThread::setSelf(CSThread *self)
 
551
{
 
552
        int err;
 
553
 
 
554
        if (self) {
 
555
                self->iThread = pthread_self();
 
556
 
 
557
                /* Store my thread in the thread key: */
 
558
                if ((err = pthread_setspecific(sThreadKey, self))) {
 
559
                        self->myException.initOSError(CS_CONTEXT, err);
 
560
                        self->myException.setStackTrace(self);
 
561
                        return false;
 
562
                }
 
563
        }
 
564
        else
 
565
                pthread_setspecific(sThreadKey, NULL);
 
566
        return true;
 
567
}
 
568
 
 
569
/* timeout is in milliseconds */
 
570
void CSThread::sleep(unsigned long timeout)
 
571
{
 
572
        enter_();
 
573
        usleep(timeout * 1000);
 
574
        self->interrupted();
 
575
        exit_();
 
576
}
 
577
 
 
578
#ifdef DEBUG
 
579
int cs_assert(const char *func, const char *file, int line, const char *message)
 
580
{
 
581
        CSException::throwAssertion(func, file, line, message);
 
582
        return 0;
 
583
}
 
584
 
 
585
int cs_hope(const char *func, const char *file, int line, const char *message)
 
586
{
 
587
        CSException e;
 
588
                
 
589
        e.initAssertion(func, file, line, message);
 
590
        e.log(NULL);
 
591
        return 0;
 
592
}
 
593
#endif
 
594
 
 
595
CSThread *CSThread::newThread(CSString *name, ThreadRunFunc run_func, CSThreadList *list)
 
596
{
 
597
        CSThread *thd;
 
598
 
 
599
        enter_();
 
600
        if (!(thd = new CSThread(list))) {
 
601
                name->release();
 
602
                CSException::throwOSError(CS_CONTEXT, ENOMEM);
 
603
        }
 
604
        thd->threadName = name;
 
605
        thd->iRunFunc = run_func;
 
606
        return_(thd);
 
607
}
 
608
 
 
609
CSThread *CSThread::newCSThread()
 
610
{
 
611
        CSThread *thd = NULL;
 
612
 
 
613
        if (!(thd = new CSThread(NULL))) {
 
614
                CSException::throwOSError(CS_CONTEXT, ENOMEM);
 
615
        }
 
616
        
 
617
        return thd;
 
618
}
 
619
 
 
620
/*
 
621
 * ---------------------------------------------------------------
 
622
 * DAEMON THREADS
 
623
 */
 
624
 
 
625
CSDaemon::CSDaemon(time_t wait_time, CSThreadList *list):
 
626
CSThread(list),
 
627
CSSync(),
 
628
myWaitTime(wait_time),
 
629
iSuspended(false),
 
630
iSuspendCount(0)
 
631
{
 
632
}
 
633
 
 
634
CSDaemon::CSDaemon(CSThreadList *list):
 
635
CSThread(list),
 
636
CSSync(),
 
637
myWaitTime(0),
 
638
iSuspended(false),
 
639
iSuspendCount(0)
 
640
{
 
641
}
 
642
 
 
643
void CSDaemon::try_Run(CSThread *self, const bool c_must_sleep)
 
644
{
 
645
        try_(a) {
 
646
                 bool must_sleep = c_must_sleep; // This done to avoid longjmp() clobber.
 
647
                while (!myMustQuit) {
 
648
                        if (must_sleep) {
 
649
                                lock_(this);
 
650
                                if (myWaitTime)
 
651
                                        suspendedWait(myWaitTime);
 
652
                                else
 
653
                                        suspendedWait();
 
654
                                unlock_(this);
 
655
                                if (myMustQuit)
 
656
                                        break;
 
657
                        }
 
658
                        must_sleep = doWork();
 
659
                }
 
660
        }
 
661
        catch_(a) {
 
662
                if (!handleException())
 
663
                        myMustQuit = true;
 
664
        }
 
665
        cont_(a);
 
666
}
 
667
 
 
668
void *CSDaemon::run()
 
669
{
 
670
        bool must_sleep = false;
 
671
 
 
672
        enter_();
 
673
 
 
674
        myMustQuit = !initializeWork();
 
675
 
 
676
        while  (!myMustQuit) {
 
677
                try_Run(self, must_sleep);
 
678
                must_sleep = true;
 
679
        }
 
680
 
 
681
        /* Prevent signals from going off in completeWork! */
 
682
        ignoreSignals = true;
 
683
 
 
684
        return_(completeWork());
 
685
}
 
686
 
 
687
bool CSDaemon::doWork()
 
688
{
 
689
        if (iRunFunc)
 
690
                (void) iRunFunc();
 
691
        return true;
 
692
}
 
693
 
 
694
bool CSDaemon::handleException()
 
695
{
 
696
        if (!myMustQuit)
 
697
                logException();
 
698
        return true;
 
699
}
 
700
 
 
701
void CSDaemon::wakeup()
 
702
{
 
703
        CSSync::wakeup();
 
704
}
 
705
 
 
706
void CSDaemon::stop()
 
707
{
 
708
        myMustQuit = true;
 
709
        wakeup();
 
710
        signal(SIGTERM);
 
711
        join();
 
712
}
 
713
 
 
714
void CSDaemon::suspend()
 
715
{
 
716
        enter_();
 
717
        lock_(this);
 
718
        iSuspendCount++;
 
719
        while (!iSuspended && !myMustQuit)
 
720
                wait(500);
 
721
        if (!iSuspended)
 
722
                iSuspendCount--;
 
723
        unlock_(this);
 
724
        exit_();
 
725
}
 
726
 
 
727
void CSDaemon::resume()
 
728
{
 
729
        enter_();
 
730
        lock_(this);
 
731
        if (iSuspendCount > 0)
 
732
                iSuspendCount--;
 
733
        wakeup();
 
734
        unlock_(this);
 
735
        exit_();
 
736
}
 
737
 
 
738
void CSDaemon::suspended()
 
739
{
 
740
        if (!iSuspendCount || myMustQuit) {
 
741
                iSuspended = false;
 
742
                return;
 
743
        }
 
744
        enter_();
 
745
        lock_(this);
 
746
        while (iSuspendCount && !myMustQuit) {
 
747
                iSuspended = true;
 
748
                wait(500);
 
749
        }
 
750
        iSuspended = false;
 
751
        unlock_(this);
 
752
        exit_();
 
753
}
 
754
 
 
755
void CSDaemon::suspendedWait()
 
756
{
 
757
        iSuspended = true;
 
758
        wait();
 
759
        if (iSuspendCount)
 
760
                suspended();
 
761
}
 
762
 
 
763
void CSDaemon::suspendedWait(time_t milli_sec)
 
764
{
 
765
        iSuspended = true;
 
766
        wait(milli_sec);
 
767
        if (iSuspendCount)
 
768
                suspended();
 
769
        else
 
770
                iSuspended = false;
 
771
}
 
772
 
 
773
/*
 
774
 * ---------------------------------------------------------------
 
775
 * THREAD POOLS
 
776
 */
 
777
 
 
778