GNU CommonC++
|
00001 // Copyright (C) 1999-2005 Open Source Telecom Corporation. 00002 // Copyright (C) 2006-2010 David Sugar, Tycho Softworks. 00003 // 00004 // This program is free software; you can redistribute it and/or modify 00005 // it under the terms of the GNU General Public License as published by 00006 // the Free Software Foundation; either version 2 of the License, or 00007 // (at your option) any later version. 00008 // 00009 // This program is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with this program; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 // 00018 // As a special exception, you may use this file as part of a free software 00019 // library without restriction. Specifically, if other files instantiate 00020 // templates or use macros or inline functions from this file, or you compile 00021 // this file and link it with other files to produce an executable, this 00022 // file does not by itself cause the resulting executable to be covered by 00023 // the GNU General Public License. This exception does not however 00024 // invalidate any other reasons why the executable file might be covered by 00025 // the GNU General Public License. 00026 // 00027 // This exception applies only to the code released under the name GNU 00028 // Common C++. If you copy code from other releases into a copy of GNU 00029 // Common C++, as the General Public License permits, the exception does 00030 // not apply to the code that you add in this way. To avoid misleading 00031 // anyone as to the status of such modified files, you must delete 00032 // this exception notice from them. 00033 // 00034 // If you write modifications of your own for GNU Common C++, it is your choice 00035 // whether to permit this exception to apply to your modifications. 00036 // If you do not wish that, delete this exception notice. 00037 // 00038 00044 #ifndef CCXX_THREAD_H_ 00045 #define CCXX_THREAD_H_ 00046 00047 #include <cc++/config.h> 00048 00049 #ifndef CCXX_STRING_H_ 00050 #include <cc++/string.h> 00051 #endif 00052 00053 #ifndef WIN32 00054 #define CCXX_POSIX 00055 #endif // !WIN32 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 HAVE_GCC_CXX_BITS_ATOMIC 00095 #include <ios> 00096 #endif 00097 00098 #ifdef CCXX_NAMESPACES 00099 namespace ost { 00100 #ifdef __BORLANDC__ 00101 # if __BORLANDC__ >= 0x0560 00102 using std::time_t; 00103 using std::tm; 00104 # endif 00105 #endif 00106 #endif 00107 00108 #ifdef HAVE_GCC_CXX_BITS_ATOMIC 00109 using namespace __gnu_cxx; 00110 #endif 00111 00112 class __EXPORT Thread; 00113 class __EXPORT ThreadKey; 00114 00115 #define TIMEOUT_INF ~((timeout_t) 0) 00116 00117 #define ENTER_CRITICAL enterMutex(); 00118 #define LEAVE_CRITICAL leaveMutex(); 00119 #define ENTER_DEFERRED setCancel(cancelDeferred); 00120 #define LEAVE_DEFERRED setCancel(cancelImmediate); 00121 00122 #ifndef WIN32 00123 // These macros override common functions with thread-safe versions. In 00124 // particular the common "libc" sleep() has problems since it normally 00125 // uses SIGARLM (as actually defined by "posix"). The pthread_delay and 00126 // usleep found in libpthread are gaurenteed not to use SIGALRM and offer 00127 // higher resolution. psleep() is defined to call the old process sleep. 00128 00129 #undef sleep 00130 #define psleep(x) (sleep)(x) 00131 00132 #ifdef signal 00133 #undef signal 00134 #endif 00135 00136 #endif // !WIN32 00137 00138 #undef Yield 00139 00140 class __EXPORT Conditional; 00141 class __EXPORT Event; 00142 00186 class __EXPORT Mutex 00187 { 00188 private: 00189 static bool _debug; 00190 String _name; 00191 #ifndef WIN32 00192 #ifndef PTHREAD_MUTEXTYPE_RECURSIVE 00193 int volatile _level; 00194 Thread *volatile _tid; 00195 #endif 00196 /* 00197 * Pthread mutex object. This is protected rather than private 00198 * because some mixed mode pthread operations require a mutex as 00199 * well as their primary pthread object. A good example of this 00200 * is the Event class, as waiting on a conditional object must be 00201 * associated with an accessable mutex. An alternative would be 00202 * to make such classes "friend" classes of the Mutex. 00203 */ 00204 pthread_mutex_t _mutex; 00205 #else // WIN32 00206 00207 # if defined(MUTEX_UNDERGROUND_WIN32_MUTEX) && defined(MUTEX_UNDERGROUND_WIN32_CRITICALSECTION) 00208 # error "Can't determine underground for Mutex" 00209 # endif 00210 00211 #ifdef MUTEX_UNDERGROUND_WIN32_MUTEX 00212 HANDLE _mutex; 00213 #endif 00214 #ifdef MUTEX_UNDERGROUND_WIN32_CRITICALSECTION 00215 CRITICAL_SECTION _criticalSection; 00216 #endif 00217 00218 #endif // WIN32 00219 00220 public: 00226 Mutex(const char *name = NULL); 00227 00233 virtual ~Mutex(); 00234 00240 static void setDebug(bool mode) 00241 {_debug = mode;}; 00242 00248 inline void nameMutex(const char *name) 00249 {_name = name;}; 00250 00258 void enterMutex(void); 00259 00263 inline void enter(void) 00264 {enterMutex();}; 00265 00269 inline void leave(void) 00270 {leaveMutex();}; 00271 00277 inline bool test(void) 00278 {return tryEnterMutex();}; 00279 00290 bool tryEnterMutex(void); 00291 00302 void leaveMutex(void); 00303 }; 00304 00328 class __EXPORT MutexLock 00329 { 00330 private: 00331 Mutex& mutex; 00332 public: 00338 MutexLock( Mutex& _mutex ) : mutex( _mutex ) 00339 { mutex.enterMutex(); } 00340 00344 // this should be not-virtual 00345 ~MutexLock() 00346 { mutex.leaveMutex(); } 00347 }; 00348 00357 class __EXPORT ThreadLock 00358 { 00359 private: 00360 #ifdef HAVE_PTHREAD_RWLOCK 00361 pthread_rwlock_t _lock; 00362 #else 00363 Mutex mutex; 00364 #endif 00365 00366 public: 00370 ThreadLock(); 00371 00375 virtual ~ThreadLock(); 00376 00380 void readLock(void); 00381 00385 void writeLock(void); 00386 00392 bool tryReadLock(void); 00393 00399 bool tryWriteLock(void); 00400 00404 void unlock(void); 00405 }; 00406 00427 class __EXPORT ReadLock 00428 { 00429 private: 00430 ThreadLock& tl; 00431 00432 public: 00438 ReadLock( ThreadLock& _tl ) : tl( _tl ) 00439 { tl.readLock(); } 00443 // this should be not-virtual 00444 ~ReadLock() 00445 { tl.unlock(); } 00446 }; 00447 00468 class __EXPORT WriteLock 00469 { 00470 private: 00471 ThreadLock& tl; 00472 00473 public: 00479 WriteLock( ThreadLock& _tl ) : tl( _tl ) 00480 { tl.writeLock(); } 00484 // this should be not-virtual 00485 ~WriteLock() 00486 { tl.unlock(); } 00487 }; 00488 00489 00499 class __EXPORT MutexCounter : public Mutex 00500 { 00501 private: 00502 volatile int counter; 00503 00504 public: 00510 MutexCounter(const char *id = NULL); 00511 00519 MutexCounter(int initial, const char *id = NULL); 00520 00521 friend __EXPORT int operator++(MutexCounter &mc); 00522 friend __EXPORT int operator--(MutexCounter &mc); 00523 }; 00524 00535 class __EXPORT AtomicCounter 00536 { 00537 #ifndef CCXX_USE_WIN32_ATOMIC 00538 private: 00539 #if defined(HAVE_ATOMIC_AIX) 00540 volatile int counter; 00541 #elif defined(HAVE_GCC_BITS_ATOMIC) 00542 volatile _Atomic_word counter; 00543 #elif defined(HAVE_GCC_CXX_BITS_ATOMIC) 00544 volatile _Atomic_word counter; 00545 // __gnu_cxx::_Atomic_word counter; 00546 #elif defined(HAVE_ATOMIC) 00547 atomic_t atomic; 00548 #else 00549 volatile int counter; 00550 pthread_mutex_t _mutex; 00551 #endif 00552 00553 public: 00557 AtomicCounter(); 00558 00564 AtomicCounter(int value); 00565 00566 ~AtomicCounter(); 00567 00568 int operator++(void); 00569 int operator--(void); 00570 int operator+=(int change); 00571 int operator-=(int change); 00572 int operator+(int change); 00573 int operator-(int change); 00574 int operator=(int value); 00575 bool operator!(void); 00576 operator int(); 00577 #else 00578 private: 00579 long atomic; 00580 00581 public: 00582 inline AtomicCounter() 00583 {atomic = 0;}; 00584 00585 inline AtomicCounter(int value) 00586 {atomic = value;}; 00587 00588 inline int operator++(void) 00589 {return InterlockedIncrement(&atomic);}; 00590 00591 inline int operator--(void) 00592 {return InterlockedDecrement(&atomic);}; 00593 00594 int operator+=(int change); 00595 00596 int operator-=(int change); 00597 00598 inline int operator+(int change) 00599 {return atomic + change;}; 00600 00601 inline int operator-(int change) 00602 {return atomic - change;}; 00603 00604 inline int operator=(int value) 00605 {return InterlockedExchange(&atomic, value);}; 00606 00607 inline bool operator!(void) 00608 {return (atomic == 0) ? true : false;}; 00609 00610 inline operator int() 00611 {return atomic;}; 00612 #endif 00613 }; 00614 00615 #ifndef WIN32 00616 00636 class __EXPORT Conditional 00637 { 00638 private: 00639 pthread_cond_t _cond; 00640 pthread_mutex_t _mutex; 00641 00642 public: 00648 Conditional(const char *id = NULL); 00649 00653 virtual ~Conditional(); 00654 00660 void signal(bool broadcast); 00661 00668 bool wait(timeout_t timer = 0, bool locked = false); 00669 00676 void enterMutex(void); 00677 00686 inline void lock(void) 00687 {enterMutex();}; 00688 00699 bool tryEnterMutex(void); 00700 00701 inline bool test(void) 00702 {return tryEnterMutex();}; 00703 00709 void leaveMutex(void); 00710 00711 inline void unlock(void) 00712 {return leaveMutex();}; 00713 }; 00714 #endif 00715 00733 class __EXPORT Semaphore 00734 { 00735 private: 00736 #ifndef WIN32 00737 unsigned _count, _waiters; 00738 pthread_mutex_t _mutex; 00739 pthread_cond_t _cond; 00740 #else 00741 HANDLE semObject; 00742 #endif // !WIN32 00743 00744 public: 00753 Semaphore(unsigned resource = 0); 00754 00761 virtual ~Semaphore(); 00762 00778 bool wait(timeout_t timeout = 0); 00779 00791 void post(void); 00792 00793 #ifndef WIN32 00794 00802 void force_unlock_after_cancellation(); 00803 00804 #endif // WIN32 00805 00806 // FIXME: how implement getValue for posix compatibility ? 00807 // not portable... 00808 #if 0 00809 00814 int getValue(void); 00815 #endif 00816 }; 00817 00837 class __EXPORT SemaphoreLock 00838 { 00839 private: 00840 Semaphore& sem; 00841 00842 public: 00846 SemaphoreLock( Semaphore& _sem ) : sem( _sem ) 00847 { sem.wait(); } 00851 // this should be not-virtual 00852 ~SemaphoreLock() 00853 { sem.post(); } 00854 }; 00855 00869 class __EXPORT Event 00870 { 00871 private: 00872 #ifndef WIN32 00873 pthread_mutex_t _mutex; 00874 pthread_cond_t _cond; 00875 bool _signaled; 00876 int _count; 00877 #else 00878 HANDLE cond; 00879 #endif 00880 00881 public: 00882 Event(); 00883 00884 virtual ~Event(); 00885 00892 void reset(void); 00893 00897 void signal(void); 00898 00907 bool wait(timeout_t timer); 00908 bool wait(void); 00909 }; 00910 00911 01093 class __EXPORT Thread 01094 { 01095 public: 01099 typedef enum Throw { 01100 throwNothing, 01101 throwObject, 01102 throwException 01103 } Throw; 01104 01108 typedef enum Cancel { 01109 cancelInitial=0, 01110 cancelDeferred=1, 01111 cancelImmediate, 01112 cancelDisabled, 01113 cancelManual, 01115 cancelDefault=cancelDeferred 01117 } Cancel; 01118 01122 typedef enum Suspend { 01123 suspendEnable, 01124 suspendDisable 01125 } Suspend; 01126 01127 #ifndef WIN32 01128 01129 friend class PosixThread; 01130 #endif 01131 01132 friend class DummyThread; 01133 private: 01134 friend class Cancellation; 01135 friend class postream_type; 01136 friend class Slog; 01137 01138 Semaphore joinSem; 01139 static Thread* _main; 01140 01141 Thread *_parent; 01142 Cancel _cancel; 01143 Semaphore *_start; 01144 01145 // private data 01146 friend class ThreadImpl; 01147 class ThreadImpl* priv; 01148 01149 public: 01150 static Thread *get(void); 01151 01152 private: 01153 #ifdef WIN32 01154 static unsigned __stdcall Execute(Thread *th); 01155 #endif 01156 01157 // close current thread, free all and call Notify 01158 void close(); 01159 01160 private: 01161 char _name[32]; 01162 static size_t _autostack; 01163 01164 #ifdef WIN32 01165 DWORD waitHandle(HANDLE obj, timeout_t timeout); 01166 #endif 01167 01168 protected: 01176 void setName(const char *text); 01177 01187 virtual void run(void) = 0; 01188 01210 virtual void final(void); 01211 01223 virtual void initial(void); 01224 01234 virtual void* getExtended(void); 01235 01243 virtual void notify(Thread*); 01244 01250 void exit(void); 01251 01255 void sync(void); 01256 01260 bool testCancel(void); 01261 01271 void setCancel(Cancel mode); 01272 01280 void setSuspend(Suspend mode); 01281 01290 void terminate(void); 01291 01295 inline void clrParent(void) 01296 {_parent = NULL;}; 01297 01298 public: 01307 Thread(bool isMain); 01308 01320 Thread(int pri = 0, size_t stack = 0); 01321 01322 #ifndef WIN32 01323 01331 Thread(const Thread &th); 01332 #endif 01333 01340 virtual ~Thread(); 01341 01347 static void setStack(size_t size = 0) 01348 {_autostack = size;}; 01349 01359 static void sleep(timeout_t msec); 01360 01365 static void yield(void); 01366 01379 int start(Semaphore *start = 0); 01380 01389 int detach(Semaphore *start = 0); 01390 01397 inline Thread *getParent(void) 01398 {return _parent;}; 01399 01406 void suspend(void); 01407 01411 void resume(void); 01412 01419 inline Cancel getCancel(void) 01420 {return _cancel;}; 01421 01428 bool isRunning(void) const; 01429 01435 bool isDetached(void) const; 01436 01440 void join(void); 01441 01448 bool isThread(void) const; 01449 01455 cctid_t getId(void) const; 01456 01463 const char *getName(void) const 01464 {return _name;}; 01465 01471 static Throw getException(void); 01472 01478 static void setException(Throw mode); 01479 01486 friend inline void operator++(Thread &th) 01487 {if (th._start) th._start->post();}; 01488 01489 friend inline void operator--(Thread &th) 01490 {if (th._start) th._start->wait();}; 01491 01492 #ifdef WIN32 01493 bool isCancelled() const; 01494 01495 static DWORD waitThread(HANDLE hRef, timeout_t timeout); 01496 #endif 01497 01505 static Cancel enterCancel(void); 01506 01512 static void exitCancel(Cancel cancel); 01513 }; 01514 01524 class __EXPORT Cancellation 01525 { 01526 private: 01527 Thread::Cancel prior; 01528 01529 public: 01530 Cancellation(Thread::Cancel cancel); 01531 ~Cancellation(); 01532 }; 01533 01534 #if !defined(WIN32) && !defined(__MINGW32__) 01535 typedef int signo_t; 01536 01537 class PosixThread: public Thread 01538 { 01539 private: 01540 #ifndef WIN32 01541 01542 friend class ThreadImpl; 01543 friend class Thread; 01544 #endif 01545 #ifndef CCXX_SIG_THREAD_ALARM 01546 static PosixThread *_timer; 01547 static Mutex _arm; 01548 #endif 01549 01550 time_t _alarm; 01551 static void signalThread(Thread* th,signo_t signo); 01552 protected: 01553 01560 inline void signalParent(signo_t signo) 01561 { signalThread(_parent,signo); }; 01562 01569 inline void signalMain(signo_t signo) 01570 { signalThread(_main,signo);}; 01571 01576 virtual void onTimer(void); 01577 01582 virtual void onHangup(void); 01583 01588 virtual void onException(void); 01589 01594 virtual void onDisconnect(void); 01595 01600 virtual void onPolling(void); 01601 01608 virtual void onSignal(int); 01609 01622 void setTimer(timeout_t timer, bool periodic = false); 01623 01630 timeout_t getTimer(void) const; 01631 01637 void endTimer(void); 01638 01639 #if defined(HAVE_SIGWAIT) || defined(HAVE_SIGWAIT2) 01640 01646 void waitSignal(signo_t signo); 01647 #endif 01648 01655 void setSignal(int signo, bool active); 01656 01663 pthread_attr_t *getPthreadAttrPtr(void); 01664 01669 pthread_t getPthreadId(void); 01670 01671 public: 01672 01673 PosixThread(int pri = 0, size_t stack = 0); 01674 01680 inline void signalThread(int signo) 01681 {signalThread(this, signo);}; 01682 01689 static void sigInstall(int signo); 01690 }; 01691 #endif 01692 01707 class __EXPORT ThreadKey 01708 { 01709 private: 01710 #ifndef WIN32 01711 pthread_key_t key; 01712 typedef void (*TDestruct)(void*); 01713 friend class ThreadImpl; 01714 ThreadKey(TDestruct destruct); 01715 #else 01716 DWORD key; 01717 #endif 01718 01719 public: 01723 ThreadKey(); 01724 01728 virtual ~ThreadKey(); 01729 01737 void *getKey(void); 01738 01746 void setKey(void *); 01747 }; 01748 01759 class __EXPORT TimerPort 01760 { 01761 #ifndef WIN32 01762 struct timeval timer; 01763 #else 01764 DWORD timer; 01765 #endif 01766 bool active; 01767 01768 public: 01775 TimerPort(); 01776 01785 void setTimer(timeout_t timeout = 0); 01786 01796 void incTimer(timeout_t timeout); 01797 01807 void decTimer(timeout_t timeout); 01808 01813 void sleepTimer(void); 01814 01820 void endTimer(void); 01821 01833 timeout_t getTimer(void) const; 01834 01844 timeout_t getElapsed(void) const; 01845 }; 01846 01847 01848 01849 // FIXME: not in win32 implementation 01850 #if !defined(WIN32) 01851 01852 // FIXME: private declaration ??? 01853 struct timespec *getTimeout(struct timespec *spec, timeout_t timeout); 01854 01855 #if !defined(__CYGWIN32__) && !defined(__MINGW32__) 01856 void wait(signo_t signo); 01857 #endif 01858 01859 #endif // !WIN32 01860 01861 #ifdef USE_POLL 01862 01870 class Poller 01871 { 01872 private: 01873 int nufds; 01874 pollfd *ufds; 01875 01876 public: 01877 Poller(); 01878 01879 virtual ~Poller(); 01880 01888 pollfd *getList(int cnt); 01889 01895 inline pollfd *getList(void) 01896 {return ufds;}; 01897 }; 01898 #endif 01899 01900 inline Thread *getThread(void) 01901 {return Thread::get();} 01902 01932 class __EXPORT SysTime 01933 { 01934 private: 01935 static Mutex timeLock; 01936 01937 protected: 01938 inline static void lock(void) 01939 {timeLock.enterMutex();} 01940 01941 inline static void unlock(void) 01942 {timeLock.leaveMutex();} 01943 01944 public: 01945 static time_t getTime(time_t *tloc = NULL); 01946 static time_t time(time_t *tloc) 01947 { return getTime(tloc); }; 01948 01949 static int getTimeOfDay(struct timeval *tp); 01950 static int gettimeofday(struct timeval *tp, struct timezone *) 01951 { return getTimeOfDay(tp); }; 01952 01953 static struct tm *getLocalTime(const time_t *clock, struct tm *result); 01954 static struct tm *locatime(const time_t *clock, struct tm *result) 01955 { return getLocalTime(clock, result); }; 01956 01957 static struct tm *getGMTTime(const time_t *clock, struct tm *result); 01958 static struct tm *gmtime(const time_t *clock, struct tm *result) 01959 { return getGMTTime(clock, result);}; 01960 }; 01961 01962 #ifndef HAVE_LOCALTIME_R 01963 01964 inline struct tm *localtime_r(const time_t *t, struct tm *b) 01965 {return SysTime::getLocalTime(t, b);}; 01966 inline char *ctime_r(const time_t *t, char *buf) 01967 {return ctime(t);}; 01968 inline struct tm *gmtime_r(const time_t *t, struct tm *b) \ 01969 {return SysTime::getGMTTime(t, b);}; 01970 inline char *asctime_r(const struct tm *tm, char *b) \ 01971 {return asctime(tm);}; 01972 01973 #endif 01974 01975 #ifdef CCXX_NAMESPACES 01976 } 01977 #endif 01978 01979 #endif 01980