|
thread.hGo to the documentation of this file.00001 // Copyright (C) 1999-2000 Open Source Telecom Corporation. 00002 // 00003 // This program is free software; you can redistribute it and/or modify 00004 // it under the terms of the GNU General Public License as published by 00005 // the Free Software Foundation; either version 2 of the License, or 00006 // (at your option) any later version. 00007 // 00008 // This program is distributed in the hope that it will be useful, 00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 // GNU General Public License for more details. 00012 // 00013 // You should have received a copy of the GNU General Public License 00014 // along with this program; if not, write to the Free Software 00015 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00016 // 00017 // As a special exception to the GNU General Public License, permission is 00018 // granted for additional uses of the text contained in its release 00019 // of Common C++. 00020 // 00021 // The exception is that, if you link the Common C++ library with other 00022 // files to produce an executable, this does not by itself cause the 00023 // resulting executable to be covered by the GNU General Public License. 00024 // Your use of that executable is in no way restricted on account of 00025 // linking the Common C++ library code into it. 00026 // 00027 // This exception does not however invalidate any other reasons why 00028 // the executable file might be covered by the GNU General Public License. 00029 // 00030 // This exception applies only to the code released under the 00031 // name Common C++. If you copy code from other releases into a copy of 00032 // Common C++, as the General Public License permits, the exception does 00033 // not apply to the code that you add in this way. To avoid misleading 00034 // anyone as to the status of such modified files, you must delete 00035 // this exception notice from them. 00036 // 00037 // If you write modifications of your own for Common C++, it is your choice 00038 // whether to permit this exception to apply to your modifications. 00039 // If you do not wish that, delete this exception notice. 00040 // 00041 00042 #ifndef __CCXX_THREAD_H__ 00043 #define __CCXX_THREAD_H__ 00044 #define __CCXX_POSIX 00045 00046 #ifndef _REENTRANT 00047 #define _REENTRANT 00048 #endif 00049 00050 #ifndef _THREAD_SAFE 00051 #define _THREAD_SAFE 00052 #endif 00053 00054 #ifndef __CCXX_CONFIG_H__ 00055 #ifdef PACKAGE 00056 #undef PACKAGE 00057 #endif 00058 #ifdef VERSION 00059 #undef VERSION 00060 #endif 00061 #include <cc++/config.h> 00062 #endif 00063 00064 #ifndef HAVE_PTHREAD_H 00065 #include <pthread.h> 00066 #include <semaphore.h> 00067 #endif 00068 00069 #ifndef __CCXX_MACROS_H__ 00070 #include <cc++/macros.h> 00071 #else 00072 #ifdef __CCXX_NAMESPACE_H__ 00073 #include <cc++/macros.h> 00074 #endif 00075 #endif 00076 00077 #include <time.h> 00078 #include <signal.h> 00079 #include <setjmp.h> 00080 #include <unistd.h> 00081 00082 #ifdef __linux__ 00083 #define _SIG_THREAD_STOPCONT 00084 #define _SIG_THREAD_ALARM 00085 #endif 00086 00087 #ifdef _THR_UNIXWARE 00088 #define _EFTSAFE 00089 #undef PTHREAD_MUTEXTYPE_RECURSIVE 00090 #undef _POSIX_THREAD_PRIORITY_SCHEDULING 00091 #define sigwait(x, y) _thr_sigwait(x, y) 00092 #endif 00093 00094 typedef pthread_t cctid_t; 00095 typedef unsigned long timeout_t; 00096 typedef int signo_t; 00097 00098 typedef enum { 00099 THROW_NOTHING, 00100 THROW_OBJECT, 00101 THROW_EXCEPTION 00102 } throw_t; 00103 00104 #define TIMEOUT_INF ~((timeout_t) 0) 00105 00106 // use a define so that if the sys/types.h header already defines caddr_t 00107 // as it may on BSD systems, we do not break it by redefining again. 00108 00109 #undef caddr_t 00110 #define caddr_t char * 00111 00112 #define ENTER_CRITICAL EnterMutex(); 00113 #define LEAVE_CRITICAL LeaveMutex(); 00114 #define ENTER_DEFERRED setCancel(THREAD_CANCEL_DEFERRED); 00115 #define LEAVE_DEFERRED setCancel(THREAD_CANCEL_IMMEDIATE); 00116 00117 // These macros override common functions with thread-safe versions. In 00118 // particular the common "libc" sleep() has problems since it normally 00119 // uses SIGARLM (as actually defined by "posix"). The pthread_delay and 00120 // usleep found in libpthread are gaurenteed not to use SIGALRM and offer 00121 // higher resolution. psleep() is defined to call the old process sleep. 00122 00123 #undef sleep 00124 #define sleep(x) ccxx_sleep((x) * 1000) 00125 #define yield() ccxx_yield() 00126 #define psleep(x) (sleep)(x) 00127 00128 typedef enum 00129 { 00130 THREAD_CANCEL_INITIAL=0, 00131 THREAD_CANCEL_DEFERRED=1, 00132 THREAD_CANCEL_IMMEDIATE, 00133 THREAD_CANCEL_DISABLED, 00134 THREAD_CANCEL_DEFAULT=THREAD_CANCEL_DEFERRED, 00135 THREAD_CANCEL_INVALID 00136 } thread_cancel_t; 00137 00138 typedef enum 00139 { 00140 THREAD_SUSPEND_ENABLE, 00141 THREAD_SUSPEND_DISABLE 00142 } thread_suspend_t; 00143 00144 #define THREAD_SIGNAL_BLOCKED false 00145 #define THREAD_SIGNAL_UNBLOCK true 00146 00147 #ifdef _SIG_THREAD_STOPCONT 00148 #define _SIG_THREAD_SUSPEND SIGSTOP 00149 #define _SIG_THREAD_RESUME SIGCONT 00150 #else 00151 #ifndef SIGUSR3 00152 #ifdef SIGWINCH 00153 #define SIGUSR3 SIGWINCH 00154 #else 00155 #define SIGUSR3 SIGINT 00156 #endif 00157 #endif 00158 #define _SIG_THREAD_SUSPEND SIGUSR3 00159 #define _SIG_THREAD_RESUME SIGUSR3 00160 #endif 00161 00162 class Thread; 00163 00164 Thread *getThread(void); 00165 00166 extern "C" { 00167 void execHandler(Thread *th); 00168 void sigHandler(int signo); 00169 }; 00170 00179 class ThreadLock 00180 { 00181 private: 00182 #ifdef HAVE_PTHREAD_RWLOCK 00183 pthread_rwlock_t _lock; 00184 #else 00185 pthread_mutex_t _lock; 00186 #endif 00187 00188 public: 00192 ThreadLock(); 00193 00197 ~ThreadLock(); 00198 00202 void ReadLock(void); 00203 00207 void WriteLock(void); 00208 00214 bool TryReadLock(void); 00215 00221 bool TryWriteLock(void); 00222 00226 void Unlock(void); 00227 }; 00228 00272 class Mutex 00273 { 00274 private: 00275 #ifndef PTHREAD_MUTEXTYPE_RECURSIVE 00276 volatile int _level; 00277 volatile Thread *_tid; 00278 #endif 00279 00280 protected: 00289 pthread_mutex_t _mutex; 00290 00291 public: 00295 Mutex(); 00296 00302 ~Mutex() 00303 {pthread_mutex_destroy(&_mutex);}; 00304 00312 #ifdef PTHREAD_MUTEXTYPE_RECURSIVE 00313 inline void EnterMutex(void) 00314 {pthread_mutex_lock(&_mutex);}; 00315 #else 00316 void EnterMutex(void); 00317 #endif 00318 00329 bool TryEnterMutex(void); 00330 00341 #ifdef PTHREAD_MUTEXTYPE_RECURSIVE 00342 inline void LeaveMutex(void) 00343 {pthread_mutex_unlock(&_mutex);}; 00344 #else 00345 void LeaveMutex(void); 00346 #endif 00347 }; 00348 00358 class MutexCounter : public Mutex 00359 { 00360 private: 00361 int counter; 00362 00363 public: 00364 MutexCounter(int initial = 0); 00365 00366 friend int operator ++(MutexCounter &mc); 00367 friend int operator --(MutexCounter &mc); 00368 }; 00369 00380 class AtomicCounter 00381 { 00382 private: 00383 #ifdef HAVE_ATOMIC 00384 atomic_t atomic; 00385 #else 00386 int counter; 00387 Mutex lock; 00388 #endif 00389 00390 public: 00394 AtomicCounter(); 00395 00401 AtomicCounter(int value); 00402 00403 int operator++(void); 00404 int operator--(void); 00405 int operator+=(int change); 00406 int operator-=(int change); 00407 int operator+(int change); 00408 int operator-(int change); 00409 int operator=(int value); 00410 bool operator!(void); 00411 operator int(); 00412 }; 00413 00431 class Semaphore 00432 { 00433 protected: 00434 sem_t _semaphore; 00435 00436 public: 00445 Semaphore(size_t resource = 0); 00446 00453 ~Semaphore() 00454 #ifndef __linux__ 00455 {sem_destroy(&_semaphore);} 00456 #endif 00457 ; 00458 00472 void Wait(void) 00473 #ifndef __linux__ 00474 {sem_wait(&_semaphore);} 00475 #endif 00476 ; 00477 00489 bool TryWait(void) 00490 #ifndef __linux__ 00491 { return ( sem_trywait(&_semaphore) == 0 ) ? true : false; } 00492 #endif 00493 ; 00494 00506 void Post(void) 00507 #ifndef __linux__ 00508 {sem_post(&_semaphore);} 00509 #endif 00510 ; 00511 00517 int getValue(void); 00518 }; 00519 00533 class Event : public Mutex 00534 { 00535 protected: 00536 pthread_cond_t _cond; 00537 bool _signaled; 00538 int _count; 00539 00540 public: 00541 Event(); 00542 00543 ~Event() 00544 {pthread_cond_destroy(&_cond);}; 00545 00552 void Reset(void) 00553 {_signaled = false;}; 00554 00558 void Signal(void); 00567 bool Wait(timeout_t timer = 0); 00568 }; 00569 00591 class Buffer 00592 { 00593 private: 00594 Mutex lock_head, lock_tail; 00595 Semaphore size_head, size_tail; 00596 size_t _size; 00597 size_t _used; 00598 00599 protected: 00605 virtual int OnPeek(void *buf) = 0; 00611 virtual int OnWait(void *buf) = 0; 00617 virtual int OnPost(void *buf) = 0; 00618 00619 public: 00624 Buffer(size_t capacity); 00629 virtual ~Buffer() 00630 {return;}; 00631 00636 inline size_t getSize(void) 00637 {return _size;}; 00638 00645 inline size_t getUsed(void) 00646 {return _used;}; 00647 00656 int Wait(void *buf); 00657 00665 int Post(void *buf); 00666 00673 int Peek(void *buf); 00674 00679 virtual bool isValid(void) 00680 {return true;}; 00681 }; 00682 00690 class FixedBuffer : public Buffer 00691 { 00692 private: 00693 char *buf, *head, *tail; 00694 size_t objsize; 00695 00696 protected: 00702 int OnPeek(void *buf); 00703 00709 int OnWait(void *buf); 00710 00716 int OnPost(void *buf); 00717 00718 public: 00726 FixedBuffer(size_t capacity, size_t objsize); 00727 00734 FixedBuffer(const FixedBuffer &fb); 00735 00739 ~FixedBuffer(); 00740 00741 FixedBuffer &operator=(const FixedBuffer &fb); 00742 00743 bool isValid(void); 00744 }; 00745 00893 class Thread 00894 { 00895 private: 00896 friend class Slog; 00897 00898 static Thread *_main; 00899 00900 #ifndef _SIG_THREAD_ALARM 00901 static Thread *_timer; 00902 static Mutex _arm; 00903 #endif 00904 00905 Thread *_parent; 00906 pthread_t _tid; 00907 pthread_attr_t _attr; 00908 thread_cancel_t _cancel; 00909 jmp_buf _env; 00910 time_t _alarm; 00911 Semaphore *_start; 00912 int _msgpos; 00913 char _msgbuf[128]; 00914 throw_t _throw; 00915 00916 friend void execHandler(Thread *th); 00917 friend void sigHandler(int signo); 00918 friend Thread *getThread(void); 00919 00920 protected: 00930 virtual void Run(void) = 0; 00931 00938 virtual void First(void) 00939 {return;}; 00940 00953 virtual void Final(void) 00954 {return;}; 00955 00966 virtual void Initial(void) 00967 {return;}; 00968 00978 virtual void *getExtended(void) 00979 {return NULL;}; 00980 00988 virtual void Notify(Thread *th) 00989 {return;}; 00990 00997 inline void SignalParent(signo_t signo) 00998 {_parent->SignalThread(signo);}; 00999 01006 inline void SignalMain(signo_t signo) 01007 {_main->SignalThread(signo);}; 01008 01013 virtual void OnTimer(void) 01014 {return;}; 01015 01020 virtual void OnHangup(void) 01021 {return;}; 01022 01027 virtual void OnException(void) 01028 {return;}; 01029 01034 virtual void OnDisconnect(void) 01035 {return;}; 01036 01041 virtual void OnPolling(void) 01042 {return;}; 01043 01050 virtual void OnSignal(int signo) 01051 {return;}; 01052 01062 inline void Sleep(timeout_t msec) 01063 {ccxx_sleep(msec);}; 01064 01070 inline void Exit(void) 01071 {longjmp(_env, 1);}; 01072 01082 void setTimer(timeout_t timer); 01089 timeout_t getTimer(void); 01095 void endTimer(void); 01102 void WaitSignal(signo_t signo); 01107 void Yield(void); 01111 void testCancel(void); 01120 void setCancel(thread_cancel_t mode); 01128 void setSuspend(thread_suspend_t mode); 01135 void setSignal(int signo, bool mode); 01144 void Terminate(void); 01145 01149 inline void clrParent(void) 01150 {_parent = NULL;}; 01151 public: 01160 Thread(bool flag); 01173 Thread(Semaphore *start = NULL, int pri = 0, size_t stack = 0); 01181 Thread(const Thread &th); 01188 virtual ~Thread() 01189 {Terminate();}; 01190 01203 int Start(Semaphore *start = NULL); 01204 01211 inline Thread *getParent(void) 01212 {return _parent;}; 01213 01219 inline void SignalThread(int signo) 01220 {pthread_kill(_tid, signo);}; 01221 01228 #ifdef _THR_SUNOS5 01229 inline void Suspend(void) 01230 {thr_suspend((thread_t)_tid);}; 01231 #else 01232 inline void Suspend(void) 01233 {pthread_kill(_tid, _SIG_THREAD_SUSPEND);}; 01234 #endif 01235 01239 #ifdef _THR_SUNOS5 01240 inline void Resume(void) 01241 {thr_continue((thread_t)_tid);}; 01242 #else 01243 inline void Resume(void) 01244 {pthread_kill(_tid, _SIG_THREAD_RESUME);}; 01245 #endif 01246 01253 inline int getCancel(void) 01254 {return _cancel;}; 01255 01262 bool isRunning(void); 01263 01270 bool isThread(void); 01271 01277 friend throw_t getException(void); 01278 01284 friend void setException(throw_t mode); 01285 01291 friend void ccxx_sleep(timeout_t msec); 01292 01298 friend void suspend(Thread &th) 01299 {pthread_kill(th._tid, _SIG_THREAD_SUSPEND);}; 01300 01306 friend void resume(Thread &th) 01307 {pthread_kill(th._tid, _SIG_THREAD_RESUME);}; 01308 01315 friend inline void operator++(Thread &th) 01316 {th._start->Post();}; 01317 01318 friend inline void operator--(Thread &th) 01319 {th._start->Wait();}; 01320 01324 friend inline int start(Thread &th, Semaphore *start) 01325 {return th.Start(start);}; 01326 01334 friend void siginstall(int signo); 01335 }; 01336 01351 class ThreadKey 01352 { 01353 private: 01354 pthread_key_t key; 01355 01356 public: 01360 ThreadKey(); 01364 ~ThreadKey(); 01372 void *getKey(void); 01380 void setKey(void *); 01381 }; 01382 01393 class TimerPort 01394 { 01395 struct timeval timer; 01396 bool active; 01397 01398 protected: 01405 TimerPort(); 01406 01407 public: 01416 void setTimer(timeout_t timeout = 0); 01417 01427 void incTimer(timeout_t timeout); 01428 01434 void endTimer(void); 01435 01446 timeout_t getTimer(void); 01447 }; 01448 01449 inline void *getKey(ThreadKey &tk) 01450 {return tk.getKey();}; 01451 01452 inline void setKey(ThreadKey &tk, void *ptr) 01453 {tk.setKey(ptr);}; 01454 01455 inline void operator ++(Mutex &m) 01456 {m.EnterMutex();}; 01457 01458 inline void operator --(Mutex &m) 01459 {m.LeaveMutex();}; 01460 01461 inline void operator ++(Semaphore &s) 01462 {s.Post();}; 01463 01464 inline void operator --(Semaphore &s) 01465 {s.Wait();}; 01466 01467 inline void operator ++(Event &s) 01468 {s.Signal();}; 01469 01470 inline void operator --(Event &s) 01471 {s.Wait();}; 01472 01473 /* 01474 * on some systems, signal(signum, handler) is a macro 01475 */ 01476 #undef signal 01477 inline void signal(Thread &th, int signo) 01478 {th.SignalThread(signo);}; 01479 01480 inline void signal(Event &ev) 01481 {ev.Signal();}; 01482 01483 inline void signal(Semaphore &sem) 01484 {sem.Post();}; 01485 01486 inline void wait(Semaphore &sem) 01487 {sem.Wait();}; 01488 01489 inline void wait(Event &ev, timeout_t timer) 01490 {ev.Wait(timer);}; 01491 01492 inline void reset(Event &ev) 01493 {ev.Reset();}; 01494 01495 inline int get(Buffer &b, void *o) 01496 {return b.Wait(o);}; 01497 01498 inline int put(Buffer &b, void *o) 01499 {return b.Post(o);}; 01500 01501 inline int peek(Buffer &b, void *o) 01502 {return b.Peek(o);}; 01503 01504 int operator++(MutexCounter &mc); 01505 int operator--(MutexCounter &mc); 01506 01507 struct timespec *gettimeout(struct timespec *spec, timeout_t timeout); 01508 void ccxx_sleep(timeout_t msec); 01509 void ccxx_yield(void); 01510 void wait(signo_t signo); 01519 void pdetach(void); 01520 01521 #ifdef __CCXX_NAMESPACE_H__ 01522 #undef __CCXX_NAMESPACE_H__ 01523 #include <cc++/namespace.h> 01524 #endif 01525 01526 #if defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H) 01527 #if defined(HAVE_SYS_STREAM_H) 01528 #if defined(__linux__) 01529 #define __CCXX_USE_POLL 1 01530 #endif 01531 #else 01532 #define __CCXX_USE_POLL 1 01533 #endif 01534 #endif 01535 01536 #ifdef __CCXX_USE_POLL 01537 01545 class Poller 01546 { 01547 private: 01548 int nufds; 01549 pollfd *ufds; 01550 01551 public: 01552 Poller(); 01553 01554 ~Poller(); 01555 01563 pollfd *getList(int cnt); 01564 01570 inline pollfd *getList(void) 01571 {return ufds;}; 01572 }; 01573 #endif 01574 01575 01576 #endif 01577 Generated at Fri Mar 23 10:47:54 2001 for CommonC++ by 1.2.1 written by Dimitri van Heesch, © 1997-2000 |