GNU CommonC++
|
00001 // Copyright (C) 1999-2005 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, you may use this file as part of a free software 00018 // library without restriction. Specifically, if other files instantiate 00019 // templates or use macros or inline functions from this file, or you compile 00020 // this file and link it with other files to produce an executable, this 00021 // file does not by itself cause the resulting executable to be covered by 00022 // the GNU General Public License. This exception does not however 00023 // invalidate any other reasons why the executable file might be covered by 00024 // the GNU General Public License. 00025 // 00026 // This exception applies only to the code released under the name GNU 00027 // Common C++. If you copy code from other releases into a copy of GNU 00028 // Common C++, as the General Public License permits, the exception does 00029 // not apply to the code that you add in this way. To avoid misleading 00030 // anyone as to the status of such modified files, you must delete 00031 // this exception notice from them. 00032 // 00033 // If you write modifications of your own for GNU Common C++, it is your choice 00034 // whether to permit this exception to apply to your modifications. 00035 // If you do not wish that, delete this exception notice. 00036 // 00037 00043 #ifndef CCXX_THREAD_H_ 00044 #define CCXX_THREAD_H_ 00045 00046 #include <cc++/config.h> 00047 00048 #ifndef WIN32 00049 #define CCXX_POSIX 00050 #endif // !WIN32 00051 00052 #include <ctime> 00053 00054 #ifndef WIN32 00055 #include <pthread.h> 00056 #endif // !WIN32 00057 00058 #undef CCXX_USE_WIN32_ATOMIC 00059 #ifndef WIN32 00060 #include <time.h> 00061 #include <signal.h> 00062 #include <unistd.h> 00063 00064 #ifdef _THR_UNIXWARE 00065 #undef PTHREAD_MUTEXTYPE_RECURSIVE 00066 #endif 00067 00068 typedef pthread_t cctid_t; 00069 typedef unsigned long timeout_t; 00070 00071 /* 00072 #if defined(__CYGWIN32__) 00073 __declspec(dllimport) long __stdcall InterlockedIncrement(long *); 00074 __declspec(dllimport) long __stdcall InterlockedDecrement(long *); 00075 __declspec(dllimport) long __stdcall InterlockedExchange(long *, long); 00076 #define CCXX_USE_WIN32_ATOMIC 1 00077 #endif 00078 */ 00079 00080 #else // WIN32 00081 typedef DWORD cctid_t; 00082 typedef DWORD timeout_t; 00083 00084 #define MAX_SEM_VALUE 1000000 00085 #define CCXX_USE_WIN32_ATOMIC 1 00086 00087 #endif // !WIN32 00088 00089 #ifdef HAVE_GCC_CXX_BITS_ATOMIC 00090 #include <ios> 00091 #endif 00092 00093 #ifdef CCXX_NAMESPACES 00094 namespace ost { 00095 #ifdef __BORLANDC__ 00096 # if __BORLANDC__ >= 0x0560 00097 using std::time_t; 00098 using std::tm; 00099 # endif 00100 #endif 00101 #endif 00102 00103 #ifdef HAVE_GCC_CXX_BITS_ATOMIC 00104 using namespace __gnu_cxx; 00105 #endif 00106 00107 class __EXPORT Thread; 00108 class __EXPORT ThreadKey; 00109 00110 #define TIMEOUT_INF ~((timeout_t) 0) 00111 00112 #define ENTER_CRITICAL enterMutex(); 00113 #define LEAVE_CRITICAL leaveMutex(); 00114 #define ENTER_DEFERRED setCancel(cancelDeferred); 00115 #define LEAVE_DEFERRED setCancel(cancelImmediate); 00116 00117 #ifndef WIN32 00118 // These macros override common functions with thread-safe versions. In 00119 // particular the common "libc" sleep() has problems since it normally 00120 // uses SIGARLM (as actually defined by "posix"). The pthread_delay and 00121 // usleep found in libpthread are gaurenteed not to use SIGALRM and offer 00122 // higher resolution. psleep() is defined to call the old process sleep. 00123 00124 #undef sleep 00125 #define psleep(x) (sleep)(x) 00126 00127 #ifdef signal 00128 #undef signal 00129 #endif 00130 00131 #endif // !WIN32 00132 00133 #undef Yield 00134 00135 class __EXPORT Conditional; 00136 class __EXPORT Event; 00137 00181 class __EXPORT Mutex 00182 { 00183 private: 00184 static bool _debug; 00185 const char *_name; 00186 #ifndef WIN32 00187 #ifndef PTHREAD_MUTEXTYPE_RECURSIVE 00188 int volatile _level; 00189 Thread *volatile _tid; 00190 #endif 00191 /* 00192 * Pthread mutex object. This is protected rather than private 00193 * because some mixed mode pthread operations require a mutex as 00194 * well as their primary pthread object. A good example of this 00195 * is the Event class, as waiting on a conditional object must be 00196 * associated with an accessable mutex. An alternative would be 00197 * to make such classes "friend" classes of the Mutex. 00198 */ 00199 pthread_mutex_t _mutex; 00200 #else // WIN32 00201 00202 # if defined(MUTEX_UNDERGROUND_WIN32_MUTEX) && defined(MUTEX_UNDERGROUND_WIN32_CRITICALSECTION) 00203 # error "Can't determine underground for Mutex" 00204 # endif 00205 00206 #ifdef MUTEX_UNDERGROUND_WIN32_MUTEX 00207 HANDLE _mutex; 00208 #endif 00209 #ifdef MUTEX_UNDERGROUND_WIN32_CRITICALSECTION 00210 CRITICAL_SECTION _criticalSection; 00211 #endif 00212 00213 #endif // WIN32 00214 00215 public: 00221 Mutex(const char *name = NULL); 00222 00228 virtual ~Mutex(); 00229 00235 static void setDebug(bool mode) 00236 {_debug = mode;}; 00237 00243 inline void nameMutex(const char *name) 00244 {_name = name;}; 00245 00253 void enterMutex(void); 00254 00258 inline void enter(void) 00259 {enterMutex();}; 00260 00264 inline void leave(void) 00265 {leaveMutex();}; 00266 00272 inline bool test(void) 00273 {return tryEnterMutex();}; 00274 00285 bool tryEnterMutex(void); 00286 00297 void leaveMutex(void); 00298 }; 00299 00323 class __EXPORT MutexLock 00324 { 00325 private: 00326 Mutex& mutex; 00327 public: 00333 MutexLock( Mutex& _mutex ) : mutex( _mutex ) 00334 { mutex.enterMutex(); } 00335 00339 // this should be not-virtual 00340 ~MutexLock() 00341 { mutex.leaveMutex(); } 00342 }; 00343 00352 class __EXPORT ThreadLock 00353 { 00354 private: 00355 #ifdef HAVE_PTHREAD_RWLOCK 00356 pthread_rwlock_t _lock; 00357 #else 00358 Mutex mutex; 00359 #endif 00360 00361 public: 00365 ThreadLock(); 00366 00370 virtual ~ThreadLock(); 00371 00375 void readLock(void); 00376 00380 void writeLock(void); 00381 00387 bool tryReadLock(void); 00388 00394 bool tryWriteLock(void); 00395 00399 void unlock(void); 00400 }; 00401 00422 class __EXPORT ReadLock 00423 { 00424 private: 00425 ThreadLock& tl; 00426 00427 public: 00433 ReadLock( ThreadLock& _tl ) : tl( _tl ) 00434 { tl.readLock(); } 00438 // this should be not-virtual 00439 ~ReadLock() 00440 { tl.unlock(); } 00441 }; 00442 00463 class __EXPORT WriteLock 00464 { 00465 private: 00466 ThreadLock& tl; 00467 00468 public: 00474 WriteLock( ThreadLock& _tl ) : tl( _tl ) 00475 { tl.writeLock(); } 00479 // this should be not-virtual 00480 ~WriteLock() 00481 { tl.unlock(); } 00482 }; 00483 00484 00494 class __EXPORT MutexCounter : public Mutex 00495 { 00496 private: 00497 volatile int counter; 00498 00499 public: 00505 MutexCounter(const char *id = NULL); 00506 00514 MutexCounter(int initial, const char *id = NULL); 00515 00516 friend __EXPORT int operator++(MutexCounter &mc); 00517 friend __EXPORT int operator--(MutexCounter &mc); 00518 }; 00519 00530 class __EXPORT AtomicCounter 00531 { 00532 #ifndef CCXX_USE_WIN32_ATOMIC 00533 private: 00534 #if defined(HAVE_ATOMIC_AIX) 00535 volatile int counter; 00536 #elif defined(HAVE_GCC_BITS_ATOMIC) 00537 volatile _Atomic_word counter; 00538 #elif defined(HAVE_GCC_CXX_BITS_ATOMIC) 00539 volatile _Atomic_word counter; 00540 // __gnu_cxx::_Atomic_word counter; 00541 #elif defined(HAVE_ATOMIC) 00542 atomic_t atomic; 00543 #else 00544 volatile int counter; 00545 pthread_mutex_t _mutex; 00546 #endif 00547 00548 public: 00552 AtomicCounter(); 00553 00559 AtomicCounter(int value); 00560 00561 ~AtomicCounter(); 00562 00563 int operator++(void); 00564 int operator--(void); 00565 int operator+=(int change); 00566 int operator-=(int change); 00567 int operator+(int change); 00568 int operator-(int change); 00569 int operator=(int value); 00570 bool operator!(void); 00571 operator int(); 00572 #else 00573 private: 00574 long atomic; 00575 00576 public: 00577 inline AtomicCounter() 00578 {atomic = 0;}; 00579 00580 inline AtomicCounter(int value) 00581 {atomic = value;}; 00582 00583 inline int operator++(void) 00584 {return InterlockedIncrement(&atomic);}; 00585 00586 inline int operator--(void) 00587 {return InterlockedDecrement(&atomic);}; 00588 00589 int operator+=(int change); 00590 00591 int operator-=(int change); 00592 00593 inline int operator+(int change) 00594 {return atomic + change;}; 00595 00596 inline int operator-(int change) 00597 {return atomic - change;}; 00598 00599 inline int operator=(int value) 00600 {return InterlockedExchange(&atomic, value);}; 00601 00602 inline bool operator!(void) 00603 {return (atomic == 0) ? true : false;}; 00604 00605 inline operator int() 00606 {return atomic;}; 00607 #endif 00608 }; 00609 00610 #ifndef WIN32 00611 00631 class __EXPORT Conditional 00632 { 00633 private: 00634 pthread_cond_t _cond; 00635 pthread_mutex_t _mutex; 00636 00637 public: 00643 Conditional(const char *id = NULL); 00644 00648 virtual ~Conditional(); 00649 00655 void signal(bool broadcast); 00656 00663 bool wait(timeout_t timer = 0, bool locked = false); 00664 00671 void enterMutex(void); 00672 00681 inline void lock(void) 00682 {enterMutex();}; 00683 00694 bool tryEnterMutex(void); 00695 00696 inline bool test(void) 00697 {return tryEnterMutex();}; 00698 00704 void leaveMutex(void); 00705 00706 inline void unlock(void) 00707 {return leaveMutex();}; 00708 }; 00709 #endif 00710 00728 class __EXPORT Semaphore 00729 { 00730 private: 00731 #ifndef WIN32 00732 unsigned _count, _waiters; 00733 pthread_mutex_t _mutex; 00734 pthread_cond_t _cond; 00735 #else 00736 HANDLE semObject; 00737 #endif // !WIN32 00738 00739 public: 00748 Semaphore(unsigned resource = 0); 00749 00756 virtual ~Semaphore(); 00757 00773 bool wait(timeout_t timeout = 0); 00774 00786 void post(void); 00787 00788 // FIXME: how implement getValue for posix compatibility ? 00789 // not portable... 00790 00791 #if 0 00792 00797 int getValue(void); 00798 #endif 00799 }; 00800 00820 class __EXPORT SemaphoreLock 00821 { 00822 private: 00823 Semaphore& sem; 00824 00825 public: 00829 SemaphoreLock( Semaphore& _sem ) : sem( _sem ) 00830 { sem.wait(); } 00834 // this should be not-virtual 00835 ~SemaphoreLock() 00836 { sem.post(); } 00837 }; 00838 00852 class __EXPORT Event 00853 { 00854 private: 00855 #ifndef WIN32 00856 pthread_mutex_t _mutex; 00857 pthread_cond_t _cond; 00858 bool _signaled; 00859 int _count; 00860 #else 00861 HANDLE cond; 00862 #endif 00863 00864 public: 00865 Event(); 00866 00867 virtual ~Event(); 00868 00875 void reset(void); 00876 00880 void signal(void); 00881 00890 bool wait(timeout_t timer); 00891 bool wait(void); 00892 }; 00893 00894 01076 class __EXPORT Thread 01077 { 01078 public: 01082 typedef enum Throw { 01083 throwNothing, 01084 throwObject, 01085 throwException 01086 } Throw; 01087 01091 typedef enum Cancel { 01092 cancelInitial=0, 01093 cancelDeferred=1, 01094 cancelImmediate, 01095 cancelDisabled, 01096 cancelManual, 01098 cancelDefault=cancelDeferred 01100 } Cancel; 01101 01105 typedef enum Suspend { 01106 suspendEnable, 01107 suspendDisable 01108 } Suspend; 01109 01110 #ifndef WIN32 01111 01112 friend class PosixThread; 01113 #endif 01114 01115 friend class DummyThread; 01116 private: 01117 friend class Cancellation; 01118 friend class postream_type; 01119 friend class Slog; 01120 01121 Semaphore joinSem; 01122 static Thread* _main; 01123 01124 Thread *_parent; 01125 Cancel _cancel; 01126 Semaphore *_start; 01127 01128 // private data 01129 friend class ThreadImpl; 01130 class ThreadImpl* priv; 01131 01132 public: 01133 static Thread *get(void); 01134 01135 private: 01136 #ifdef WIN32 01137 static unsigned __stdcall Execute(Thread *th); 01138 #endif 01139 01140 // close current thread, free all and call Notify 01141 void close(); 01142 01143 private: 01144 char _name[32]; 01145 static size_t _autostack; 01146 01147 #ifdef WIN32 01148 DWORD waitHandle(HANDLE obj, timeout_t timeout); 01149 #endif 01150 01151 protected: 01159 void setName(const char *text); 01160 01170 virtual void run(void) = 0; 01171 01193 virtual void final(void); 01194 01206 virtual void initial(void); 01207 01217 virtual void* getExtended(void); 01218 01226 virtual void notify(Thread*); 01227 01233 void exit(void); 01234 01238 void sync(void); 01239 01243 bool testCancel(void); 01244 01254 void setCancel(Cancel mode); 01255 01263 void setSuspend(Suspend mode); 01264 01273 void terminate(void); 01274 01278 inline void clrParent(void) 01279 {_parent = NULL;}; 01280 01281 public: 01290 Thread(bool isMain); 01291 01303 Thread(int pri = 0, size_t stack = 0); 01304 01305 #ifndef WIN32 01306 01314 Thread(const Thread &th); 01315 #endif 01316 01323 virtual ~Thread(); 01324 01330 static void setStack(size_t size = 0) 01331 {_autostack = size;}; 01332 01342 static void sleep(timeout_t msec); 01343 01348 static void yield(void); 01349 01362 int start(Semaphore *start = 0); 01363 01372 int detach(Semaphore *start = 0); 01373 01380 inline Thread *getParent(void) 01381 {return _parent;}; 01382 01389 void suspend(void); 01390 01394 void resume(void); 01395 01402 inline Cancel getCancel(void) 01403 {return _cancel;}; 01404 01411 bool isRunning(void) const; 01412 01418 bool isDetached(void) const; 01419 01423 void join(void); 01424 01431 bool isThread(void) const; 01432 01438 cctid_t getId(void) const; 01439 01446 const char *getName(void) const 01447 {return _name;}; 01448 01454 static Throw getException(void); 01455 01461 static void setException(Throw mode); 01462 01469 friend inline void operator++(Thread &th) 01470 {if (th._start) th._start->post();}; 01471 01472 friend inline void operator--(Thread &th) 01473 {if (th._start) th._start->wait();}; 01474 01475 #ifdef WIN32 01476 bool isCancelled() const; 01477 01478 static DWORD waitThread(HANDLE hRef, timeout_t timeout); 01479 #endif 01480 01488 static Cancel enterCancel(void); 01489 01495 static void exitCancel(Cancel cancel); 01496 }; 01497 01507 class __EXPORT Cancellation 01508 { 01509 private: 01510 Thread::Cancel prior; 01511 01512 public: 01513 Cancellation(Thread::Cancel cancel); 01514 ~Cancellation(); 01515 }; 01516 01517 #if !defined(WIN32) && !defined(__MINGW32__) 01518 typedef int signo_t; 01519 01520 class PosixThread: public Thread 01521 { 01522 private: 01523 #ifndef WIN32 01524 01525 friend class ThreadImpl; 01526 friend class Thread; 01527 #endif 01528 #ifndef CCXX_SIG_THREAD_ALARM 01529 static PosixThread *_timer; 01530 static Mutex _arm; 01531 #endif 01532 01533 time_t _alarm; 01534 static void signalThread(Thread* th,signo_t signo); 01535 protected: 01536 01543 inline void signalParent(signo_t signo) 01544 { signalThread(_parent,signo); }; 01545 01552 inline void signalMain(signo_t signo) 01553 { signalThread(_main,signo);}; 01554 01559 virtual void onTimer(void); 01560 01565 virtual void onHangup(void); 01566 01571 virtual void onException(void); 01572 01577 virtual void onDisconnect(void); 01578 01583 virtual void onPolling(void); 01584 01591 virtual void onSignal(int); 01592 01605 void setTimer(timeout_t timer, bool periodic = false); 01606 01613 timeout_t getTimer(void) const; 01614 01620 void endTimer(void); 01621 01622 #if defined(HAVE_SIGWAIT) || defined(HAVE_SIGWAIT2) 01623 01629 void waitSignal(signo_t signo); 01630 #endif 01631 01638 void setSignal(int signo, bool active); 01639 01646 pthread_attr_t *getPthreadAttrPtr(void); 01647 01652 pthread_t getPthreadId(void); 01653 01654 public: 01655 01656 PosixThread(int pri = 0, size_t stack = 0); 01657 01663 inline void signalThread(int signo) 01664 {signalThread(this, signo);}; 01665 01672 static void sigInstall(int signo); 01673 }; 01674 #endif 01675 01690 class __EXPORT ThreadKey 01691 { 01692 private: 01693 #ifndef WIN32 01694 pthread_key_t key; 01695 typedef void (*TDestruct)(void*); 01696 friend class ThreadImpl; 01697 ThreadKey(TDestruct destruct); 01698 #else 01699 DWORD key; 01700 #endif 01701 01702 public: 01706 ThreadKey(); 01707 01711 virtual ~ThreadKey(); 01712 01720 void *getKey(void); 01721 01729 void setKey(void *); 01730 }; 01731 01742 class __EXPORT TimerPort 01743 { 01744 #ifndef WIN32 01745 struct timeval timer; 01746 #else 01747 DWORD timer; 01748 #endif 01749 bool active; 01750 01751 public: 01758 TimerPort(); 01759 01768 void setTimer(timeout_t timeout = 0); 01769 01779 void incTimer(timeout_t timeout); 01780 01790 void decTimer(timeout_t timeout); 01791 01796 void sleepTimer(void); 01797 01803 void endTimer(void); 01804 01816 timeout_t getTimer(void) const; 01817 01827 timeout_t getElapsed(void) const; 01828 }; 01829 01830 01831 01832 // FIXME: not in win32 implementation 01833 #if !defined(WIN32) 01834 01835 // FIXME: private declaration ??? 01836 struct timespec *getTimeout(struct timespec *spec, timeout_t timeout); 01837 01838 #if !defined(__CYGWIN32__) && !defined(__MINGW32__) 01839 void wait(signo_t signo); 01840 #endif 01841 01842 #endif // !WIN32 01843 01844 #ifdef USE_POLL 01845 01853 class Poller 01854 { 01855 private: 01856 int nufds; 01857 pollfd *ufds; 01858 01859 public: 01860 Poller(); 01861 01862 virtual ~Poller(); 01863 01871 pollfd *getList(int cnt); 01872 01878 inline pollfd *getList(void) 01879 {return ufds;}; 01880 }; 01881 #endif 01882 01883 inline Thread *getThread(void) 01884 {return Thread::get();} 01885 01915 class __EXPORT SysTime 01916 { 01917 private: 01918 static Mutex timeLock; 01919 01920 protected: 01921 inline static void lock(void) 01922 {timeLock.enterMutex();} 01923 01924 inline static void unlock(void) 01925 {timeLock.leaveMutex();} 01926 01927 public: 01928 static time_t getTime(time_t *tloc = NULL); 01929 static time_t time(time_t *tloc) 01930 { return getTime(tloc); }; 01931 01932 static int getTimeOfDay(struct timeval *tp); 01933 static int gettimeofday(struct timeval *tp, struct timezone *) 01934 { return getTimeOfDay(tp); }; 01935 01936 static struct tm *getLocalTime(const time_t *clock, struct tm *result); 01937 static struct tm *locatime(const time_t *clock, struct tm *result) 01938 { return getLocalTime(clock, result); }; 01939 01940 static struct tm *getGMTTime(const time_t *clock, struct tm *result); 01941 static struct tm *gmtime(const time_t *clock, struct tm *result) 01942 { return getGMTTime(clock, result);}; 01943 }; 01944 01945 #ifndef HAVE_LOCALTIME_R 01946 01947 inline struct tm *localtime_r(const time_t *t, struct tm *b) 01948 {return SysTime::getLocalTime(t, b);}; 01949 inline char *ctime_r(const time_t *t, char *buf) 01950 {return ctime(t);}; 01951 inline struct tm *gmtime_r(const time_t *t, struct tm *b) \ 01952 {return SysTime::getGMTTime(t, b);}; 01953 inline char *asctime_r(const struct tm *tm, char *b) \ 01954 {return asctime(tm);}; 01955 01956 #endif 01957 01958 #ifdef CCXX_NAMESPACES 01959 } 01960 #endif 01961 01962 #endif 01963