Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages | Examples

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 #ifndef WIN32
00047 #define CCXX_POSIX
00048 #endif // !WIN32
00049 
00050 #ifndef CCXX_CONFIG_H_
00051 #include <cc++/config.h>
00052 #endif
00053 
00054 #include <ctime>
00055 
00056 #ifndef WIN32
00057 #include <pthread.h>
00058 #endif // !WIN32
00059 
00060 #undef CCXX_USE_WIN32_ATOMIC
00061 #ifndef WIN32
00062 #include <time.h>
00063 #include <signal.h>
00064 #include <unistd.h>
00065 
00066 #ifdef  _THR_UNIXWARE
00067 #undef  PTHREAD_MUTEXTYPE_RECURSIVE
00068 #endif
00069 
00070 typedef pthread_t       cctid_t;
00071 typedef unsigned long   timeout_t;
00072 
00073 /*
00074 #if defined(__CYGWIN32__)
00075 __declspec(dllimport) long __stdcall InterlockedIncrement(long *);
00076 __declspec(dllimport) long __stdcall InterlockedDecrement(long *);
00077 __declspec(dllimport) long __stdcall InterlockedExchange(long *, long);
00078 #define CCXX_USE_WIN32_ATOMIC 1
00079 #endif
00080 */
00081 
00082 #else // WIN32
00083 typedef DWORD   cctid_t;
00084 typedef DWORD   timeout_t;
00085 
00086 #define MAX_SEM_VALUE   1000000
00087 #define CCXX_USE_WIN32_ATOMIC 1
00088 
00089 #endif // !WIN32
00090 
00091 #ifdef  CCXX_NAMESPACES
00092 namespace ost {
00093 #endif
00094 
00095 #ifdef  HAVE_GCC_CXX_BITS_ATOMIC
00096 using namespace __gnu_cxx;
00097 #endif
00098 
00099 class __EXPORT Thread;
00100 class __EXPORT ThreadKey;
00101 
00102 #define TIMEOUT_INF ~((timeout_t) 0)
00103 
00104 #define ENTER_CRITICAL  enterMutex();
00105 #define LEAVE_CRITICAL  leaveMutex();
00106 #define ENTER_DEFERRED  setCancel(cancelDeferred);
00107 #define LEAVE_DEFERRED  setCancel(cancelImmediate);
00108 
00109 #ifndef WIN32
00110 // These macros override common functions with thread-safe versions. In
00111 // particular the common "libc" sleep() has problems since it normally
00112 // uses SIGARLM (as actually defined by "posix").  The pthread_delay and
00113 // usleep found in libpthread are gaurenteed not to use SIGALRM and offer
00114 // higher resolution.  psleep() is defined to call the old process sleep.
00115 
00116 #undef  sleep
00117 #define psleep(x)       (sleep)(x)
00118 
00119 #ifdef  signal
00120 #undef  signal
00121 #endif
00122 
00123 #endif // !WIN32
00124 
00125 #undef Yield
00126 
00127 class __EXPORT Conditional;
00128 class __EXPORT Event;
00129 
00173 class __EXPORT Mutex
00174 {
00175 private:
00176         static bool _debug;
00177         const char *_name;
00178 #ifndef WIN32
00179 #ifndef PTHREAD_MUTEXTYPE_RECURSIVE
00180         int volatile _level;
00181         Thread *volatile _tid;
00182 #endif
00183         /*
00184          * Pthread mutex object.  This is protected rather than private
00185          * because some mixed mode pthread operations require a mutex as
00186          * well as their primary pthread object.  A good example of this
00187          * is the Event class, as waiting on a conditional object must be
00188          * associated with an accessable mutex.  An alternative would be
00189          * to make such classes "friend" classes of the Mutex.
00190          */
00191         pthread_mutex_t _mutex;
00192 #else // WIN32
00193 
00194 # if defined(MUTEX_UNDERGROUND_WIN32_MUTEX) && defined(MUTEX_UNDERGROUND_WIN32_CRITICALSECTION)
00195 # error "Can't determine underground for Mutex"
00196 # endif
00197 
00198 #ifdef MUTEX_UNDERGROUND_WIN32_MUTEX 
00199         HANDLE _mutex;
00200 #endif
00201 #ifdef MUTEX_UNDERGROUND_WIN32_CRITICALSECTION 
00202         CRITICAL_SECTION _criticalSection;
00203 #endif
00204 
00205 #endif // WIN32
00206 
00207 public:
00211         Mutex(const char *name = NULL);
00212 
00218         virtual ~Mutex();
00219 
00225         static void setDebug(bool mode)
00226                 {_debug = mode;};
00227 
00233         inline void nameMutex(const char *cp)
00234                 {_name = cp;};
00235 
00243         void enterMutex(void);
00244 
00248         inline void enter(void)
00249                 {enterMutex();};
00250 
00251         inline void leave(void)
00252                 {leaveMutex();};
00253 
00254         inline bool test(void)
00255                 {return tryEnterMutex();};
00256 
00267         bool tryEnterMutex(void);
00268 
00279         void leaveMutex(void);
00280 };
00281 
00305 class __EXPORT MutexLock
00306 {
00307 private:
00308         Mutex& mutex;
00309 public:
00313         MutexLock( Mutex& _mutex ) : mutex( _mutex ) 
00314                 { mutex.enterMutex(); }
00318         // this should be not-virtual
00319         ~MutexLock()
00320                 { mutex.leaveMutex(); }
00321 };
00322 
00331 class __EXPORT ThreadLock
00332 {
00333 private:
00334 #ifdef HAVE_PTHREAD_RWLOCK
00335         pthread_rwlock_t _lock;
00336 #else
00337         Mutex mutex;
00338 #endif
00339 
00340 public:
00344         ThreadLock();
00345 
00349         virtual ~ThreadLock();
00350 
00354         void readLock(void);
00355 
00359         void writeLock(void);
00360 
00366         bool tryReadLock(void);
00367 
00373         bool tryWriteLock(void);
00374 
00378         void unlock(void);
00379 };
00380 
00401 class __EXPORT ReadLock
00402 {
00403 private:
00404         ThreadLock& tl;
00405 
00406 public:
00410         ReadLock( ThreadLock& _tl ) : tl( _tl ) 
00411                 { tl.readLock(); }
00415         // this should be not-virtual
00416         ~ReadLock()
00417                 { tl.unlock(); }
00418 };
00419 
00440 class __EXPORT WriteLock
00441 {
00442 private:
00443         ThreadLock& tl;
00444 
00445 public:
00449         WriteLock( ThreadLock& _tl ) : tl( _tl ) 
00450                 { tl.writeLock(); }
00454         // this should be not-virtual
00455         ~WriteLock()
00456                 { tl.unlock(); }
00457 };
00458 
00459 
00469 class __EXPORT MutexCounter : public Mutex
00470 {
00471 private:
00472         volatile int    counter;
00473 
00474 public:
00475         MutexCounter(const char *id = NULL);
00476         MutexCounter(int initial, const char *id = NULL);
00477 
00478         friend __EXPORT int operator++(MutexCounter &mc);
00479         friend __EXPORT int operator--(MutexCounter &mc);
00480 };
00481 
00492 class __EXPORT AtomicCounter
00493 {
00494 #ifndef CCXX_USE_WIN32_ATOMIC
00495 private:
00496 #ifdef  HAVE_ATOMIC_AIX
00497         volatile int counter;
00498 #elif   HAVE_GCC_BITS_ATOMIC
00499         volatile _Atomic_word counter;
00500 #elif   HAVE_GCC_CXX_BITS_ATOMIC
00501         volatile _Atomic_word counter;
00502 //      __gnu_cxx::_Atomic_word counter;
00503 #elif   HAVE_ATOMIC
00504         atomic_t atomic;
00505 #else
00506         volatile int counter;
00507         pthread_mutex_t _mutex;
00508 #endif
00509 
00510 public:
00514         AtomicCounter();
00515 
00521         AtomicCounter(int value);
00522 
00523         ~AtomicCounter();
00524 
00525         int operator++(void);
00526         int operator--(void);
00527         int operator+=(int change);
00528         int operator-=(int change);
00529         int operator+(int change);
00530         int operator-(int change);
00531         int operator=(int value);
00532         bool operator!(void);
00533         operator int();
00534 #else
00535 private:
00536         long atomic;
00537 
00538 public:
00539         inline AtomicCounter()
00540                 {atomic = 0;};
00541 
00542         inline AtomicCounter(int value)
00543                 {atomic = value;};
00544 
00545         inline int operator++(void)
00546                 {return InterlockedIncrement(&atomic);};
00547 
00548         inline int operator--(void)
00549                 {return InterlockedDecrement(&atomic);};
00550 
00551         int operator+=(int change);
00552 
00553         int operator-=(int change);
00554 
00555         inline int operator+(int change)
00556                 {return atomic + change;};
00557 
00558         inline int operator-(int change)
00559                 {return atomic - change;};
00560         
00561         inline int operator=(int value)
00562                 {return InterlockedExchange(&atomic, value);};
00563 
00564         inline bool operator!(void)
00565                 {return (atomic == 0) ? true : false;};
00566 
00567         inline operator int()
00568                 {return atomic;};
00569 #endif
00570 };
00571 
00572 #ifndef WIN32
00573 
00593 class __EXPORT Conditional 
00594 {
00595 private:
00596         pthread_cond_t _cond;
00597         pthread_mutex_t _mutex;
00598 
00599 public:
00603         Conditional(const char *id = NULL);
00604 
00608         virtual ~Conditional();
00609 
00615         void signal(bool broadcast);
00616 
00623         bool wait(timeout_t timer = 0, bool locked = false);
00624 
00631         void enterMutex(void);
00632 
00641         inline void lock(void)
00642                 {enterMutex();};
00643 
00654         bool tryEnterMutex(void);
00655 
00656         inline bool test(void)
00657                 {return tryEnterMutex();};
00658 
00664         void leaveMutex(void);
00665 
00666         inline void unlock(void)
00667                 {return leaveMutex();};
00668 };
00669 #endif
00670 
00688 class __EXPORT Semaphore
00689 {
00690 private:
00691 #ifndef WIN32
00692         unsigned _count, _waiters;
00693         pthread_mutex_t _mutex;
00694         pthread_cond_t _cond;
00695 #else
00696         HANDLE  semObject;
00697 #endif // !WIN32
00698 
00699 public:
00708         Semaphore(unsigned resource = 0);
00709 
00716         virtual ~Semaphore();
00717 
00733         bool wait(timeout_t timeout = 0);
00734 
00746         void post(void);
00747 
00748         // FIXME: how implement getValue for posix compatibility ?
00749         // not portable...
00750 
00751 #if     0
00752 
00757         int getValue(void);
00758 #endif
00759 };
00760 
00780 class __EXPORT SemaphoreLock
00781 {
00782 private:
00783         Semaphore& sem;
00784 
00785 public:
00789         SemaphoreLock( Semaphore& _sem ) : sem( _sem ) 
00790                 { sem.wait(); }
00794         // this should be not-virtual
00795         ~SemaphoreLock()
00796                 { sem.post(); }
00797 };
00798 
00812 class __EXPORT Event
00813 {
00814 private:
00815 #ifndef WIN32
00816         pthread_mutex_t _mutex;
00817         pthread_cond_t _cond;
00818         bool _signaled;
00819         int _count;
00820 #else
00821         HANDLE cond;
00822 #endif
00823 
00824 public:
00825         Event();
00826 
00827         virtual ~Event();
00828 
00835         void reset(void);
00836 
00840         void signal(void);
00841 
00850         bool wait(timeout_t timer);
00851         bool wait(void);
00852 };
00853 
00854 
01036 class __EXPORT Thread
01037 {
01038 public:
01042         typedef enum Throw {
01043                 throwNothing,  
01044                 throwObject,   
01045                 throwException 
01046         } Throw;
01047         
01051         typedef enum Cancel
01052         {
01053                 cancelInitial=0,  
01054                 cancelDeferred=1, 
01055                 cancelImmediate,  
01056                 cancelDisabled,   
01057                 cancelManual,     
01059                 cancelDefault=cancelDeferred
01061         } Cancel;
01062 
01066         typedef enum Suspend
01067         {
01068                 suspendEnable, 
01069                 suspendDisable 
01070         } Suspend;
01071 
01072 #ifndef WIN32
01073 
01074 friend class PosixThread;
01075 #endif
01076 
01077 friend class DummyThread;
01078 private:
01079         friend class Cancellation;
01080         friend class postream_type;
01081         friend class Slog;
01082 
01083         Semaphore joinSem;
01084         static Thread* _main;
01085 
01086         Thread *_parent;
01087         Cancel _cancel;
01088         Semaphore *_start;
01089 
01090         // private data
01091         friend class ThreadImpl;
01092         class ThreadImpl* priv;
01093 
01094 public:
01095         static Thread *get(void);
01096 
01097 private:
01098 #ifdef  WIN32
01099         static unsigned __stdcall Execute(Thread *th);
01100 #endif
01101 
01102         // close current thread, free all and call Notify
01103         void close();
01104 
01105 private:
01106         char _name[32];
01107         static size_t _autostack;
01108 
01109 #ifdef WIN32
01110         DWORD waitHandle(HANDLE obj, timeout_t timeout);
01111 #endif
01112 
01113 protected:
01121         void setName(const char *text);
01122 
01132         virtual void run(void) = 0;
01133 
01155         virtual void final(void);
01156 
01168         virtual void initial(void);
01169 
01179         virtual void* getExtended(void);
01180 
01188         virtual void notify(Thread*);
01189 
01195         void exit(void);
01196 
01200         void sync(void);
01201 
01205         bool testCancel(void);
01206 
01216         void setCancel(Cancel mode);
01217 
01225         void setSuspend(Suspend mode);
01226 
01235         void terminate(void);
01236 
01240         inline void clrParent(void)
01241                 {_parent = NULL;};
01242 
01243 public:
01252         Thread(bool isMain);
01253 
01265         Thread(int pri = 0, size_t stack = 0);
01266 
01267 #ifndef WIN32
01268 
01276         Thread(const Thread &th);
01277 #endif
01278 
01285         virtual ~Thread();
01286 
01292         static void setStack(size_t size = 0)
01293                 {_autostack = size;};
01294 
01304         static void sleep(timeout_t msec);
01305 
01310         static void yield(void);
01311 
01324         int start(Semaphore *start = 0);
01325 
01334         int detach(Semaphore *start = 0);
01335 
01342         inline Thread *getParent(void)
01343                 {return _parent;};
01344 
01351         void suspend(void);
01352 
01356         void resume(void);
01357 
01364         inline Cancel getCancel(void)
01365                 {return _cancel;};
01366 
01373         bool isRunning(void);
01374 
01380         bool isDetached(void);
01381 
01385         void join(void);
01386 
01393         bool isThread(void);
01394 
01400         cctid_t getId(void) const;
01401 
01408         const char *getName(void)
01409                 {return _name;};
01410 
01416         static Throw getException(void);
01417 
01423         static void setException(Throw mode);
01424 
01431         friend inline void operator++(Thread &th)
01432                 {if (th._start) th._start->post();};
01433 
01434         friend inline void operator--(Thread &th)
01435                 {if (th._start) th._start->wait();};
01436 
01437 #ifdef WIN32
01438         bool isCancelled();
01439 
01440         static DWORD waitThread(HANDLE hRef, timeout_t timeout);
01441 #endif
01442 
01450         static Cancel enterCancel(void);
01451 
01457         static void exitCancel(Cancel cancel);
01458 };
01459 
01469 class __EXPORT Cancellation
01470 {
01471 private:
01472         Thread::Cancel prior;
01473 
01474 public:
01475         Cancellation(Thread::Cancel cancel);
01476         ~Cancellation();
01477 };
01478 
01479 #if !defined(WIN32) && !defined(__MINGW32__)
01480 typedef int             signo_t;
01481 
01482 class PosixThread: public Thread
01483 {
01484 private:
01485 #ifndef WIN32
01486 
01487         friend class ThreadImpl;
01488         friend class Thread;
01489 #endif
01490 #ifndef CCXX_SIG_THREAD_ALARM
01491         static PosixThread *_timer;
01492         static Mutex _arm;
01493 #endif
01494         
01495         time_t  _alarm;
01496         static void signalThread(Thread* th,signo_t signo);
01497 protected:
01498                 
01505         inline void signalParent(signo_t signo)
01506                 { signalThread(_parent,signo); };
01507         
01514         inline void signalMain(signo_t signo)
01515                 { signalThread(_main,signo);};
01516 
01521         virtual void onTimer(void);
01522 
01527         virtual void onHangup(void);
01528 
01533         virtual void onException(void);
01534 
01539         virtual void onDisconnect(void);
01540 
01545         virtual void onPolling(void);
01546 
01553         virtual void onSignal(int);
01554         
01567         void setTimer(timeout_t timer, bool periodic = false);
01568         
01575         timeout_t getTimer(void) const;
01576         
01582         void endTimer(void);
01583 
01584 #if defined(HAVE_SIGWAIT) || defined(HAVE_SIGWAIT2)     
01585 
01591         void waitSignal(signo_t signo);
01592 #endif
01593         
01600         void setSignal(int signo, bool active);
01601 
01608         pthread_attr_t *getPthreadAttrPtr(void);
01609 
01614         pthread_t getPthreadId(void);
01615 
01616 public:
01617 
01618         PosixThread(int pri = 0, size_t stack = 0);
01619         
01625         inline void signalThread(int signo)
01626                 {signalThread(this, signo);};
01627 
01634         static void sigInstall(int signo);
01635 };
01636 #endif
01637 
01652 class __EXPORT ThreadKey
01653 {
01654 private:
01655 #ifndef WIN32
01656         pthread_key_t key;
01657         typedef void (*TDestruct)(void*);
01658         friend class ThreadImpl;
01659         ThreadKey(TDestruct destruct);
01660 #else
01661         DWORD   key;
01662 #endif
01663 
01664 public:
01668         ThreadKey();
01669 
01673         virtual ~ThreadKey();
01674 
01682         void *getKey(void);
01683 
01691         void setKey(void *);
01692 };
01693 
01704 class __EXPORT TimerPort
01705 {
01706 #ifndef WIN32
01707         struct timeval timer;
01708 #else
01709         DWORD timer;
01710 #endif
01711         bool active;
01712 
01713 public:
01720         TimerPort();
01721 
01730         void setTimer(timeout_t timeout = 0);
01731 
01741         void incTimer(timeout_t timeout);
01742 
01748         void endTimer(void);
01749 
01761         timeout_t getTimer(void) const;
01762 
01772         timeout_t getElapsed(void) const;
01773 };
01774 
01775 
01776 
01777 // FIXME: not in win32 implementation
01778 #if !defined(WIN32)
01779 
01780 // FIXME: private declaration ???
01781 struct  timespec *getTimeout(struct timespec *spec, timeout_t timeout); 
01782 
01783 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
01784 void    wait(signo_t signo);
01785 #endif
01786 
01787 #endif // !WIN32
01788 
01789 #ifdef USE_POLL
01790 
01798 class Poller 
01799 {
01800 private:
01801         int nufds;
01802         pollfd *ufds;
01803 
01804 public:
01805         Poller();
01806 
01807         virtual ~Poller();
01808 
01816         pollfd *getList(int cnt);
01817 
01823         inline  pollfd *getList(void)
01824                 {return ufds;};
01825 };
01826 #endif
01827 
01828 inline Thread *getThread(void)
01829         {return Thread::get();}
01830 
01860 class __EXPORT SysTime
01861 {
01862 private:
01863                 static Mutex timeLock;
01864 
01865 protected:
01866                 inline static void lock(void)
01867                         {timeLock.enterMutex();}
01868 
01869                 inline static void unlock(void)
01870                         {timeLock.leaveMutex();}
01871 
01872 public:
01873         static time_t getTime(time_t *tloc = NULL);
01874         static time_t time(time_t *tloc) 
01875                         { return getTime(tloc); };
01876 
01877         static int getTimeOfDay(struct timeval *tp);
01878         static int gettimeofday(struct timeval *tp, struct timezone *)
01879                         { return getTimeOfDay(tp); };
01880         
01881         static struct tm *getLocalTime(const time_t *clock, struct tm *result);
01882         static struct tm *locatime(const time_t *clock, struct tm *result)
01883                         { return getLocalTime(clock, result); };
01884 
01885                 static struct tm *getGMTTime(const time_t *clock, struct tm *result);
01886                 static struct tm *gmtime(const time_t *clock, struct tm *result)
01887                         { return getGMTTime(clock, result);};
01888 }; 
01889 
01890 #ifndef HAVE_LOCALTIME_R
01891 
01892 inline struct tm *localtime_r(const time_t *t, struct tm *b)
01893         {return SysTime::getLocalTime(t, b);};
01894 inline char *ctime_r(const time_t *t, char *buf)
01895         {return ctime(t);};
01896 inline struct tm *gmtime_r(const time_t *t, struct tm *b) \
01897 {return SysTime::getGMTTime(t, b);};
01898 inline char *asctime_r(const struct tm *tm, char *b) \
01899         {return asctime(tm);};
01900 
01901 #endif 
01902         
01903 #ifdef  CCXX_NAMESPACES
01904 }
01905 #endif
01906 
01907 #endif
01908 

Generated on Fri Jul 22 00:15:50 2005 for GNU CommonC++ by  doxygen 1.4.3-20050530