blob: eb43c67b847f877dd7c8a3d583506410022fdb27 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39#include <cc++/config.h>
40#include <cc++/export.h>
41#include <cc++/thread.h>
42#include <cc++/exception.h>
43#include <cc++/process.h>
44#ifdef __BORLANDC__
45#include <stdio.h>
46#include <stdlib.h>
47#else
48#include <cstdio>
49#include <cstdlib>
50#endif
51#include "private.h"
52#include <asm/page.h>
53
54#ifdef CCXX_HAVE_NEW_INIT
55#include <new>
56#else
57inline void* operator new(size_t s,void* p)
58{ return p;}
59#endif
60
61#ifdef WIN32
62#include <process.h>
63#endif
64
65#ifdef CCXX_NAMESPACES
66namespace ost {
67#endif
68
69#ifdef _THR_UNIXWARE
70#undef _POSIX_THREAD_PRIORITY_SCHEDULING
71#define sigwait(x, y) _thr_sigwait(x, y)
72#endif
73
74#ifdef __linux__
75#define CCXX_SIG_THREAD_ALARM
76// NOTE: Comment this line to test Resume/Signal using one signal method
77#define CCXX_SIG_THREAD_STOPCONT
78#endif
79
80#ifndef WIN32
81extern "C"
82{
83 typedef void *(*exec_t)(void *);
84 typedef RETSIGTYPE (*signalexec_t)(int);
85
86#ifndef CCXX_SIG_THREAD_STOPCONT
87#ifndef _THR_SUNOS5
88#ifndef HAVE_PTHREAD_SUSPEND
89 static RETSIGTYPE ccxx_sigsuspend(int);
90#endif
91#endif
92#endif
93
94 static void ccxx_exec_handler(Thread *th);
95 static void ccxx_thread_cleanup(void* arg);
96 static void ccxx_thread_destructor(void* arg);
97 static void ccxx_sig_handler(int signo);
98}
99
100#endif // ndef WIN32
101
102#ifdef CCXX_SIG_THREAD_CANCEL
103
104extern "C" RETSIGTYPE _th_sigcancel(int sig)
105{
106 pthread_exit(NULL);
107}
108
109#endif
110
111#ifdef WIN32
112typedef unsigned (__stdcall *exec_t)(void *);
113#ifndef CCXX_NO_DLL
114# if defined(_MSC_VER) && !defined(_DLL)
115# error This project cannot be compiled as a static library. Some implementation stuff require DLL
116# endif
117#endif // CCXX_NO_DLL
118#endif // WIN32
119
120/*
121 * Start Suspend/Resume stuff
122 */
123
124// method to suspend are
125// - system suspend/resume recursive
126// - system suspend/resume not recursive
127// - one signal only, not recursive
128#ifndef WIN32
129#define CCXX_SUSPEND_MODE_RECURSIVE 1
130#define CCXX_SUSPEND_MODE_NOT_RECURSIVE 2
131#define CCXX_SUSPEND_MODE_ONE_SIGNAL 3
132#define CCXX_SUSPEND_MODE_MACH 4
133
134#if defined(_THR_MACH) && !defined(MACOSX)
135#define CCXX_SUSPEND_MODE CCXX_SUSPEND_MODE_MACH
136#elif defined(HAVE_PTHREAD_SUSPEND)
137#define CCXX_SUSPEND_MODE CCXX_SUSPEND_MODE_NOT_RECURSIVE
138static inline void ccxx_resume(cctid_t tid) { pthread_continue(tid); }
139static inline void ccxx_suspend(cctid_t tid) { pthread_suspend(tid); }
140#else
141# if defined(_THR_SUNOS5) || defined(CCXX_SIG_THREAD_STOPCONT)
142# define CCXX_SUSPEND_MODE CCXX_SUSPEND_MODE_NOT_RECURSIVE
143# ifdef _THR_SUNOS5
144 static inline void ccxx_resume(cctid_t tid) { thr_continue((thread_t)tid); }
145 static inline void ccxx_suspend(cctid_t tid) { thr_suspend((thread_t)tid); }
146# else
147# define CCXX_SIG_THREAD_SUSPEND SIGSTOP
148# define CCXX_SIG_THREAD_RESUME SIGCONT
149 static inline void ccxx_resume(cctid_t tid) {
150 pthread_kill(tid, CCXX_SIG_THREAD_RESUME);
151}
152 static inline void ccxx_suspend(cctid_t tid) {
153 pthread_kill(tid, CCXX_SIG_THREAD_SUSPEND);
154}
155# endif
156# else
157# define CCXX_SUSPEND_MODE CCXX_SUSPEND_MODE_ONE_SIGNAL
158# ifndef SIGUSR3
159# ifdef SIGWINCH
160# define SIGUSR3 SIGWINCH
161# else
162# define SIGUSR3 SIGINT
163# endif
164# endif
165# define CCXX_SIG_THREAD_SUSPEND SIGUSR3
166# define CCXX_SIG_THREAD_RESUME SIGUSR3
167 static inline void ccxx_resume(cctid_t tid) {
168 pthread_kill(tid, CCXX_SIG_THREAD_RESUME);
169 }
170 static inline void ccxx_suspend(cctid_t tid) {
171 pthread_kill(tid, CCXX_SIG_THREAD_SUSPEND);
172 }
173# endif
174#endif
175#endif // ndef WIN32
176
177Thread::Cancel Thread::enterCancel(void)
178{
179 Thread *th = getThread();
180
181 if(!th)
182 return cancelInitial;
183
184 Cancel old = th->_cancel;
185 if(old != cancelDisabled && old != cancelImmediate) {
186 th->setCancel(cancelImmediate);
187#ifdef WIN32
188 Thread::yield();
189#else
190#ifndef ANDROID
191 pthread_testcancel();
192#endif
193#endif
194 }
195
196 return old;
197}
198
199void Thread::exitCancel(Cancel old)
200{
201 Thread *th = getThread();
202
203 if(!th)
204 return;
205
206 if(old != th->_cancel) {
207#ifndef WIN32
208#ifndef ANDROID
209 pthread_testcancel();
210#endif
211#endif
212 th->setCancel(old);
213 }
214}
215
216void Thread::suspend(void)
217{
218 if(!priv)
219 return;
220
221#ifdef WIN32
222 if (!priv->_active || !priv->_suspendEnable) {
223#ifdef CCXX_EXCEPTIONS
224 if (Thread::getException() != throwNothing)
225 throw this;
226#endif
227 return;
228 }
229 SuspendThread(priv->_hThread);
230
231#else
232
233 if (!priv->_suspendEnable) return;
234#if CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_MACH
235 thread_suspend(priv->_mach);
236#endif
237#if CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_RECURSIVE
238 ccxx_suspend(priv->_tid);
239#endif
240#if (CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_NOT_RECURSIVE) \
241 || (CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_ONE_SIGNAL)
242 if (++priv->_suspendcount != 1) return;
243 ccxx_suspend(priv->_tid);
244#endif
245
246#endif // WIN32
247}
248
249#if defined(__FreeBSD__)
250#define AUTOSTACK 0x10000
251#endif
252
253#if defined(MACOSX)
254#define AUTOSTACK 0
255#endif
256
257#ifndef AUTOSTACK
258#define AUTOSTACK 0x100000
259#endif
260
261size_t Thread::_autostack = AUTOSTACK;
262
263void Thread::resume(void)
264{
265 if(!priv)
266 return;
267
268#ifdef WIN32
269 if (!priv->_active || !priv->_suspendEnable) {
270#ifdef CCXX_EXCEPTIONS
271 if (Thread::getException() != throwNothing)
272 throw this;
273#endif
274 return;
275 }
276 ResumeThread(priv->_hThread);
277
278#else
279 if (!priv->_suspendEnable) return;
280#if CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_MACH
281 thread_resume(priv->_mach);
282#endif
283#if CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_RECURSIVE
284 ccxx_resume(priv->_tid);
285#endif
286#if (CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_NOT_RECURSIVE) \
287 || (CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_ONE_SIGNAL)
288 int c;
289 if ( (c = --priv->_suspendcount) > 0) return;
290 if ( c < 0 ) {
291 ++priv->_suspendcount;
292 return;
293 }
294 ccxx_resume(priv->_tid);
295#endif
296
297#endif // WIN32
298}
299
300void Thread::join(void)
301{
302 bool detached = isDetached();
303 joinSem.wait();
304 if(detached) {
305 joinSem.post();
306 return;
307 }
308
309#ifdef WIN32 // wait for real w32 thread to cleanup
310
311 if(priv->_hThread) {
312 WaitForSingleObject(priv->_hThread, INFINITE);
313 ::CloseHandle(priv->_hThread);
314 priv->_hThread = NULL;
315 }
316
317#else // make sure we cleanup exiting thread
318 if(priv->_jtid) {
319 pthread_join(priv->_jtid, NULL);
320 }
321
322 priv->_jtid = 0;
323#endif
324 joinSem.post(); // enable next waiting thread after cleanup
325}
326
327#ifndef WIN32
328#if CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_ONE_SIGNAL
329// NOTE: Do not modify _suspendcount here, one program can call
330// Suspend 2 or more time but this function can be called only once
331inline RETSIGTYPE ThreadImpl::ThreadSigSuspend(int)
332{
333 sigset_t sigs;
334
335 sigemptyset(&sigs);
336 sigaddset(&sigs, SIGUSR3);
337 while ( (getThread()->priv->_suspendcount) > 0) {
338#ifdef HAVE_SIGWAIT2
339 int signo;
340 sigwait(&sigs, &signo);
341#else
342 sigwait(&sigs);
343#endif
344 }
345}
346
347static RETSIGTYPE ccxx_sigsuspend(int signo)
348{
349 return ThreadImpl::ThreadSigSuspend(signo);
350}
351#endif
352
353void Thread::setSuspend(Suspend mode)
354{
355 if(!priv)
356 return;
357
358 priv->_suspendEnable = (mode == suspendEnable);
359#ifndef HAVE_PTHREAD_SUSPEND
360#ifdef CCXX_SIG_THREAD_SUSPEND
361 sigset_t mask;
362
363 sigemptyset(&mask);
364 sigaddset(&mask, CCXX_SIG_THREAD_SUSPEND);
365
366 switch(mode) {
367 case suspendEnable:
368 pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
369 return;
370 case suspendDisable:
371 pthread_sigmask(SIG_BLOCK, &mask, NULL);
372 }
373#endif
374#endif
375}
376
377/*
378 * End Suspend/Resume stuff
379 */
380
381static sigset_t *blocked_signals(sigset_t *sig)
382{
383 sigemptyset(sig);
384 sigaddset(sig, SIGINT);
385 sigaddset(sig, SIGKILL);
386 sigaddset(sig, SIGHUP);
387 sigaddset(sig, SIGABRT);
388 sigaddset(sig, SIGALRM);
389 sigaddset(sig, SIGPIPE);
390#if CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_ONE_SIGNAL
391 sigaddset(sig, SIGUSR3);
392#endif
393 return sig;
394}
395#endif // ndef WIN32
396
397typedef enum ThreadType {
398 threadTypeNormal=0,
399 threadTypeMain,
400 threadTypePosix,
401 threadTypeDummy
402} ThreadType;
403
404class MainThread : public Thread
405{
406protected:
407 void run(void) {return;};
408#ifndef WIN32
409 void onSignal(int signo) { std::exit(signo);};
410#endif
411
412public:
413 MainThread() : Thread(true) {};
414};
415
416// mantain info on thread creation
417class DummyThread : public Thread
418{
419protected:
420 void run() {};
421public:
422 DummyThread() : Thread(false) { priv->_type = threadTypeDummy; }
423#ifdef WIN32
424 static void CheckDelete();
425#endif
426};
427
428#ifdef WIN32
429static ThreadKey _self;
430#else
431// NOTE: _self instantiation MUST appear before _mainthread !!
432ThreadKey ThreadImpl::_self(ccxx_thread_destructor);
433#endif
434
435#ifdef WIN32
436void DummyThread::CheckDelete()
437{
438 Thread *th = (Thread*)_self.getKey();
439 if (!th) return;
440
441 // delete if dummy thread
442 if (th->priv->_type == threadTypeDummy)
443 delete th;
444}
445#endif
446
447static MainThread _mainthread;
448Thread *Thread::_main = NULL;
449
450// invalid pointer to thread used to test deleted thread
451// point in the middle of mainthread...
452#define DUMMY_INVALID_THREAD ((Thread*)(((char*)((Thread*)&_mainthread))+1))
453
454#if !defined(WIN32)
455#ifndef CCXX_SIG_THREAD_ALARM
456PosixThread *PosixThread::_timer = NULL;
457Mutex PosixThread::_arm;
458#endif
459#endif
460
461//void PosixThread::sigInstall(int);
462
463Thread::Thread(bool isMain):
464_cancel(cancelDefault), _start(NULL), priv(new ThreadImpl(threadTypeDummy))
465{
466#ifdef WIN32
467 priv->_tid = GetCurrentThreadId();
468
469 // FIXME: error handling
470 HANDLE process = GetCurrentProcess();
471 DuplicateHandle(process,GetCurrentThread(),process,&priv->_hThread,0,FALSE,DUPLICATE_SAME_ACCESS);
472 _parent = this;
473 priv->_cancellation = CreateEvent(NULL, TRUE, FALSE, NULL);
474
475 if(isMain) {
476 setName("main()");
477 priv->_type = threadTypeMain;
478 _main = this;
479 }
480 else
481 setName("-dummy-");
482 _self.setKey(this);
483
484#else
485 priv->_suspendEnable = false;
486 priv->_tid = pthread_self();
487 _parent = NULL;
488 struct sigaction act;
489
490 // NOTE: for race condition (signal handler can use getThread)
491 // you should initialize _main and _self before registering signals
492 ThreadImpl::_self.setKey(this);
493 if(isMain == true) {
494 _main = this;
495 priv->_type = threadTypeMain;
496#if !defined(__CYGWIN32__) && !defined(__MINGW32__)
497 PosixThread::sigInstall(SIGHUP);
498 PosixThread::sigInstall(SIGALRM);
499 PosixThread::sigInstall(SIGPIPE);
500 PosixThread::sigInstall(SIGABRT);
501
502 memset(&act, 0, sizeof(act));
503 act.sa_handler = (signalexec_t)&ccxx_sig_handler;
504 sigemptyset(&act.sa_mask);
505# ifdef SA_RESTART
506 act.sa_flags = SA_RESTART;
507# else
508 act.sa_flags = 0;
509# endif
510# ifdef SA_INTERRUPT
511 act.sa_flags |= SA_INTERRUPT;
512# endif
513# ifdef SIGPOLL
514 sigaction(SIGPOLL, &act, NULL);
515# else
516 sigaction(SIGIO, &act, NULL);
517# endif
518
519# if CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_ONE_SIGNAL
520 act.sa_handler = ccxx_sigsuspend;
521 sigemptyset(&act.sa_mask);
522# ifdef SA_RESTART
523 act.sa_flags = SA_RESTART;
524# else
525 act.sa_flags = 0;
526# endif
527 sigaction(SIGUSR3, &act, NULL);
528# endif
529
530# ifdef CCXX_SIG_THREAD_CANCEL
531 memset(&act, sizeof(act), 0);
532 act.sa_flags = 0;
533 act.sa_handler = _th_sigcancel;
534 sigemptyset(&act.sa_mask);
535 sigaddset(&act.sa_mask, SIGHUP);
536 sigaddset(&act.sa_mask, SIGALRM);
537 sigaddset(&act.sa_mask, SIGPIPE);
538
539 sigaction(CCXX_SIG_THREAD_CANCEL, &act, NULL);
540# endif
541#endif
542 }
543#endif // WIN32
544}
545
546Thread::Thread(int pri, size_t stack):
547_cancel(cancelDefault), _start(NULL), priv(new ThreadImpl(threadTypeNormal))
548{
549#ifdef WIN32
550 if(!_main) {
551 _self.setKey(NULL);
552 _main = this;
553 setName("main()");
554 }
555 else
556#ifdef WIN32
557 _name[0] = 0;
558#else
559 snprintf(_name, sizeof(_name), "%d", getId());
560#endif
561
562 _parent = Thread::get();
563 if(_parent)
564 priv->_throw = _parent->priv->_throw;
565 else
566 _parent = this;
567
568 priv->_cancellation = CreateEvent(NULL, TRUE, FALSE, NULL);
569 if(!priv->_cancellation)
570 THROW(this);
571
572 if(stack <= _autostack)
573 priv->_stack = 0;
574 else
575 priv->_stack = stack;
576
577 if(pri > 2)
578 pri = 2;
579 if(pri < -2)
580 pri = -2;
581
582 if(Process::isRealtime() && pri < 0)
583 pri = 0;
584
585 switch(pri) {
586 case 1:
587 priv->_priority = THREAD_PRIORITY_ABOVE_NORMAL;
588 break;
589 case -1:
590 priv->_priority = THREAD_PRIORITY_BELOW_NORMAL;
591 break;
592 case 2:
593 priv->_priority = THREAD_PRIORITY_HIGHEST;
594 break;
595 case -2:
596 priv->_priority = THREAD_PRIORITY_LOWEST;
597 break;
598 default:
599 priv->_priority = THREAD_PRIORITY_NORMAL;
600 }
601
602#else
603 pthread_attr_init(&priv->_attr);
604 pthread_attr_setdetachstate(&priv->_attr, PTHREAD_CREATE_JOINABLE);
605
606#ifdef PTHREAD_STACK_MIN
607 if(stack && stack <= _autostack)
608 pthread_attr_setstacksize(&priv->_attr, _autostack);
609 else if(stack > _autostack) {
610 if(stack < PTHREAD_STACK_MIN)
611 stack = PTHREAD_STACK_MIN;
612 else { // align to nearest min boundry
613 int salign = stack / PTHREAD_STACK_MIN;
614 if(stack % PTHREAD_STACK_MIN)
615 ++salign;
616 stack = salign * PTHREAD_STACK_MIN;
617 }
618 if(stack && pthread_attr_setstacksize(&priv->_attr, stack)) {
619#ifdef CCXX_EXCEPTIONS
620 switch(Thread::getException()) {
621 case throwObject:
622 throw(this);
623 return;
624#ifdef COMMON_STD_EXCEPTION
625 case throwException:
626 throw(ThrException("no stack space"));
627 return;
628#endif
629 default:
630 return;
631 }
632#else
633 return;
634#endif
635 }
636 }
637#endif
638
639#ifndef __FreeBSD__
640#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
641#ifdef HAVE_SCHED_GETSCHEDULER
642#define __HAS_PRIORITY_SCHEDULING__
643 if(pri < 0 && Process::isRealtime())
644 pri = 0;
645
646 if(pri) {
647 struct sched_param sched;
648 int policy;
649
650 policy = sched_getscheduler(0);
651 if(policy < 0) {
652#ifdef CCXX_EXCEPTIONS
653 switch(Thread::getException()) {
654 case throwObject:
655 throw(this);
656 return;
657#ifdef COMMON_STD_EXCEPTION
658 case throwException:
659 throw(ThrException("invalid scheduler"));
660 return;
661#endif
662 default:
663 return;
664 }
665#else
666 return;
667#endif
668 }
669
670 sched_getparam(0, &sched);
671
672 pri = sched.sched_priority - pri;
673 if(pri > sched_get_priority_max(policy))
674 pri = sched_get_priority_max(policy);
675
676 if(pri < sched_get_priority_min(policy))
677 pri = sched_get_priority_min(policy);
678
679 sched.sched_priority = pri;
680 pthread_attr_setschedpolicy(&priv->_attr, policy);
681 pthread_attr_setschedparam(&priv->_attr, &sched);
682 }
683#endif // ifdef HAVE_SCHED_GETSCHEDULER
684#endif // ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
685#endif // ifndef __FreeBSD__
686
687#ifndef ANDROID
688#ifdef __HAS_PRIORITY_SCHEDULING__
689 if(!pri)
690 pthread_attr_setinheritsched(&priv->_attr, PTHREAD_INHERIT_SCHED);
691#else
692 pthread_attr_setinheritsched(&priv->_attr, PTHREAD_INHERIT_SCHED);
693#endif
694#endif
695
696 _parent = getThread();
697 priv->_throw = _parent->priv->_throw;
698
699 _cancel = cancelInitial;
700
701#endif // WIN32
702}
703
704#ifndef WIN32
705Thread::Thread(const Thread &th)
706{
707 priv = new ThreadImpl(threadTypeNormal);
708 _parent = th._parent;
709 priv->_attr = th.priv->_attr;
710 _cancel = cancelInitial;
711 _start = NULL;
712 priv->_throw = th.priv->_throw;
713 priv->_suspendEnable = false;
714
715 setName(NULL);
716
717// sigset_t mask, newmask;
718// int rc;
719//
720// pthread_sigmask(SIG_BLOCK, blocked_signals(&newmask), &mask);
721// rc = pthread_create(&_tid, &_attr, exec_t(&ccxx_exec_handler), this);
722// pthread_sigmask(SIG_SETMASK, &mask, NULL);
723// if(rc && Thread::getException() == throwObject)
724// throw(this);
725//#ifdef COMMON_STD_EXCEPTION
726// else if(rc && Thread::getException() == throwException)
727// throw(ThrException("cannot start copy"));
728//#endif
729}
730#endif // ndef WIN32
731
732Thread::~Thread()
733{
734 if(!priv)
735 return;
736
737#ifndef WIN32
738 if(this == &_mainthread)
739 return;
740#endif
741
742 if(priv->_type == threadTypeDummy) {
743 delete priv;
744 priv = NULL;
745 return;
746 }
747
748 terminate();
749}
750
751void Thread::setName(const char *text)
752{
753 if(text)
754 snprintf(_name, sizeof(_name), "%s", text);
755 else
756 snprintf(_name, sizeof(_name), "%ld", (long)getId());
757}
758
759void Thread::initial(void)
760{}
761
762void Thread::final(void)
763{}
764
765void *Thread::getExtended(void)
766{
767 return NULL;
768}
769
770void Thread::notify(Thread *)
771{}
772
773bool Thread::isThread(void) const
774{
775 if(!priv)
776 return false;
777
778#ifdef WIN32
779 return ((priv->_tid == GetCurrentThreadId())) ? true : false;
780#else
781 return (priv->_tid == pthread_self()) ? true : false;
782#endif
783}
784
785bool Thread::isDetached(void) const
786{
787 if(!priv)
788 return false;
789
790#ifdef WIN32
791 // win32 doesn't support detached threads directly
792 return priv->_detached;
793#else
794 int state;
795
796 pthread_attr_getdetachstate(&priv->_attr, &state);
797 if(state == PTHREAD_CREATE_DETACHED)
798 return true;
799 return false;
800#endif
801}
802
803cctid_t Thread::getId(void) const
804{
805 if(!priv)
806 return (cctid_t)-1;
807
808 return priv->_tid;
809}
810
811bool Thread::isRunning(void) const
812{
813 if(!priv)
814 return false;
815#ifdef WIN32
816 return (priv->_tid != 0 && priv->_active) ? true : false;
817#else
818 return (priv->_tid != 0) ? true : false;
819#endif // WIN32
820}
821
822int Thread::start(Semaphore *st)
823{
824 if(!priv)
825 return -1;
826
827#ifdef WIN32
828 if(priv->_active)
829 return -1;
830
831 _start = st;
832
833 priv->_hThread = (HANDLE)_beginthreadex(NULL, (unsigned)priv->_stack, (exec_t)&Execute, (void *)this, CREATE_SUSPENDED, (unsigned *)&priv->_tid);
834 if(!priv->_hThread) {
835 CloseHandle(priv->_cancellation);
836 priv->_cancellation = NULL;
837 return -1;
838 }
839
840 setCancel(cancelInitial);
841
842 SetThreadPriority(priv->_hThread, priv->_priority);
843
844 ResumeThread(priv->_hThread);
845
846 priv->_active = true;
847
848 return 0;
849
850#else
851 if(priv->_tid) {
852 if(_start) {
853 _start->post();
854 return 0;
855 }
856 else
857 return -1;
858 }
859
860 _start = st;
861 return pthread_create(&priv->_tid, &priv->_attr, exec_t(&ccxx_exec_handler), this);
862#endif
863}
864
865int Thread::detach(Semaphore *st)
866{
867 _parent = NULL;
868#ifdef WIN32
869 // win32 we emulate detach
870 if(!priv)
871 return -1;
872 priv->_detached = true;
873 if(!priv->_active)
874 return Thread::start(st);
875 else if(_start)
876 _start->post();
877 return 0;
878#else
879 if(!priv)
880 return -1;
881
882 if(priv->_tid) {
883 pthread_detach(priv->_tid);
884 if(_start) {
885 _start->post();
886 pthread_attr_setdetachstate(&priv->_attr, PTHREAD_CREATE_DETACHED);
887 return 0;
888 }
889 return -1;
890 }
891
892 pthread_attr_setdetachstate(&priv->_attr, PTHREAD_CREATE_DETACHED);
893
894 _start = st;
895 if(!pthread_create(&priv->_tid, &priv->_attr, exec_t(&ccxx_exec_handler), this))
896 return 0;
897 return -1;
898#endif
899}
900
901void Thread::terminate(void)
902{
903#ifdef WIN32
904 HANDLE hThread;
905
906 if(!priv)
907 return;
908
909 hThread = priv->_hThread;
910
911 if (!priv->_tid || isThread()) {
912 if( priv->_cancellation)
913 ::CloseHandle(priv->_cancellation);
914 if(hThread)
915 ::CloseHandle(hThread);
916 delete priv;
917 priv = NULL;
918 return;
919 }
920
921 bool terminated = false;
922 if(!priv->_active && hThread != NULL) {
923 // NOTE: add a test in testthread for multiple
924 // suspended Terminate
925 ResumeThread(hThread);
926 TerminateThread(hThread, 0);
927 terminated = true;
928 }
929 else if(hThread != NULL) {
930 switch(_cancel) {
931 case cancelImmediate:
932 TerminateThread(hThread, 0);
933 terminated = true;
934 break;
935 default:
936 SetEvent(priv->_cancellation);
937 }
938 }
939 if(hThread != NULL) {
940 WaitForSingleObject(hThread, INFINITE);
941 CloseHandle(hThread);
942 hThread = NULL;
943 }
944
945// what if parent already exited?
946
947// if(_parent)
948// _parent->notify(this);
949 if(priv->_cancellation != NULL)
950 CloseHandle(priv->_cancellation);
951 priv->_cancellation = NULL;
952 priv->_tid = 0;
953 if(getThread() == this)
954 _self.setKey(DUMMY_INVALID_THREAD);
955
956 if (terminated)
957 final();
958#else
959 if(!priv)
960 return;
961
962 cctid_t jtid = priv->_jtid, tid = priv->_tid;
963
964 if(jtid && (pthread_self() != jtid)) {
965 pthread_join(jtid, NULL);
966 priv->_jtid = 0;
967 }
968 else if((pthread_self() != tid) && tid) {
969 // in suspend thread cannot be cancelled or signaled
970 // ??? rigth
971 // ccxx_resume(priv->_tid);
972
973
974 // assure thread has ran before we try to cancel...
975 if(_start)
976 _start->post();
977
978 pthread_cancel(tid);
979 if(!isDetached()) {
980 pthread_join(tid,NULL);
981 priv->_tid = 0;
982 }
983 }
984
985 pthread_attr_destroy(&priv->_attr);
986#endif
987 delete priv;
988 priv = NULL;
989}
990
991void Thread::sync(void)
992{
993#if defined(__MACH__) || defined(__GNU__)
994 Thread::exit();
995#else
996 Thread::sleep(TIMEOUT_INF);
997#endif
998}
999
1000void Thread::exit(void)
1001{
1002 if (isThread()) {
1003 setCancel(cancelDisabled);
1004#ifdef WIN32
1005 close();
1006 ExitThread(0);
1007#else
1008 pthread_exit(NULL);
1009#endif // WIN32
1010 }
1011
1012}
1013
1014void Thread::close()
1015{
1016 bool detached = isDetached();
1017
1018#if !defined(CCXX_SIG_THREAD_ALARM) && !defined(__CYGWIN32__) && !defined(__MINGW32__) && !defined(WIN32)
1019 if(this == PosixThread::_timer)
1020 PosixThread::_arm.leaveMutex();
1021#endif
1022 setCancel(cancelDisabled);
1023// if(_parent)
1024// _parent->notify(this);
1025
1026 // final can call destructor (that call Terminate)
1027 final();
1028
1029 // test if this class is self-exiting thread
1030
1031#ifdef WIN32
1032 if (_self.getKey() == this)
1033#else
1034 if (ThreadImpl::_self.getKey() == this)
1035#endif
1036 {
1037 if(priv) {
1038#ifndef WIN32
1039 priv->_jtid = priv->_tid;
1040 priv->_tid = 0;
1041#else
1042 priv->_active = false;
1043#endif
1044 }
1045 joinSem.post();
1046 }
1047
1048 // see if detached, and hence self deleting
1049
1050 if(detached)
1051 delete this;
1052}
1053
1054#ifndef WIN32
1055inline void ThreadImpl::ThreadCleanup(Thread* th)
1056{
1057 // close thread
1058 // (freddy77) Originally I thougth to throw an exception for deferred
1059 // for capture it and cleanup using C++ destructor
1060 // this doesn't work out!!
1061 // Throwing exception here (in cleanup) core dump app
1062 th->close();
1063}
1064
1065extern "C" {
1066 static void ccxx_thread_cleanup(void* arg)
1067 {
1068 ThreadImpl::ThreadCleanup( (Thread*)arg );
1069 }
1070}
1071
1072inline void ThreadImpl::ThreadExecHandler(Thread *th)
1073{
1074 ThreadImpl::_self.setKey(th);
1075 sigset_t mask;
1076
1077 pthread_sigmask(SIG_BLOCK, blocked_signals(&mask), NULL);
1078 th->priv->_tid = pthread_self();
1079#if defined(HAVE_PTHREAD_MACH_THREAD_NP)
1080 th->priv->_mach = pthread_mach_thread_np(th->priv->_tid);
1081#elif defined(_THR_MACH)
1082 th->priv->_mach = mach_thread_self();
1083#endif
1084 th->setCancel(Thread::cancelInitial);
1085 // using SIGUSR3 do not enable suspend by default
1086 th->setSuspend(Thread::suspendEnable);
1087 th->yield();
1088 if(th->_start) {
1089 th->_start->wait();
1090 th->_start = NULL;
1091 }
1092
1093 pthread_cleanup_push(ccxx_thread_cleanup,th);
1094 th->initial();
1095 if(th->getCancel() == Thread::cancelInitial)
1096 th->setCancel(Thread::cancelDefault);
1097 th->run();
1098 th->setCancel(Thread::cancelDisabled);
1099
1100 pthread_cleanup_pop(0);
1101 if(th->isDetached())
1102 ThreadImpl::_self.setKey(NULL);
1103 th->close();
1104 pthread_exit(NULL);
1105}
1106
1107// delete Thread class created for no CommonC++ thread
1108inline void ThreadImpl::ThreadDestructor(Thread* th)
1109{
1110 if (!th || th == DUMMY_INVALID_THREAD || !th->priv)
1111 return;
1112 if(!th->priv)
1113 return;
1114 if (th->priv->_type == threadTypeDummy)
1115 delete th;
1116}
1117
1118extern "C" {
1119 static void ccxx_thread_destructor(void* arg)
1120 {
1121 ThreadImpl::ThreadDestructor( (Thread*)arg );
1122 }
1123
1124 static void ccxx_exec_handler(Thread *th)
1125 {
1126 ThreadImpl::ThreadExecHandler(th);
1127 }
1128}
1129#endif // ndef WIN32
1130
1131#ifdef CCXX_SIG_THREAD_CANCEL
1132
1133void Thread::setCancel(Cancel mode)
1134{
1135 sigset_t mask;
1136
1137 sigemptyset(&mask);
1138 sigaddset(&mask, CCXX_SIG_THREAD_CANCEL);
1139
1140 switch(mode) {
1141 case cancelImmediate:
1142 pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
1143 break;
1144 case cancelInitial:
1145 case cancelDisabled:
1146 case cancelDeferred:
1147 pthread_sigmask(SIG_BLOCK, &mask, NULL);
1148 break;
1149 }
1150 _cancel = mode;
1151}
1152#else
1153
1154void Thread::setCancel(Cancel mode)
1155{
1156#ifdef WIN32
1157 switch(mode) {
1158 case cancelDeferred:
1159 case cancelImmediate:
1160 _cancel = mode;
1161 yield();
1162 break;
1163 case cancelDisabled:
1164 case cancelInitial:
1165 _cancel = mode;
1166 }
1167
1168#else
1169 int old;
1170
1171 switch(mode) {
1172 case cancelImmediate:
1173 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
1174 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old);
1175 break;
1176 case cancelDeferred:
1177 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
1178 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old);
1179 break;
1180 case cancelInitial:
1181 case cancelDisabled:
1182 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old);
1183 break;
1184 default:
1185 return;
1186 }
1187 _cancel = mode;
1188#endif // WIN32
1189}
1190
1191#endif
1192
1193void Thread::yield(void)
1194{
1195#ifdef WIN32
1196 Thread::sleep(1); // note: on Win32, Sleep(0) is "optimized" to NOP.
1197#else
1198
1199#ifdef CCXX_SIG_THREAD_CANCEL
1200 Thread* th = getThread();
1201 sigset_t cancel, old;
1202
1203 sigemptyset(&cancel);
1204 sigaddset(&cancel, CCXX_SIG_THREAD_CANCEL);
1205
1206 if(th && th->_cancel != cancelDisabled &&
1207 th->_cancel != cancelInitial)
1208 pthread_sigmask(SIG_UNBLOCK, &cancel, &old);
1209#else
1210 pthread_testcancel();
1211#endif
1212#ifdef HAVE_PTHREAD_YIELD
1213 pthread_yield();
1214#endif
1215
1216#ifdef CCXX_SIG_THREAD_CANCEL
1217 if(th && th->_cancel != cancelDisabled && th->_cancel != cancelInitial)
1218 pthread_sigmask(SIG_SETMASK, &old, NULL);
1219#endif
1220
1221#endif // WIN32
1222}
1223
1224void Thread::setException(Thread::Throw mode)
1225{
1226 Thread *thread = getThread();
1227 thread->priv->_throw = mode;
1228}
1229
1230Thread::Throw Thread::getException(void)
1231{
1232 Thread *thread = getThread();
1233 return thread->priv->_throw;
1234}
1235
1236Cancellation::Cancellation(Thread::Cancel cancel)
1237{
1238 Thread *thread = getThread();
1239 if(!thread)
1240 return;
1241
1242 prior = thread->getCancel();
1243 thread->setCancel(cancel);
1244}
1245
1246Cancellation::~Cancellation()
1247{
1248 Thread *thread = getThread();
1249 if(!thread)
1250 return;
1251
1252 thread->setCancel(prior);
1253}
1254
1255bool Thread::testCancel(void)
1256{
1257#ifdef WIN32
1258 switch(_cancel) {
1259 case cancelInitial:
1260 case cancelDisabled:
1261 break;
1262 default:
1263 if(WaitForSingleObject(priv->_cancellation, 0) == WAIT_OBJECT_0) {
1264 if (_cancel == cancelManual)
1265 THROW(InterruptException());
1266 else
1267 exit();
1268 }
1269 }
1270 return false;
1271
1272#else // WIN32
1273
1274#ifdef CCXX_SIG_THREAD_CANCEL
1275 sigset_t cancel, old;
1276
1277 sigemptyset(&cancel);
1278 sigaddset(&cancel, CCXX_SIG_THREAD_CANCEL);
1279
1280 if(_cancel != cancelDisabled && _cancel != cancelInitial)
1281 pthread_sigmask(SIG_UNBLOCK, &cancel, &old);
1282#else
1283 pthread_testcancel();
1284#endif
1285
1286#ifdef CCXX_SIG_THREAD_CANCEL
1287 if(_cancel != cancelDisabled)
1288 pthread_sigmask(SIG_SETMASK, &old, NULL);
1289#endif
1290 return false;
1291
1292#endif // WIN32
1293}
1294
1295#ifdef WIN32
1296
1297bool Thread::isCancelled() const
1298{
1299 return waitThread(priv->_cancellation, 0) == WAIT_OBJECT_0;
1300}
1301
1302DWORD Thread::waitThread(HANDLE hRef, timeout_t timeout)
1303{
1304 Thread *th = getThread();
1305
1306 if(th)
1307 return th->waitHandle(hRef, timeout);
1308 else
1309 return WaitForSingleObject(hRef, timeout);
1310}
1311
1312void Thread::sleep(timeout_t timeout)
1313{
1314 Thread *th = getThread();
1315 if(!th) {
1316 SleepEx(timeout, FALSE);
1317 return;
1318 }
1319
1320 switch(th->_cancel) {
1321 case cancelInitial:
1322 case cancelDisabled:
1323 SleepEx(timeout, FALSE);
1324 break;
1325 default:
1326 if(WaitForSingleObject(th->priv->_cancellation, timeout) == WAIT_OBJECT_0) {
1327 if (th->_cancel == cancelManual)
1328 THROW(InterruptException());
1329 else
1330 th->exit();
1331 }
1332 }
1333}
1334
1335DWORD Thread::waitHandle(HANDLE obj, timeout_t timeout)
1336{
1337 HANDLE objects[2];
1338 DWORD stat;
1339
1340 objects[0] = priv->_cancellation;
1341 objects[1] = obj;
1342
1343 // FIXME: what should happen if someone enable cancellation on wait??
1344 switch(_cancel) {
1345 case cancelInitial:
1346 case cancelDisabled:
1347 return WaitForSingleObject(obj, timeout);
1348 default:
1349 switch(stat = WaitForMultipleObjects(2, objects, false, timeout)) {
1350 case WAIT_OBJECT_0:
1351 if (_cancel == cancelManual)
1352 THROW(InterruptException());
1353 else
1354 exit();
1355 case WAIT_OBJECT_0 + 1:
1356 return WAIT_OBJECT_0;
1357 default:
1358 return stat;
1359 }
1360 }
1361}
1362
1363// Entry point linked for default disable thread call, not suitable
1364// for threading library...
1365BOOL WINAPI DllMain(
1366 HANDLE hDllHandle,
1367 DWORD dwReason,
1368 LPVOID lpreserved
1369 )
1370{
1371 switch(dwReason) {
1372 case DLL_THREAD_DETACH:
1373 DummyThread::CheckDelete();
1374 break;
1375 }
1376 return TRUE ;
1377}
1378
1379#endif // WIN32
1380
1381#ifndef WIN32
1382Thread *Thread::get(void)
1383{
1384 Thread *thread;
1385
1386 // fix strange no-init on Solaris
1387 if(!Thread::_main) {
1388 new (&_mainthread) MainThread();
1389 return &_mainthread;
1390 }
1391
1392 thread = (Thread *)ThreadImpl::_self.getKey();
1393
1394 // class have been deleted, return NULL
1395 if (thread == DUMMY_INVALID_THREAD)
1396 return NULL;
1397
1398 if(!thread) {
1399 // this Thread will be deleted by ccxx_thread_destruct
1400 thread = new DummyThread;
1401 ThreadImpl::_self.setKey(thread);
1402 }
1403 return thread;
1404}
1405
1406#else // WIN32
1407
1408Thread *Thread::get(void)
1409{
1410 Thread *th = (Thread *)_self.getKey();
1411 if (th == DUMMY_INVALID_THREAD) return NULL;
1412 // for no common c++ thread construct a dummy thread
1413 if (!th)
1414 th = new DummyThread();
1415 return th;
1416}
1417
1418unsigned __stdcall Thread::Execute(Thread *th)
1419{
1420 _self.setKey(th);
1421 th->yield();
1422
1423 if(th->_start) {
1424 th->_start->wait();
1425 th->_start = NULL;
1426 }
1427
1428 try {
1429 th->priv->_tid = GetCurrentThreadId();
1430 if(!th->_name[0])
1431 snprintf(th->_name, sizeof(th->_name), "%d", GetCurrentThreadId());
1432 th->initial();
1433 if(th->getCancel() == cancelInitial)
1434 th->setCancel(cancelDefault);
1435 th->run();
1436 }
1437 // ignore cancellation exception
1438 catch(const InterruptException&)
1439 { ; }
1440
1441 th->close();
1442 return 0;
1443}
1444#endif //WIN32
1445
1446#if !defined(WIN32)
1447/*
1448 * PosixThread implementation
1449 */
1450inline void ThreadImpl::PosixThreadSigHandler(int signo)
1451{
1452 Thread *t = getThread();
1453 PosixThread *th = NULL;
1454
1455#ifdef CCXX_EXCEPTIONS
1456 if (t) th = dynamic_cast<PosixThread*>(t);
1457#else
1458 if (t) th = (PosixThread*)(t);
1459#endif
1460
1461 if (!th) return;
1462
1463 switch(signo) {
1464 case SIGHUP:
1465 if(th)
1466 th->onHangup();
1467 break;
1468 case SIGABRT:
1469 if(th)
1470 th->onException();
1471 break;
1472 case SIGPIPE:
1473 if(th)
1474 th->onDisconnect();
1475 break;
1476 case SIGALRM:
1477#ifndef CCXX_SIG_THREAD_ALARM
1478 if(PosixThread::_timer) {
1479 PosixThread::_timer->_alarm = 0;
1480 PosixThread::_timer->onTimer();
1481 }
1482 else
1483#endif
1484 if(th)
1485 th->onTimer();
1486 break;
1487#ifdef SIGPOLL
1488 case SIGPOLL:
1489#else
1490 case SIGIO:
1491#endif
1492 if(th)
1493 th->onPolling();
1494 break;
1495 default:
1496 if(th)
1497 th->onSignal(signo);
1498 }
1499}
1500
1501extern "C" {
1502 static void ccxx_sig_handler(int signo)
1503 {
1504 ThreadImpl::PosixThreadSigHandler(signo);
1505 }
1506}
1507
1508PosixThread::PosixThread(int pri, size_t stack):
1509Thread(pri,stack)
1510{
1511 SysTime::getTime(&_alarm);
1512}
1513
1514void PosixThread::onTimer(void)
1515{}
1516
1517void PosixThread::onHangup(void)
1518{}
1519
1520void PosixThread::onException(void)
1521{}
1522
1523void PosixThread::onDisconnect(void)
1524{}
1525
1526void PosixThread::onPolling(void)
1527{}
1528
1529void PosixThread::onSignal(int sig)
1530{}
1531
1532void PosixThread::setTimer(timeout_t timer, bool periodic)
1533{
1534 sigset_t sigs;
1535
1536#ifdef HAVE_SETITIMER
1537 struct itimerval itimer;
1538
1539 memset(&itimer, 0, sizeof(itimer));
1540 itimer.it_value.tv_usec = (timer * 1000) % 1000000;
1541 itimer.it_value.tv_sec = timer / 1000;
1542 if (periodic) {
1543 itimer.it_interval.tv_usec = itimer.it_value.tv_usec;
1544 itimer.it_interval.tv_sec = itimer.it_value.tv_sec;
1545 }
1546#else
1547 timer /= 1000;
1548#endif
1549
1550#ifndef CCXX_SIG_THREAD_ALARM
1551 _arm.enterMutex();
1552 _timer = this;
1553#endif
1554 SysTime::getTime(&_alarm);
1555 sigemptyset(&sigs);
1556 sigaddset(&sigs, SIGALRM);
1557 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
1558#ifdef HAVE_SETITIMER
1559 setitimer(ITIMER_REAL, &itimer, NULL);
1560#else
1561 alarm(timer);
1562#endif
1563}
1564
1565timeout_t PosixThread::getTimer(void) const
1566{
1567#ifdef HAVE_SETITIMER
1568 struct itimerval itimer;
1569#endif
1570
1571 if(!_alarm)
1572 return 0;
1573
1574#ifdef HAVE_SETITIMER
1575 getitimer(ITIMER_REAL, &itimer);
1576 return (timeout_t)(itimer.it_value.tv_sec * 1000 +
1577 itimer.it_value.tv_usec / 1000);
1578#else
1579 time_t now = SysTime::getTime();
1580 return (timeout_t)(((now - _alarm) * 1000) + 500);
1581#endif
1582}
1583
1584void PosixThread::endTimer(void)
1585{
1586#ifdef HAVE_SETITIMER
1587 static const struct itimerval itimer = {{0, 0},{0,0}};
1588#endif
1589
1590 sigset_t sigs;
1591#ifndef CCXX_SIG_THREAD_ALARM
1592 if(_timer != this)
1593 return;
1594#endif
1595
1596#ifdef HAVE_SETITIMER
1597 setitimer(ITIMER_REAL, (struct itimerval *)&itimer, NULL);
1598#else
1599 alarm(0);
1600#endif
1601 sigemptyset(&sigs);
1602 sigaddset(&sigs, SIGALRM);
1603 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
1604#ifndef CCXX_SIG_THREAD_ALARM
1605 _arm.leaveMutex();
1606 _timer = NULL;
1607#endif
1608}
1609
1610#if defined(HAVE_SIGWAIT) || defined(HAVE_SIGWAIT2)
1611void PosixThread::waitSignal(signo_t signo)
1612{
1613 sigset_t mask;
1614
1615 sigemptyset(&mask);
1616 sigaddset(&mask, signo);
1617#ifndef HAVE_SIGWAIT2
1618 signo = sigwait(&mask);
1619#else
1620 sigwait(&mask, &signo);
1621#endif
1622}
1623#endif // ifdef HAVE_SIGWAIT
1624
1625void PosixThread::setSignal(int signo, bool mode)
1626{
1627 sigset_t sigs;
1628
1629 sigemptyset(&sigs);
1630 sigaddset(&sigs, signo);
1631
1632 if(mode)
1633 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
1634 else
1635 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
1636}
1637
1638void PosixThread::signalThread(Thread* th,signo_t signo)
1639{
1640 pthread_kill(th->priv->_tid, signo);
1641 }
1642
1643pthread_attr_t * PosixThread::getPthreadAttrPtr(void)
1644{
1645 return &priv->_attr;
1646}
1647
1648pthread_t PosixThread::getPthreadId(void)
1649{
1650 return priv->_tid;
1651}
1652
1653void PosixThread::sigInstall(int signo)
1654{
1655 struct sigaction act;
1656
1657 act.sa_handler = (signalexec_t)&ccxx_sig_handler;
1658 sigemptyset(&act.sa_mask);
1659
1660#ifdef SA_INTERRUPT
1661 act.sa_flags = SA_INTERRUPT;
1662#else
1663 act.sa_flags = 0;
1664#endif
1665 sigaction(signo, &act, NULL);
1666}
1667#endif
1668
1669#ifdef USE_POLL
1670
1671Poller::Poller()
1672{
1673 nufds = 0;
1674 ufds = NULL;
1675}
1676
1677Poller::~Poller()
1678{
1679 if(ufds) {
1680 delete[] ufds;
1681 ufds = NULL;
1682 }
1683}
1684
1685pollfd *Poller::getList(int cnt)
1686{
1687 if(nufds < cnt) {
1688 if(ufds)
1689 delete[] ufds;
1690 ufds = new pollfd[cnt];
1691 nufds = cnt;
1692 }
1693 return ufds;
1694}
1695
1696#endif
1697
1698Mutex SysTime::timeLock;
1699
1700time_t SysTime::getTime(time_t *tloc)
1701{
1702 time_t ret;
1703 lock();
1704 time_t temp;
1705#ifdef WIN32
1706 ::time(&temp);
1707#else
1708 std::time(&temp);
1709#endif
1710 memcpy(&ret, &temp, sizeof(time_t));
1711 if (tloc != NULL)
1712 memcpy(tloc, &ret, sizeof(time_t));
1713 unlock();
1714 return ret;
1715}
1716
1717int SysTime::getTimeOfDay(struct timeval *tp)
1718{
1719 struct timeval temp;
1720 int ret(0);
1721 lock();
1722
1723#ifdef WIN32
1724 // We could use _ftime(), but it is not available on WinCE.
1725 // (WinCE also lacks time.h)
1726 // Note also that the average error of _ftime is around 20 ms :)
1727 time_t now;
1728 time(&now);
1729 temp.tv_sec = (long)now;
1730 temp.tv_usec = (GetTickCount() % 1000) * 1000;
1731 memcpy(tp, &temp, sizeof(struct timeval));
1732#else
1733 ret = ::gettimeofday(&temp, NULL);
1734 if(ret == 0)
1735 memcpy(tp, &temp, sizeof(struct timeval));
1736#endif
1737
1738 unlock();
1739 return ret;
1740}
1741
1742struct tm *SysTime::getLocalTime(const time_t *clock, struct tm* result)
1743{
1744 lock();
1745#ifdef WIN32
1746 struct tm *temp = ::localtime(clock);
1747#else
1748 struct tm *temp = std::localtime(clock);
1749#endif
1750 memcpy(result, temp, sizeof(struct tm));
1751 unlock();
1752 return result;
1753}
1754
1755struct tm *SysTime::getGMTTime(const time_t *clock, struct tm* result)
1756{
1757 lock();
1758#ifdef WIN32
1759 struct tm *temp = ::gmtime(clock);
1760#else
1761 struct tm *temp = std::gmtime(clock);
1762#endif
1763 memcpy(result, temp, sizeof(struct tm));
1764 unlock();
1765 return result;
1766}
1767
1768// C stuff
1769// this function must declared as extern "C" for some compiler
1770
1771#ifdef CCXX_NAMESPACES
1772}
1773#endif
1774
1775/** EMACS **
1776 * Local variables:
1777 * mode: c++
1778 * tab-width: 4
1779 * c-basic-offset: 4
1780 * End:
1781 */
1782