~drizzle-trunk/drizzle/development

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