thread.h

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

Generated on Fri Jun 13 09:40:53 2008 for GNU CommonC++ by  doxygen 1.5.3