~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Mats Kindahl
  • Date: 2008-08-26 07:32:59 UTC
  • mto: (489.1.2 codestyle)
  • mto: This revision was merged to the branch mainline in revision 491.
  • Revision ID: mats@mysql.com-20080826073259-9k4evtajgldgolli
Replaced use of thd_proc_info() macro with calls to
set_proc_info() and get_proc_info() internally.  Introduced
functions set_thd_proc_info() and get_thd_proc_info() for
external users, i.e., plug-ins.

The set_thd_proc_info() accepted callers info that can be used to
print debug output, but the information was not used. The return
value was changed to void and the old value is not fetched any
more. To be able to get the value of proc_info for external
users, the function get_thd_proc_info() was introduced.

The thd_proc_info() macro called set_thd_proc_info() but almost
never used the return value of set_thd_proc_info() so the macro
was replaced with a call of THD::set_proc_info().

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