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         {
01093                 cancelInitial=0,  
01094                 cancelDeferred=1, 
01095                 cancelImmediate,  
01096                 cancelDisabled,   
01097                 cancelManual,     
01099                 cancelDefault=cancelDeferred
01101         } Cancel;
01102 
01106         typedef enum Suspend
01107         {
01108                 suspendEnable, 
01109                 suspendDisable 
01110         } Suspend;
01111 
01112 #ifndef WIN32
01113 
01114 friend class PosixThread;
01115 #endif
01116 
01117 friend class DummyThread;
01118 private:
01119         friend class Cancellation;
01120         friend class postream_type;
01121         friend class Slog;
01122 
01123         Semaphore joinSem;
01124         static Thread* _main;
01125 
01126         Thread *_parent;
01127         Cancel _cancel;
01128         Semaphore *_start;
01129 
01130         // private data
01131         friend class ThreadImpl;
01132         class ThreadImpl* priv;
01133 
01134 public:
01135         static Thread *get(void);
01136 
01137 private:
01138 #ifdef  WIN32
01139         static unsigned __stdcall Execute(Thread *th);
01140 #endif
01141 
01142         // close current thread, free all and call Notify
01143         void close();
01144 
01145 private:
01146         char _name[32];
01147         static size_t _autostack;
01148 
01149 #ifdef WIN32
01150         DWORD waitHandle(HANDLE obj, timeout_t timeout);
01151 #endif
01152 
01153 protected:
01161         void setName(const char *text);
01162 
01172         virtual void run(void) = 0;
01173 
01195         virtual void final(void);
01196 
01208         virtual void initial(void);
01209 
01219         virtual void* getExtended(void);
01220 
01228         virtual void notify(Thread*);
01229 
01235         void exit(void);
01236 
01240         void sync(void);
01241 
01245         bool testCancel(void);
01246 
01256         void setCancel(Cancel mode);
01257 
01265         void setSuspend(Suspend mode);
01266 
01275         void terminate(void);
01276 
01280         inline void clrParent(void)
01281                 {_parent = NULL;};
01282 
01283 public:
01292         Thread(bool isMain);
01293 
01305         Thread(int pri = 0, size_t stack = 0);
01306 
01307 #ifndef WIN32
01308 
01316         Thread(const Thread &th);
01317 #endif
01318 
01325         virtual ~Thread();
01326 
01332         static void setStack(size_t size = 0)
01333                 {_autostack = size;};
01334 
01344         static void sleep(timeout_t msec);
01345 
01350         static void yield(void);
01351 
01364         int start(Semaphore *start = 0);
01365 
01374         int detach(Semaphore *start = 0);
01375 
01382         inline Thread *getParent(void)
01383                 {return _parent;};
01384 
01391         void suspend(void);
01392 
01396         void resume(void);
01397 
01404         inline Cancel getCancel(void)
01405                 {return _cancel;};
01406 
01413         bool isRunning(void);
01414 
01420         bool isDetached(void);
01421 
01425         void join(void);
01426 
01433         bool isThread(void);
01434 
01440         cctid_t getId(void) const;
01441 
01448         const char *getName(void)
01449                 {return _name;};
01450 
01456         static Throw getException(void);
01457 
01463         static void setException(Throw mode);
01464 
01471         friend inline void operator++(Thread &th)
01472                 {if (th._start) th._start->post();};
01473 
01474         friend inline void operator--(Thread &th)
01475                 {if (th._start) th._start->wait();};
01476 
01477 #ifdef WIN32
01478         bool isCancelled();
01479 
01480         static DWORD waitThread(HANDLE hRef, timeout_t timeout);
01481 #endif
01482 
01490         static Cancel enterCancel(void);
01491 
01497         static void exitCancel(Cancel cancel);
01498 };
01499 
01509 class __EXPORT Cancellation
01510 {
01511 private:
01512         Thread::Cancel prior;
01513 
01514 public:
01515         Cancellation(Thread::Cancel cancel);
01516         ~Cancellation();
01517 };
01518 
01519 #if !defined(WIN32) && !defined(__MINGW32__)
01520 typedef int             signo_t;
01521 
01522 class PosixThread: public Thread
01523 {
01524 private:
01525 #ifndef WIN32
01526 
01527         friend class ThreadImpl;
01528         friend class Thread;
01529 #endif
01530 #ifndef CCXX_SIG_THREAD_ALARM
01531         static PosixThread *_timer;
01532         static Mutex _arm;
01533 #endif
01534         
01535         time_t  _alarm;
01536         static void signalThread(Thread* th,signo_t signo);
01537 protected:
01538                 
01545         inline void signalParent(signo_t signo)
01546                 { signalThread(_parent,signo); };
01547         
01554         inline void signalMain(signo_t signo)
01555                 { signalThread(_main,signo);};
01556 
01561         virtual void onTimer(void);
01562 
01567         virtual void onHangup(void);
01568 
01573         virtual void onException(void);
01574 
01579         virtual void onDisconnect(void);
01580 
01585         virtual void onPolling(void);
01586 
01593         virtual void onSignal(int);
01594         
01607         void setTimer(timeout_t timer, bool periodic = false);
01608         
01615         timeout_t getTimer(void) const;
01616         
01622         void endTimer(void);
01623 
01624 #if defined(HAVE_SIGWAIT) || defined(HAVE_SIGWAIT2)     
01625 
01631         void waitSignal(signo_t signo);
01632 #endif
01633         
01640         void setSignal(int signo, bool active);
01641 
01648         pthread_attr_t *getPthreadAttrPtr(void);
01649 
01654         pthread_t getPthreadId(void);
01655 
01656 public:
01657 
01658         PosixThread(int pri = 0, size_t stack = 0);
01659         
01665         inline void signalThread(int signo)
01666                 {signalThread(this, signo);};
01667 
01674         static void sigInstall(int signo);
01675 };
01676 #endif
01677 
01692 class __EXPORT ThreadKey
01693 {
01694 private:
01695 #ifndef WIN32
01696         pthread_key_t key;
01697         typedef void (*TDestruct)(void*);
01698         friend class ThreadImpl;
01699         ThreadKey(TDestruct destruct);
01700 #else
01701         DWORD   key;
01702 #endif
01703 
01704 public:
01708         ThreadKey();
01709 
01713         virtual ~ThreadKey();
01714 
01722         void *getKey(void);
01723 
01731         void setKey(void *);
01732 };
01733 
01744 class __EXPORT TimerPort
01745 {
01746 #ifndef WIN32
01747         struct timeval timer;
01748 #else
01749         DWORD timer;
01750 #endif
01751         bool active;
01752 
01753 public:
01760         TimerPort();
01761 
01770         void setTimer(timeout_t timeout = 0);
01771 
01781         void incTimer(timeout_t timeout);
01782 
01788         void endTimer(void);
01789 
01801         timeout_t getTimer(void) const;
01802 
01812         timeout_t getElapsed(void) const;
01813 };
01814 
01815 
01816 
01817 // FIXME: not in win32 implementation
01818 #if !defined(WIN32)
01819 
01820 // FIXME: private declaration ???
01821 struct  timespec *getTimeout(struct timespec *spec, timeout_t timeout); 
01822 
01823 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
01824 void    wait(signo_t signo);
01825 #endif
01826 
01827 #endif // !WIN32
01828 
01829 #ifdef USE_POLL
01830 
01838 class Poller 
01839 {
01840 private:
01841         int nufds;
01842         pollfd *ufds;
01843 
01844 public:
01845         Poller();
01846 
01847         virtual ~Poller();
01848 
01856         pollfd *getList(int cnt);
01857 
01863         inline  pollfd *getList(void)
01864                 {return ufds;};
01865 };
01866 #endif
01867 
01868 inline Thread *getThread(void)
01869         {return Thread::get();}
01870 
01900 class __EXPORT SysTime
01901 {
01902 private:
01903                 static Mutex timeLock;
01904 
01905 protected:
01906                 inline static void lock(void)
01907                         {timeLock.enterMutex();}
01908 
01909                 inline static void unlock(void)
01910                         {timeLock.leaveMutex();}
01911 
01912 public:
01913         static time_t getTime(time_t *tloc = NULL);
01914         static time_t time(time_t *tloc) 
01915                         { return getTime(tloc); };
01916 
01917         static int getTimeOfDay(struct timeval *tp);
01918         static int gettimeofday(struct timeval *tp, struct timezone *)
01919                         { return getTimeOfDay(tp); };
01920         
01921         static struct tm *getLocalTime(const time_t *clock, struct tm *result);
01922         static struct tm *locatime(const time_t *clock, struct tm *result)
01923                         { return getLocalTime(clock, result); };
01924 
01925                 static struct tm *getGMTTime(const time_t *clock, struct tm *result);
01926                 static struct tm *gmtime(const time_t *clock, struct tm *result)
01927                         { return getGMTTime(clock, result);};
01928 }; 
01929 
01930 #ifndef HAVE_LOCALTIME_R
01931 
01932 inline struct tm *localtime_r(const time_t *t, struct tm *b)
01933         {return SysTime::getLocalTime(t, b);};
01934 inline char *ctime_r(const time_t *t, char *buf)
01935         {return ctime(t);};
01936 inline struct tm *gmtime_r(const time_t *t, struct tm *b) \
01937 {return SysTime::getGMTTime(t, b);};
01938 inline char *asctime_r(const struct tm *tm, char *b) \
01939         {return asctime(tm);};
01940 
01941 #endif 
01942         
01943 #ifdef  CCXX_NAMESPACES
01944 }
01945 #endif
01946 
01947 #endif
01948 

Generated on Thu Nov 9 19:30:51 2006 for GNU CommonC++ by  doxygen 1.5.1