Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages | Examples

thread.h

Go to the documentation of this file.
00001 // Copyright (C) 1999-2003 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 00046 #ifndef CCXX_THREAD_H_ 00047 #define CCXX_THREAD_H_ 00048 00049 #ifndef WIN32 00050 #define CCXX_POSIX 00051 #endif // !WIN32 00052 00053 #ifndef CCXX_CONFIG_H_ 00054 #include <cc++/config.h> 00055 #endif 00056 00057 #include <ctime> 00058 00059 #ifndef WIN32 00060 #include <pthread.h> 00061 #endif // !WIN32 00062 00063 #undef CCXX_USE_WIN32_ATOMIC 00064 #ifndef WIN32 00065 #include <time.h> 00066 #include <signal.h> 00067 #include <unistd.h> 00068 00069 #ifdef _THR_UNIXWARE 00070 #undef PTHREAD_MUTEXTYPE_RECURSIVE 00071 #endif 00072 00073 typedef pthread_t cctid_t; 00074 typedef unsigned long timeout_t; 00075 00076 /* 00077 #if defined(__CYGWIN32__) 00078 __declspec(dllimport) long __stdcall InterlockedIncrement(long *); 00079 __declspec(dllimport) long __stdcall InterlockedDecrement(long *); 00080 __declspec(dllimport) long __stdcall InterlockedExchange(long *, long); 00081 #define CCXX_USE_WIN32_ATOMIC 1 00082 #endif 00083 */ 00084 00085 #else // WIN32 00086 typedef DWORD cctid_t; 00087 typedef DWORD timeout_t; 00088 00089 #define MAX_SEM_VALUE 1000000 00090 #define CCXX_USE_WIN32_ATOMIC 1 00091 00092 #endif // !WIN32 00093 00094 #ifdef CCXX_NAMESPACES 00095 namespace ost { 00096 #endif 00097 00098 class __EXPORT Thread; 00099 class __EXPORT ThreadKey; 00100 00101 #define TIMEOUT_INF ~((timeout_t) 0) 00102 00103 #define ENTER_CRITICAL enterMutex(); 00104 #define LEAVE_CRITICAL leaveMutex(); 00105 #define ENTER_DEFERRED setCancel(cancelDeferred); 00106 #define LEAVE_DEFERRED setCancel(cancelImmediate); 00107 00108 #ifndef WIN32 00109 // These macros override common functions with thread-safe versions. In 00110 // particular the common "libc" sleep() has problems since it normally 00111 // uses SIGARLM (as actually defined by "posix"). The pthread_delay and 00112 // usleep found in libpthread are gaurenteed not to use SIGALRM and offer 00113 // higher resolution. psleep() is defined to call the old process sleep. 00114 00115 #undef sleep 00116 #define psleep(x) (sleep)(x) 00117 00118 #ifdef signal 00119 #undef signal 00120 #endif 00121 00122 #endif // !WIN32 00123 00124 #undef Yield 00125 00126 class __EXPORT Conditional; 00127 class __EXPORT Event; 00128 00172 class __EXPORT Mutex 00173 { 00174 private: 00175 static bool _debug; 00176 const char *_name; 00177 #ifndef WIN32 00178 #ifndef PTHREAD_MUTEXTYPE_RECURSIVE 00179 int volatile _level; 00180 Thread *volatile _tid; 00181 #endif 00182 /* 00183 * Pthread mutex object. This is protected rather than private 00184 * because some mixed mode pthread operations require a mutex as 00185 * well as their primary pthread object. A good example of this 00186 * is the Event class, as waiting on a conditional object must be 00187 * associated with an accessable mutex. An alternative would be 00188 * to make such classes "friend" classes of the Mutex. 00189 */ 00190 pthread_mutex_t _mutex; 00191 #else // WIN32 00192 00193 # if defined(MUTEX_UNDERGROUND_WIN32_MUTEX) && defined(MUTEX_UNDERGROUND_WIN32_CRITICALSECTION) 00194 # error "Can't determine underground for Mutex" 00195 # endif 00196 00197 #ifdef MUTEX_UNDERGROUND_WIN32_MUTEX 00198 HANDLE _mutex; 00199 #endif 00200 #ifdef MUTEX_UNDERGROUND_WIN32_CRITICALSECTION 00201 CRITICAL_SECTION _criticalSection; 00202 #endif 00203 00204 #endif // WIN32 00205 00206 public: 00210 Mutex(const char *name = NULL); 00211 00217 virtual ~Mutex(); 00218 00224 static void setDebug(bool mode) 00225 {_debug = mode;}; 00226 00234 void enterMutex(void); 00235 00239 inline void enter(void) 00240 {enterMutex();}; 00241 00242 inline void leave(void) 00243 {leaveMutex();}; 00244 00245 inline bool test(void) 00246 {return tryEnterMutex();}; 00247 00258 bool tryEnterMutex(void); 00259 00270 void leaveMutex(void); 00271 }; 00272 00296 class __EXPORT MutexLock 00297 { 00298 private: 00299 Mutex& mutex; 00300 public: 00304 MutexLock( Mutex& _mutex ) : mutex( _mutex ) 00305 { mutex.enterMutex(); } 00309 // this should be not-virtual 00310 ~MutexLock() 00311 { mutex.leaveMutex(); } 00312 }; 00313 00322 class __EXPORT ThreadLock 00323 { 00324 private: 00325 #ifdef HAVE_PTHREAD_RWLOCK 00326 pthread_rwlock_t _lock; 00327 #else 00328 Mutex mutex; 00329 #endif 00330 00331 public: 00335 ThreadLock(); 00336 00340 virtual ~ThreadLock(); 00341 00345 void readLock(void); 00346 00350 void writeLock(void); 00351 00357 bool tryReadLock(void); 00358 00364 bool tryWriteLock(void); 00365 00369 void unlock(void); 00370 }; 00371 00392 class __EXPORT ReadLock 00393 { 00394 private: 00395 ThreadLock& tl; 00396 00397 public: 00401 ReadLock( ThreadLock& _tl ) : tl( _tl ) 00402 { tl.readLock(); } 00406 // this should be not-virtual 00407 ~ReadLock() 00408 { tl.unlock(); } 00409 }; 00410 00431 class __EXPORT WriteLock 00432 { 00433 private: 00434 ThreadLock& tl; 00435 00436 public: 00440 WriteLock( ThreadLock& _tl ) : tl( _tl ) 00441 { tl.writeLock(); } 00445 // this should be not-virtual 00446 ~WriteLock() 00447 { tl.unlock(); } 00448 }; 00449 00450 00460 class __EXPORT MutexCounter : public Mutex 00461 { 00462 private: 00463 volatile int counter; 00464 00465 public: 00466 MutexCounter(const char *id = NULL); 00467 MutexCounter(int initial, const char *id = NULL); 00468 00469 friend __EXPORT int operator++(MutexCounter &mc); 00470 friend __EXPORT int operator--(MutexCounter &mc); 00471 }; 00472 00483 class __EXPORT AtomicCounter 00484 { 00485 #ifndef CCXX_USE_WIN32_ATOMIC 00486 private: 00487 #ifdef HAVE_ATOMIC_AIX 00488 volatile int counter; 00489 #elif HAVE_ATOMIC 00490 atomic_t atomic; 00491 #else 00492 volatile int counter; 00493 pthread_mutex_t _mutex; 00494 #endif 00495 00496 public: 00500 AtomicCounter(); 00501 00507 AtomicCounter(int value); 00508 00509 ~AtomicCounter(); 00510 00511 int operator++(void); 00512 int operator--(void); 00513 int operator+=(int change); 00514 int operator-=(int change); 00515 int operator+(int change); 00516 int operator-(int change); 00517 int operator=(int value); 00518 bool operator!(void); 00519 operator int(); 00520 #else 00521 private: 00522 long atomic; 00523 00524 public: 00525 inline AtomicCounter() 00526 {atomic = 0;}; 00527 00528 inline AtomicCounter(int value) 00529 {atomic = value;}; 00530 00531 inline int operator++(void) 00532 {return InterlockedIncrement(&atomic);}; 00533 00534 inline int operator--(void) 00535 {return InterlockedDecrement(&atomic);}; 00536 00537 int operator+=(int change); 00538 00539 int operator-=(int change); 00540 00541 inline int operator+(int change) 00542 {return atomic + change;}; 00543 00544 inline int operator-(int change) 00545 {return atomic - change;}; 00546 00547 inline int operator=(int value) 00548 {return InterlockedExchange(&atomic, value);}; 00549 00550 inline bool operator!(void) 00551 {return (atomic == 0) ? true : false;}; 00552 00553 inline operator int() 00554 {return atomic;}; 00555 #endif 00556 }; 00557 00558 #ifndef WIN32 00559 00579 class __EXPORT Conditional 00580 { 00581 private: 00582 pthread_cond_t _cond; 00583 pthread_mutex_t _mutex; 00584 00585 public: 00589 Conditional(const char *id = NULL); 00590 00594 virtual ~Conditional(); 00595 00601 void signal(bool broadcast); 00602 00609 bool wait(timeout_t timer = 0, bool locked = false); 00610 00617 void enterMutex(void); 00618 00627 inline void lock(void) 00628 {enterMutex();}; 00629 00640 bool tryEnterMutex(void); 00641 00642 inline bool test(void) 00643 {return tryEnterMutex();}; 00644 00650 void leaveMutex(void); 00651 00652 inline void unlock(void) 00653 {return leaveMutex();}; 00654 }; 00655 #endif 00656 00674 class __EXPORT Semaphore 00675 { 00676 private: 00677 #ifndef WIN32 00678 unsigned _count, _waiters; 00679 pthread_mutex_t _mutex; 00680 pthread_cond_t _cond; 00681 #else 00682 HANDLE semObject; 00683 #endif // !WIN32 00684 00685 public: 00694 Semaphore(unsigned resource = 0); 00695 00702 virtual ~Semaphore(); 00703 00719 bool wait(timeout_t timeout = 0); 00720 00732 void post(void); 00733 00734 // FIXME: how implement getValue for posix compatibility ? 00740 #ifndef WIN32 00741 #ifndef __CYGWIN32__ 00742 int getValue(void); 00743 #endif 00744 #endif 00745 }; 00746 00766 class __EXPORT SemaphoreLock 00767 { 00768 private: 00769 Semaphore& sem; 00770 00771 public: 00775 SemaphoreLock( Semaphore& _sem ) : sem( _sem ) 00776 { sem.wait(); } 00780 // this should be not-virtual 00781 ~SemaphoreLock() 00782 { sem.post(); } 00783 }; 00784 00798 class __EXPORT Event 00799 { 00800 private: 00801 #ifndef WIN32 00802 pthread_mutex_t _mutex; 00803 pthread_cond_t _cond; 00804 bool _signaled; 00805 int _count; 00806 #else 00807 HANDLE cond; 00808 #endif 00809 00810 public: 00811 Event(); 00812 00813 virtual ~Event(); 00814 00821 void reset(void); 00822 00826 void signal(void); 00827 00836 bool wait(timeout_t timer); 00837 bool wait(void); 00838 }; 00839 00840 01022 class __EXPORT Thread 01023 { 01024 public: 01028 typedef enum Throw { 01029 throwNothing, 01030 throwObject, 01031 throwException 01032 } Throw; 01033 01037 typedef enum Cancel 01038 { 01039 cancelInitial=0, 01040 cancelDeferred=1, 01041 cancelImmediate, 01042 cancelDisabled, 01043 cancelManual, 01045 cancelDefault=cancelDeferred 01047 } Cancel; 01048 01052 typedef enum Suspend 01053 { 01054 suspendEnable, 01055 suspendDisable 01056 } Suspend; 01057 01058 #ifndef WIN32 01059 01060 friend class PosixThread; 01061 #endif 01062 01063 friend class DummyThread; 01064 private: 01065 friend class Cancellation; 01066 friend class postream_type; 01067 friend class Slog; 01068 01069 Semaphore joinSem; 01070 static Thread* _main; 01071 01072 Thread *_parent; 01073 Cancel _cancel; 01074 Semaphore *_start; 01075 01076 // private data 01077 friend class ThreadImpl; 01078 class ThreadImpl* priv; 01079 01080 public: 01081 static Thread *get(void); 01082 01083 private: 01084 #ifdef WIN32 01085 static unsigned __stdcall Execute(Thread *th); 01086 #endif 01087 01088 // close current thread, free all and call Notify 01089 void close(); 01090 01091 private: 01092 char _name[32]; 01093 static size_t _autostack; 01094 01095 #ifdef WIN32 01096 DWORD waitHandle(HANDLE obj, timeout_t timeout); 01097 #endif 01098 01099 protected: 01107 void setName(const char *text); 01108 01118 virtual void run(void) = 0; 01119 01141 virtual void final(void) 01142 {return;}; 01143 01155 virtual void initial(void) 01156 {return;}; 01157 01167 virtual void* getExtended(void) 01168 {return NULL;}; 01169 01177 virtual void notify(Thread*) 01178 {return;}; 01179 01185 void exit(void); 01186 01190 void sync(void); 01191 01195 bool testCancel(void); 01196 01206 void setCancel(Cancel mode); 01207 01215 void setSuspend(Suspend mode); 01216 01225 void terminate(void); 01226 01230 inline void clrParent(void) 01231 {_parent = NULL;}; 01232 01233 public: 01242 Thread(bool isMain); 01243 01255 Thread(int pri = 0, size_t stack = 0); 01256 01257 #ifndef WIN32 01258 01266 Thread(const Thread &th); 01267 #endif 01268 01275 virtual ~Thread(); 01276 01282 static void setStack(size_t size = 0) 01283 {_autostack = size;}; 01284 01294 static void sleep(timeout_t msec); 01295 01300 static void yield(void); 01301 01314 int start(Semaphore *start = 0); 01315 01324 int detach(Semaphore *start = 0); 01325 01332 inline Thread *getParent(void) 01333 {return _parent;}; 01334 01341 void suspend(void); 01342 01346 void resume(void); 01347 01354 inline Cancel getCancel(void) 01355 {return _cancel;}; 01356 01363 bool isRunning(void); 01364 01370 bool isDetached(void); 01371 01375 void join(void); 01376 01383 bool isThread(void); 01384 01390 cctid_t getId(void) const; 01391 01398 const char *getName(void) 01399 {return _name;}; 01400 01406 static Throw getException(void); 01407 01413 static void setException(Throw mode); 01414 01421 friend inline void operator++(Thread &th) 01422 {if (th._start) th._start->post();}; 01423 01424 friend inline void operator--(Thread &th) 01425 {if (th._start) th._start->wait();}; 01426 01427 #ifdef WIN32 01428 bool isCancelled(); 01429 01430 static DWORD waitThread(HANDLE hRef, timeout_t timeout); 01431 #endif 01432 01440 static Cancel enterCancel(void); 01441 01447 static void exitCancel(Cancel cancel); 01448 }; 01449 01459 class __EXPORT Cancellation 01460 { 01461 private: 01462 Thread::Cancel prior; 01463 01464 public: 01465 Cancellation(Thread::Cancel cancel); 01466 ~Cancellation(); 01467 }; 01468 01469 #if !defined(WIN32) && !defined(__MINGW32__) 01470 typedef int signo_t; 01471 01472 class PosixThread: public Thread 01473 { 01474 private: 01475 #ifndef WIN32 01476 01477 friend class ThreadImpl; 01478 friend class Thread; 01479 #endif 01480 #ifndef CCXX_SIG_THREAD_ALARM 01481 static PosixThread *_timer; 01482 static Mutex _arm; 01483 #endif 01484 01485 time_t _alarm; 01486 static void signalThread(Thread* th,signo_t signo); 01487 protected: 01488 01495 inline void signalParent(signo_t signo) 01496 { signalThread(_parent,signo); }; 01497 01504 inline void signalMain(signo_t signo) 01505 { signalThread(_main,signo);}; 01506 01511 virtual void onTimer(void) 01512 {return;}; 01513 01518 virtual void onHangup(void) 01519 {return;}; 01520 01525 virtual void onException(void) 01526 {return;}; 01527 01532 virtual void onDisconnect(void) 01533 {return;}; 01534 01539 virtual void onPolling(void) 01540 {return;}; 01541 01548 virtual void onSignal(int) 01549 {return;}; 01550 01563 void setTimer(timeout_t timer, bool periodic = false); 01564 01571 timeout_t getTimer(void) const; 01572 01578 void endTimer(void); 01579 01580 #if defined(HAVE_SIGWAIT) || defined(HAVE_SIGWAIT2) 01587 void waitSignal(signo_t signo); 01588 #endif 01589 01596 void setSignal(int signo, bool active); 01597 01604 pthread_attr_t *getPthreadAttrPtr(void); 01605 01610 pthread_t getPthreadId(void); 01611 01612 public: 01613 01614 PosixThread(int pri = 0, size_t stack = 0); 01615 01621 inline void signalThread(int signo) 01622 {signalThread(this, signo);}; 01623 01630 static void sigInstall(int signo); 01631 }; 01632 #endif 01633 01648 class __EXPORT ThreadKey 01649 { 01650 private: 01651 #ifndef WIN32 01652 pthread_key_t key; 01653 typedef void (*TDestruct)(void*); 01654 friend class ThreadImpl; 01655 ThreadKey(TDestruct destruct); 01656 #else 01657 DWORD key; 01658 #endif 01659 01660 public: 01664 ThreadKey(); 01668 virtual ~ThreadKey(); 01676 void *getKey(void); 01684 void setKey(void *); 01685 }; 01686 01697 class __EXPORT TimerPort 01698 { 01699 #ifndef WIN32 01700 struct timeval timer; 01701 #else 01702 DWORD timer; 01703 #endif 01704 bool active; 01705 01706 public: 01713 TimerPort(); 01714 01723 void setTimer(timeout_t timeout = 0); 01724 01734 void incTimer(timeout_t timeout); 01735 01741 void endTimer(void); 01742 01754 timeout_t getTimer(void) const; 01755 01765 timeout_t getElapsed(void) const; 01766 }; 01767 01768 01769 01770 // FIXME: not in win32 implementation 01771 #if !defined(WIN32) 01772 01773 // FIXME: private declaration ??? 01774 struct timespec *getTimeout(struct timespec *spec, timeout_t timeout); 01775 01776 #if !defined(__CYGWIN32__) && !defined(__MINGW32__) 01777 void wait(signo_t signo); 01778 #endif 01779 01780 #endif // !WIN32 01781 01782 #ifdef USE_POLL 01783 01791 class Poller 01792 { 01793 private: 01794 int nufds; 01795 pollfd *ufds; 01796 01797 public: 01798 Poller(); 01799 01800 virtual ~Poller(); 01801 01809 pollfd *getList(int cnt); 01810 01816 inline pollfd *getList(void) 01817 {return ufds;}; 01818 }; 01819 #endif 01820 01821 inline Thread *getThread(void) 01822 {return Thread::get();} 01823 01853 class __EXPORT SysTime 01854 { 01855 private: 01856 static Mutex timeLock; 01857 01858 protected: 01859 inline static void lock(void) 01860 {timeLock.enterMutex();} 01861 01862 inline static void unlock(void) 01863 {timeLock.leaveMutex();} 01864 01865 public: 01866 static time_t getTime(time_t *tloc = NULL); 01867 static time_t time(time_t *tloc) 01868 { return getTime(tloc); }; 01869 01870 static int getTimeOfDay(struct timeval *tp); 01871 static int gettimeofday(struct timeval *tp, struct timezone *) 01872 { return getTimeOfDay(tp); }; 01873 01874 static struct tm *getLocalTime(const time_t *clock, struct tm *result); 01875 static struct tm *locatime(const time_t *clock, struct tm *result) 01876 { return getLocalTime(clock, result); }; 01877 01878 static struct tm *getGMTTime(const time_t *clock, struct tm *result); 01879 static struct tm *gmtime(const time_t *clock, struct tm *result) 01880 { return getGMTTime(clock, result);}; 01881 }; 01882 01883 #ifndef HAVE_LOCALTIME_R 01884 01885 inline struct tm *localtime_r(const time_t *t, struct tm *b) 01886 {return SysTime::getLocalTime(t, b);}; 01887 inline char *ctime_r(const time_t *t, char *buf) 01888 {return ctime(t);}; 01889 inline struct tm *gmtime_r(const time_t *t, struct tm *b) \ 01890 {return SysTime::getGMTTime(t, b);}; 01891 inline char *asctime_r(const struct tm *tm, char *b) \ 01892 {return asctime(tm);}; 01893 01894 #endif 01895 01896 #ifdef CCXX_NAMESPACES 01897 } 01898 #endif 01899 01900 #endif 01901

Generated on Fri Jan 21 13:36:02 2005 for GNU CommonC++ by doxygen 1.3.8