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:
00219         Mutex(const char *name = NULL);
00220 
00226         virtual ~Mutex();
00227 
00233         static void setDebug(bool mode)
00234                 {_debug = mode;};
00235 
00241         inline void nameMutex(const char *cp)
00242                 {_name = cp;};
00243 
00251         void enterMutex(void);
00252 
00256         inline void enter(void)
00257                 {enterMutex();};
00258 
00259         inline void leave(void)
00260                 {leaveMutex();};
00261 
00262         inline bool test(void)
00263                 {return tryEnterMutex();};
00264 
00275         bool tryEnterMutex(void);
00276 
00287         void leaveMutex(void);
00288 };
00289 
00313 class __EXPORT MutexLock
00314 {
00315 private:
00316         Mutex& mutex;
00317 public:
00321         MutexLock( Mutex& _mutex ) : mutex( _mutex ) 
00322                 { mutex.enterMutex(); }
00326         // this should be not-virtual
00327         ~MutexLock()
00328                 { mutex.leaveMutex(); }
00329 };
00330 
00339 class __EXPORT ThreadLock
00340 {
00341 private:
00342 #ifdef HAVE_PTHREAD_RWLOCK
00343         pthread_rwlock_t _lock;
00344 #else
00345         Mutex mutex;
00346 #endif
00347 
00348 public:
00352         ThreadLock();
00353 
00357         virtual ~ThreadLock();
00358 
00362         void readLock(void);
00363 
00367         void writeLock(void);
00368 
00374         bool tryReadLock(void);
00375 
00381         bool tryWriteLock(void);
00382 
00386         void unlock(void);
00387 };
00388 
00409 class __EXPORT ReadLock
00410 {
00411 private:
00412         ThreadLock& tl;
00413 
00414 public:
00418         ReadLock( ThreadLock& _tl ) : tl( _tl ) 
00419                 { tl.readLock(); }
00423         // this should be not-virtual
00424         ~ReadLock()
00425                 { tl.unlock(); }
00426 };
00427 
00448 class __EXPORT WriteLock
00449 {
00450 private:
00451         ThreadLock& tl;
00452 
00453 public:
00457         WriteLock( ThreadLock& _tl ) : tl( _tl ) 
00458                 { tl.writeLock(); }
00462         // this should be not-virtual
00463         ~WriteLock()
00464                 { tl.unlock(); }
00465 };
00466 
00467 
00477 class __EXPORT MutexCounter : public Mutex
00478 {
00479 private:
00480         volatile int    counter;
00481 
00482 public:
00483         MutexCounter(const char *id = NULL);
00484         MutexCounter(int initial, const char *id = NULL);
00485 
00486         friend __EXPORT int operator++(MutexCounter &mc);
00487         friend __EXPORT int operator--(MutexCounter &mc);
00488 };
00489 
00500 class __EXPORT AtomicCounter
00501 {
00502 #ifndef CCXX_USE_WIN32_ATOMIC
00503 private:
00504 #if     defined(HAVE_ATOMIC_AIX)
00505         volatile int counter;
00506 #elif   defined(HAVE_GCC_BITS_ATOMIC)
00507         volatile _Atomic_word counter;
00508 #elif   defined(HAVE_GCC_CXX_BITS_ATOMIC)
00509         volatile _Atomic_word counter;
00510 //      __gnu_cxx::_Atomic_word counter;
00511 #elif   defined(HAVE_ATOMIC)
00512         atomic_t atomic;
00513 #else
00514         volatile int counter;
00515         pthread_mutex_t _mutex;
00516 #endif
00517 
00518 public:
00522         AtomicCounter();
00523 
00529         AtomicCounter(int value);
00530 
00531         ~AtomicCounter();
00532 
00533         int operator++(void);
00534         int operator--(void);
00535         int operator+=(int change);
00536         int operator-=(int change);
00537         int operator+(int change);
00538         int operator-(int change);
00539         int operator=(int value);
00540         bool operator!(void);
00541         operator int();
00542 #else
00543 private:
00544         long atomic;
00545 
00546 public:
00547         inline AtomicCounter()
00548                 {atomic = 0;};
00549 
00550         inline AtomicCounter(int value)
00551                 {atomic = value;};
00552 
00553         inline int operator++(void)
00554                 {return InterlockedIncrement(&atomic);};
00555 
00556         inline int operator--(void)
00557                 {return InterlockedDecrement(&atomic);};
00558 
00559         int operator+=(int change);
00560 
00561         int operator-=(int change);
00562 
00563         inline int operator+(int change)
00564                 {return atomic + change;};
00565 
00566         inline int operator-(int change)
00567                 {return atomic - change;};
00568         
00569         inline int operator=(int value)
00570                 {return InterlockedExchange(&atomic, value);};
00571 
00572         inline bool operator!(void)
00573                 {return (atomic == 0) ? true : false;};
00574 
00575         inline operator int()
00576                 {return atomic;};
00577 #endif
00578 };
00579 
00580 #ifndef WIN32
00581 
00601 class __EXPORT Conditional 
00602 {
00603 private:
00604         pthread_cond_t _cond;
00605         pthread_mutex_t _mutex;
00606 
00607 public:
00611         Conditional(const char *id = NULL);
00612 
00616         virtual ~Conditional();
00617 
00623         void signal(bool broadcast);
00624 
00631         bool wait(timeout_t timer = 0, bool locked = false);
00632 
00639         void enterMutex(void);
00640 
00649         inline void lock(void)
00650                 {enterMutex();};
00651 
00662         bool tryEnterMutex(void);
00663 
00664         inline bool test(void)
00665                 {return tryEnterMutex();};
00666 
00672         void leaveMutex(void);
00673 
00674         inline void unlock(void)
00675                 {return leaveMutex();};
00676 };
00677 #endif
00678 
00696 class __EXPORT Semaphore
00697 {
00698 private:
00699 #ifndef WIN32
00700         unsigned _count, _waiters;
00701         pthread_mutex_t _mutex;
00702         pthread_cond_t _cond;
00703 #else
00704         HANDLE  semObject;
00705 #endif // !WIN32
00706 
00707 public:
00716         Semaphore(unsigned resource = 0);
00717 
00724         virtual ~Semaphore();
00725 
00741         bool wait(timeout_t timeout = 0);
00742 
00754         void post(void);
00755 
00756         // FIXME: how implement getValue for posix compatibility ?
00757         // not portable...
00758 
00759 #if     0
00760 
00765         int getValue(void);
00766 #endif
00767 };
00768 
00788 class __EXPORT SemaphoreLock
00789 {
00790 private:
00791         Semaphore& sem;
00792 
00793 public:
00797         SemaphoreLock( Semaphore& _sem ) : sem( _sem ) 
00798                 { sem.wait(); }
00802         // this should be not-virtual
00803         ~SemaphoreLock()
00804                 { sem.post(); }
00805 };
00806 
00820 class __EXPORT Event
00821 {
00822 private:
00823 #ifndef WIN32
00824         pthread_mutex_t _mutex;
00825         pthread_cond_t _cond;
00826         bool _signaled;
00827         int _count;
00828 #else
00829         HANDLE cond;
00830 #endif
00831 
00832 public:
00833         Event();
00834 
00835         virtual ~Event();
00836 
00843         void reset(void);
00844 
00848         void signal(void);
00849 
00858         bool wait(timeout_t timer);
00859         bool wait(void);
00860 };
00861 
00862 
01044 class __EXPORT Thread
01045 {
01046 public:
01050         typedef enum Throw {
01051                 throwNothing,  
01052                 throwObject,   
01053                 throwException 
01054         } Throw;
01055         
01059         typedef enum Cancel
01060         {
01061                 cancelInitial=0,  
01062                 cancelDeferred=1, 
01063                 cancelImmediate,  
01064                 cancelDisabled,   
01065                 cancelManual,     
01067                 cancelDefault=cancelDeferred
01069         } Cancel;
01070 
01074         typedef enum Suspend
01075         {
01076                 suspendEnable, 
01077                 suspendDisable 
01078         } Suspend;
01079 
01080 #ifndef WIN32
01081 
01082 friend class PosixThread;
01083 #endif
01084 
01085 friend class DummyThread;
01086 private:
01087         friend class Cancellation;
01088         friend class postream_type;
01089         friend class Slog;
01090 
01091         Semaphore joinSem;
01092         static Thread* _main;
01093 
01094         Thread *_parent;
01095         Cancel _cancel;
01096         Semaphore *_start;
01097 
01098         // private data
01099         friend class ThreadImpl;
01100         class ThreadImpl* priv;
01101 
01102 public:
01103         static Thread *get(void);
01104 
01105 private:
01106 #ifdef  WIN32
01107         static unsigned __stdcall Execute(Thread *th);
01108 #endif
01109 
01110         // close current thread, free all and call Notify
01111         void close();
01112 
01113 private:
01114         char _name[32];
01115         static size_t _autostack;
01116 
01117 #ifdef WIN32
01118         DWORD waitHandle(HANDLE obj, timeout_t timeout);
01119 #endif
01120 
01121 protected:
01129         void setName(const char *text);
01130 
01140         virtual void run(void) = 0;
01141 
01163         virtual void final(void);
01164 
01176         virtual void initial(void);
01177 
01187         virtual void* getExtended(void);
01188 
01196         virtual void notify(Thread*);
01197 
01203         void exit(void);
01204 
01208         void sync(void);
01209 
01213         bool testCancel(void);
01214 
01224         void setCancel(Cancel mode);
01225 
01233         void setSuspend(Suspend mode);
01234 
01243         void terminate(void);
01244 
01248         inline void clrParent(void)
01249                 {_parent = NULL;};
01250 
01251 public:
01260         Thread(bool isMain);
01261 
01273         Thread(int pri = 0, size_t stack = 0);
01274 
01275 #ifndef WIN32
01276 
01284         Thread(const Thread &th);
01285 #endif
01286 
01293         virtual ~Thread();
01294 
01300         static void setStack(size_t size = 0)
01301                 {_autostack = size;};
01302 
01312         static void sleep(timeout_t msec);
01313 
01318         static void yield(void);
01319 
01332         int start(Semaphore *start = 0);
01333 
01342         int detach(Semaphore *start = 0);
01343 
01350         inline Thread *getParent(void)
01351                 {return _parent;};
01352 
01359         void suspend(void);
01360 
01364         void resume(void);
01365 
01372         inline Cancel getCancel(void)
01373                 {return _cancel;};
01374 
01381         bool isRunning(void);
01382 
01388         bool isDetached(void);
01389 
01393         void join(void);
01394 
01401         bool isThread(void);
01402 
01408         cctid_t getId(void) const;
01409 
01416         const char *getName(void)
01417                 {return _name;};
01418 
01424         static Throw getException(void);
01425 
01431         static void setException(Throw mode);
01432 
01439         friend inline void operator++(Thread &th)
01440                 {if (th._start) th._start->post();};
01441 
01442         friend inline void operator--(Thread &th)
01443                 {if (th._start) th._start->wait();};
01444 
01445 #ifdef WIN32
01446         bool isCancelled();
01447 
01448         static DWORD waitThread(HANDLE hRef, timeout_t timeout);
01449 #endif
01450 
01458         static Cancel enterCancel(void);
01459 
01465         static void exitCancel(Cancel cancel);
01466 };
01467 
01477 class __EXPORT Cancellation
01478 {
01479 private:
01480         Thread::Cancel prior;
01481 
01482 public:
01483         Cancellation(Thread::Cancel cancel);
01484         ~Cancellation();
01485 };
01486 
01487 #if !defined(WIN32) && !defined(__MINGW32__)
01488 typedef int             signo_t;
01489 
01490 class PosixThread: public Thread
01491 {
01492 private:
01493 #ifndef WIN32
01494 
01495         friend class ThreadImpl;
01496         friend class Thread;
01497 #endif
01498 #ifndef CCXX_SIG_THREAD_ALARM
01499         static PosixThread *_timer;
01500         static Mutex _arm;
01501 #endif
01502         
01503         time_t  _alarm;
01504         static void signalThread(Thread* th,signo_t signo);
01505 protected:
01506                 
01513         inline void signalParent(signo_t signo)
01514                 { signalThread(_parent,signo); };
01515         
01522         inline void signalMain(signo_t signo)
01523                 { signalThread(_main,signo);};
01524 
01529         virtual void onTimer(void);
01530 
01535         virtual void onHangup(void);
01536 
01541         virtual void onException(void);
01542 
01547         virtual void onDisconnect(void);
01548 
01553         virtual void onPolling(void);
01554 
01561         virtual void onSignal(int);
01562         
01575         void setTimer(timeout_t timer, bool periodic = false);
01576         
01583         timeout_t getTimer(void) const;
01584         
01590         void endTimer(void);
01591 
01592 #if defined(HAVE_SIGWAIT) || defined(HAVE_SIGWAIT2)     
01593 
01599         void waitSignal(signo_t signo);
01600 #endif
01601         
01608         void setSignal(int signo, bool active);
01609 
01616         pthread_attr_t *getPthreadAttrPtr(void);
01617 
01622         pthread_t getPthreadId(void);
01623 
01624 public:
01625 
01626         PosixThread(int pri = 0, size_t stack = 0);
01627         
01633         inline void signalThread(int signo)
01634                 {signalThread(this, signo);};
01635 
01642         static void sigInstall(int signo);
01643 };
01644 #endif
01645 
01660 class __EXPORT ThreadKey
01661 {
01662 private:
01663 #ifndef WIN32
01664         pthread_key_t key;
01665         typedef void (*TDestruct)(void*);
01666         friend class ThreadImpl;
01667         ThreadKey(TDestruct destruct);
01668 #else
01669         DWORD   key;
01670 #endif
01671 
01672 public:
01676         ThreadKey();
01677 
01681         virtual ~ThreadKey();
01682 
01690         void *getKey(void);
01691 
01699         void setKey(void *);
01700 };
01701 
01712 class __EXPORT TimerPort
01713 {
01714 #ifndef WIN32
01715         struct timeval timer;
01716 #else
01717         DWORD timer;
01718 #endif
01719         bool active;
01720 
01721 public:
01728         TimerPort();
01729 
01738         void setTimer(timeout_t timeout = 0);
01739 
01749         void incTimer(timeout_t timeout);
01750 
01756         void endTimer(void);
01757 
01769         timeout_t getTimer(void) const;
01770 
01780         timeout_t getElapsed(void) const;
01781 };
01782 
01783 
01784 
01785 // FIXME: not in win32 implementation
01786 #if !defined(WIN32)
01787 
01788 // FIXME: private declaration ???
01789 struct  timespec *getTimeout(struct timespec *spec, timeout_t timeout); 
01790 
01791 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
01792 void    wait(signo_t signo);
01793 #endif
01794 
01795 #endif // !WIN32
01796 
01797 #ifdef USE_POLL
01798 
01806 class Poller 
01807 {
01808 private:
01809         int nufds;
01810         pollfd *ufds;
01811 
01812 public:
01813         Poller();
01814 
01815         virtual ~Poller();
01816 
01824         pollfd *getList(int cnt);
01825 
01831         inline  pollfd *getList(void)
01832                 {return ufds;};
01833 };
01834 #endif
01835 
01836 inline Thread *getThread(void)
01837         {return Thread::get();}
01838 
01868 class __EXPORT SysTime
01869 {
01870 private:
01871                 static Mutex timeLock;
01872 
01873 protected:
01874                 inline static void lock(void)
01875                         {timeLock.enterMutex();}
01876 
01877                 inline static void unlock(void)
01878                         {timeLock.leaveMutex();}
01879 
01880 public:
01881         static time_t getTime(time_t *tloc = NULL);
01882         static time_t time(time_t *tloc) 
01883                         { return getTime(tloc); };
01884 
01885         static int getTimeOfDay(struct timeval *tp);
01886         static int gettimeofday(struct timeval *tp, struct timezone *)
01887                         { return getTimeOfDay(tp); };
01888         
01889         static struct tm *getLocalTime(const time_t *clock, struct tm *result);
01890         static struct tm *locatime(const time_t *clock, struct tm *result)
01891                         { return getLocalTime(clock, result); };
01892 
01893                 static struct tm *getGMTTime(const time_t *clock, struct tm *result);
01894                 static struct tm *gmtime(const time_t *clock, struct tm *result)
01895                         { return getGMTTime(clock, result);};
01896 }; 
01897 
01898 #ifndef HAVE_LOCALTIME_R
01899 
01900 inline struct tm *localtime_r(const time_t *t, struct tm *b)
01901         {return SysTime::getLocalTime(t, b);};
01902 inline char *ctime_r(const time_t *t, char *buf)
01903         {return ctime(t);};
01904 inline struct tm *gmtime_r(const time_t *t, struct tm *b) \
01905 {return SysTime::getGMTTime(t, b);};
01906 inline char *asctime_r(const struct tm *tm, char *b) \
01907         {return asctime(tm);};
01908 
01909 #endif 
01910         
01911 #ifdef  CCXX_NAMESPACES
01912 }
01913 #endif
01914 
01915 #endif
01916 

Generated on Wed Nov 23 23:37:12 2005 for GNU CommonC++ by  doxygen 1.4.5