GNU CommonC++

thread.h

Go to the documentation of this file.
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