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

thread.h

Go to the documentation of this file.
00001 // Copyright (C) 1999-2003 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 to the GNU General Public License, permission is 
00018 // granted for additional uses of the text contained in its release 
00019 // of Common C++.
00020 // 
00021 // The exception is that, if you link the Common C++ library with other
00022 // files to produce an executable, this does not by itself cause the
00023 // resulting executable to be covered by the GNU General Public License.
00024 // Your use of that executable is in no way restricted on account of
00025 // linking the Common C++ library code into it.
00026 //
00027 // This exception does not however invalidate any other reasons why
00028 // the executable file might be covered by the GNU General Public License.
00029 // 
00030 // This exception applies only to the code released under the 
00031 // name Common C++.  If you copy code from other releases into a copy of
00032 // Common C++, as the General Public License permits, the exception does
00033 // not apply to the code that you add in this way.  To avoid misleading
00034 // anyone as to the status of such modified files, you must delete
00035 // this exception notice from them.
00036 // 
00037 // If you write modifications of your own for Common C++, it is your choice
00038 // whether to permit this exception to apply to your modifications.
00039 // If you do not wish that, delete this exception notice.
00040 
00046 #ifndef CCXX_THREAD_H_
00047 #define CCXX_THREAD_H_
00048 
00049 #ifndef WIN32
00050 #define CCXX_POSIX
00051 #endif // !WIN32
00052 
00053 #ifndef CCXX_CONFIG_H_
00054 #include <cc++/config.h>
00055 #endif
00056 
00057 #include <ctime>
00058 
00059 #ifndef WIN32
00060 #if (defined(__FreeBSD__) && __FreeBSD__ <= 3) || defined(_AIX)
00061 #define CCXX_SYSV_SEMAPHORES
00062 #endif
00063 
00064 #ifdef  MACOSX
00065 #define CCXX_NAMED_SEMAPHORES
00066 #define CCXX_BROKEN_SEMGETVALUE
00067 #endif
00068 
00069 #ifndef HAVE_PTHREAD_H
00070 #include <pthread.h>
00071 #ifndef CCXX_SYSV_SEMAPHORES
00072 #include <semaphore.h>
00073 #endif
00074 #endif
00075 #endif // !WIN32
00076 
00077 #undef CCXX_USE_WIN32_ATOMIC
00078 #ifndef WIN32
00079 #include <time.h>
00080 #include <signal.h>
00081 #include <unistd.h>
00082 
00083 #ifdef  _THR_UNIXWARE
00084 #undef  PTHREAD_MUTEXTYPE_RECURSIVE
00085 #endif
00086 
00087 typedef pthread_t       cctid_t;
00088 typedef unsigned long   timeout_t;
00089 
00090 /*
00091 #if defined(__CYGWIN32__)
00092 __declspec(dllimport) long __stdcall InterlockedIncrement(long *);
00093 __declspec(dllimport) long __stdcall InterlockedDecrement(long *);
00094 __declspec(dllimport) long __stdcall InterlockedExchange(long *, long);
00095 #define CCXX_USE_WIN32_ATOMIC 1
00096 #endif
00097 */
00098 
00099 #else // WIN32
00100 typedef DWORD   cctid_t;
00101 typedef DWORD   timeout_t;
00102 
00103 #define MAX_SEM_VALUE   1000000
00104 #define CCXX_USE_WIN32_ATOMIC 1
00105 
00106 #endif // !WIN32
00107 
00108 #ifdef  CCXX_NAMESPACES
00109 namespace ost {
00110 #endif
00111 
00112 class __EXPORT Thread;
00113 class __EXPORT ThreadKey;
00114 
00115 #define TIMEOUT_INF ~((timeout_t) 0)
00116 
00117 #define ENTER_CRITICAL  enterMutex();
00118 #define LEAVE_CRITICAL  leaveMutex();
00119 #define ENTER_DEFERRED  setCancel(cancelDeferred);
00120 #define LEAVE_DEFERRED  setCancel(cancelImmediate);
00121 
00122 #ifndef WIN32
00123 // These macros override common functions with thread-safe versions. In
00124 // particular the common "libc" sleep() has problems since it normally
00125 // uses SIGARLM (as actually defined by "posix").  The pthread_delay and
00126 // usleep found in libpthread are gaurenteed not to use SIGALRM and offer
00127 // higher resolution.  psleep() is defined to call the old process sleep.
00128 
00129 #undef  sleep
00130 #define psleep(x)       (sleep)(x)
00131 
00132 #endif // !WIN32
00133 
00134 #undef Yield
00135 
00136 class __EXPORT Conditional;
00137 class __EXPORT Event;
00138 
00182 class __EXPORT Mutex
00183 {
00184 private:
00185         static bool _debug;
00186         const char *_name;
00187 #ifndef WIN32
00188 #ifndef PTHREAD_MUTEXTYPE_RECURSIVE
00189         int volatile _level;
00190         Thread *volatile _tid;
00191 #endif
00192         /*
00193          * Pthread mutex object.  This is protected rather than private
00194          * because some mixed mode pthread operations require a mutex as
00195          * well as their primary pthread object.  A good example of this
00196          * is the Event class, as waiting on a conditional object must be
00197          * associated with an accessable mutex.  An alternative would be
00198          * to make such classes "friend" classes of the Mutex.
00199          */
00200         pthread_mutex_t _mutex;
00201 #else // WIN32
00202 
00203 # if defined(MUTEX_UNDERGROUND_WIN32_MUTEX) && defined(MUTEX_UNDERGROUND_WIN32_CRITICALSECTION)
00204 # error "Can't determine underground for Mutex"
00205 # endif
00206 
00207 #ifdef MUTEX_UNDERGROUND_WIN32_MUTEX 
00208         HANDLE _mutex;
00209 #endif
00210 #ifdef MUTEX_UNDERGROUND_WIN32_CRITICALSECTION 
00211         CRITICAL_SECTION _criticalSection;
00212 #endif
00213 
00214 #endif // WIN32
00215 
00216 public:
00220         Mutex(const char *name = NULL);
00221 
00227         virtual ~Mutex();
00228 
00234         static void setDebug(bool mode)
00235                 {_debug = mode;};
00236 
00244         void enterMutex(void);
00245 
00249         inline void enter(void)
00250                 {enterMutex();};
00251 
00252         inline void leave(void)
00253                 {leaveMutex();};
00254 
00255         inline bool test(void)
00256                 {return tryEnterMutex();};
00257 
00268         bool tryEnterMutex(void);
00269 
00280         void leaveMutex(void);
00281 };
00282 
00306 class __EXPORT MutexLock
00307 {
00308 private:
00309         Mutex& mutex;
00310 public:
00314         MutexLock( Mutex& _mutex ) : mutex( _mutex ) 
00315                 { mutex.enterMutex(); }
00319         // this should be not-virtual
00320         ~MutexLock()
00321                 { mutex.leaveMutex(); }
00322 };
00323 
00332 class __EXPORT ThreadLock
00333 {
00334 private:
00335 #ifdef HAVE_PTHREAD_RWLOCK
00336         pthread_rwlock_t _lock;
00337 #else
00338         Mutex mutex;
00339 #endif
00340 
00341 public:
00345         ThreadLock();
00346 
00350         virtual ~ThreadLock();
00351 
00355         void readLock(void);
00356 
00360         void writeLock(void);
00361 
00367         bool tryReadLock(void);
00368 
00374         bool tryWriteLock(void);
00375 
00379         void unlock(void);
00380 };
00381 
00402 class __EXPORT ReadLock
00403 {
00404 private:
00405         ThreadLock& tl;
00406 
00407 public:
00411         ReadLock( ThreadLock& _tl ) : tl( _tl ) 
00412                 { tl.readLock(); }
00416         // this should be not-virtual
00417         ~ReadLock()
00418                 { tl.unlock(); }
00419 };
00420 
00441 class __EXPORT WriteLock
00442 {
00443 private:
00444         ThreadLock& tl;
00445 
00446 public:
00450         WriteLock( ThreadLock& _tl ) : tl( _tl ) 
00451                 { tl.writeLock(); }
00455         // this should be not-virtual
00456         ~WriteLock()
00457                 { tl.unlock(); }
00458 };
00459 
00460 
00470 class __EXPORT MutexCounter : public Mutex
00471 {
00472 private:
00473         volatile int    counter;
00474 
00475 public:
00476         MutexCounter(const char *id = NULL);
00477         MutexCounter(int initial, const char *id = NULL);
00478 
00479         friend __EXPORT int operator++(MutexCounter &mc);
00480         friend __EXPORT int operator--(MutexCounter &mc);
00481 };
00482 
00493 class __EXPORT AtomicCounter
00494 {
00495 #ifndef CCXX_USE_WIN32_ATOMIC
00496 private:
00497 #ifdef  HAVE_ATOMIC_AIX
00498         volatile int counter;
00499 #elif   HAVE_ATOMIC
00500         atomic_t atomic;
00501 #else
00502         volatile int counter;
00503         pthread_mutex_t _mutex;
00504 #endif
00505 
00506 public:
00510         AtomicCounter();
00511 
00517         AtomicCounter(int value);
00518 
00519         ~AtomicCounter();
00520 
00521         int operator++(void);
00522         int operator--(void);
00523         int operator+=(int change);
00524         int operator-=(int change);
00525         int operator+(int change);
00526         int operator-(int change);
00527         int operator=(int value);
00528         bool operator!(void);
00529         operator int();
00530 #else
00531 private:
00532         long atomic;
00533 
00534 public:
00535         inline AtomicCounter()
00536                 {atomic = 0;};
00537 
00538         inline AtomicCounter(int value)
00539                 {atomic = value;};
00540 
00541         inline int operator++(void)
00542                 {return InterlockedIncrement(&atomic);};
00543 
00544         inline int operator--(void)
00545                 {return InterlockedDecrement(&atomic);};
00546 
00547         int operator+=(int change);
00548 
00549         int operator-=(int change);
00550 
00551         inline int operator+(int change)
00552                 {return atomic + change;};
00553 
00554         inline int operator-(int change)
00555                 {return atomic - change;};
00556         
00557         inline int operator=(int value)
00558                 {return InterlockedExchange(&atomic, value);};
00559 
00560         inline bool operator!(void)
00561                 {return (atomic == 0) ? true : false;};
00562 
00563         inline operator int()
00564                 {return atomic;};
00565 #endif
00566 };
00567 
00568 #ifndef WIN32
00569 
00589 class __EXPORT Conditional 
00590 {
00591 private:
00592         pthread_cond_t _cond;
00593         pthread_mutex_t _mutex;
00594 
00595 public:
00599         Conditional(const char *id = NULL);
00600 
00604         virtual ~Conditional();
00605 
00611         void signal(bool broadcast);
00612 
00619         bool wait(timeout_t timer = 0, bool locked = false);
00620 
00627         void enterMutex(void);
00628 
00637         inline void lock(void)
00638                 {enterMutex();};
00639 
00650         bool tryEnterMutex(void);
00651 
00652         inline bool test(void)
00653                 {return tryEnterMutex();};
00654 
00660         void leaveMutex(void);
00661 
00662         inline void unlock(void)
00663                 {return leaveMutex();};
00664 };
00665 #endif
00666 
00684 class __EXPORT Semaphore
00685 {
00686 private:
00687 #ifndef WIN32
00688 #ifdef  CCXX_SYSV_SEMAPHORES
00689         int _semaphore;
00690 #else
00691         sem_t _semaphore;
00692         sem_t *_semobject;
00693 #endif
00694 #else // WIN32
00695         HANDLE  semObject;
00696 #endif // !WIN32
00697 
00698 public:
00707         Semaphore(size_t resource = 0);
00708 
00715         virtual ~Semaphore();
00716 
00730         void wait(void);
00731 
00743         bool tryWait(void);
00744 
00756         void post(void);
00757 
00758         // FIXME: how implement getValue for posix compatibility ?
00764 #ifndef WIN32
00765 #ifndef __CYGWIN32__
00766         int getValue(void);
00767 #endif
00768 #endif
00769 };
00770 
00790 class __EXPORT SemaphoreLock
00791 {
00792 private:
00793         Semaphore& sem;
00794 
00795 public:
00799         SemaphoreLock( Semaphore& _sem ) : sem( _sem ) 
00800                 { sem.wait(); }
00804         // this should be not-virtual
00805         ~SemaphoreLock()
00806                 { sem.post(); }
00807 };
00808 
00822 class __EXPORT Event
00823 {
00824 private:
00825 #ifndef WIN32
00826         pthread_mutex_t _mutex;
00827         pthread_cond_t _cond;
00828         bool _signaled;
00829         int _count;
00830 #else
00831         HANDLE cond;
00832 #endif
00833 
00834 public:
00835         Event();
00836 
00837         virtual ~Event();
00838 
00845         void reset(void);
00846 
00850         void signal(void);
00851 
00860         bool wait(timeout_t timer);
00861         bool wait(void);
00862 };
00863 
00864 
01046 class __EXPORT Thread
01047 {
01048 public:
01052         typedef enum Throw {
01053                 throwNothing,  
01054                 throwObject,   
01055                 throwException 
01056         } Throw;
01057         
01061         typedef enum Cancel
01062         {
01063                 cancelInitial=0,  
01064                 cancelDeferred=1, 
01065                 cancelImmediate,  
01066                 cancelDisabled,   
01067                 cancelManual,     
01069                 cancelDefault=cancelDeferred
01071         } Cancel;
01072 
01076         typedef enum Suspend
01077         {
01078                 suspendEnable, 
01079                 suspendDisable 
01080         } Suspend;
01081 
01082 #ifndef WIN32
01083 
01084 friend class PosixThread;
01085 #endif
01086 
01087 friend class DummyThread;
01088 private:
01089         friend class Cancellation;
01090         friend class postream_type;
01091         friend class Slog;
01092 
01093         Semaphore joinSem;
01094         static Thread* _main;
01095 
01096         Thread *_parent;
01097         Cancel _cancel;
01098         Semaphore *_start;
01099 
01100         // private data
01101         friend class ThreadImpl;
01102         class ThreadImpl* priv;
01103 
01104 public:
01105         static Thread *get(void);
01106 
01107 private:
01108 #ifdef  WIN32
01109         static unsigned __stdcall Execute(Thread *th);
01110 #endif
01111 
01112         // close current thread, free all and call Notify
01113         void close();
01114 
01115 private:
01116         char _name[32];
01117         static size_t _autostack;
01118 
01119 #ifdef WIN32
01120         DWORD waitHandle(HANDLE obj, timeout_t timeout);
01121 #endif
01122 
01123 protected:
01131         void setName(const char *text);
01132 
01142         virtual void run(void) = 0;
01143 
01165         virtual void final(void)
01166                 {return;};
01167 
01179         virtual void initial(void)
01180                 {return;};
01181 
01191         virtual void* getExtended(void)
01192                 {return NULL;};
01193 
01201         virtual void notify(Thread*)
01202                 {return;};
01203 
01209         void exit(void);
01210 
01214         void sync(void);
01215 
01219         bool testCancel(void);
01220 
01230         void setCancel(Cancel mode);
01231 
01239         void setSuspend(Suspend mode);
01240 
01249         void terminate(void);
01250 
01254         inline void clrParent(void)
01255                 {_parent = NULL;};
01256 
01257 public:
01266         Thread(bool isMain);
01267 
01279         Thread(int pri = 0, size_t stack = 0);
01280 
01281 #ifndef WIN32
01282 
01290         Thread(const Thread &th);
01291 #endif
01292 
01299         virtual ~Thread();
01300 
01306         static void setStack(size_t size = 0)
01307                 {_autostack = size;};
01308 
01318         static void sleep(timeout_t msec);
01319 
01324         static void yield(void);
01325 
01338         int start(Semaphore *start = 0);
01339 
01348         int detach(Semaphore *start = 0);
01349 
01356         inline Thread *getParent(void)
01357                 {return _parent;};
01358 
01365         void suspend(void);
01366 
01370         void resume(void);
01371 
01378         inline Cancel getCancel(void)
01379                 {return _cancel;};
01380 
01387         bool isRunning(void);
01388 
01394         bool isDetached(void);
01395 
01399         void join(void);
01400 
01407         bool isThread(void);
01408 
01414         cctid_t getId(void) const;
01415 
01422         const char *getName(void)
01423                 {return _name;};
01424 
01430         static Throw getException(void);
01431 
01437         static void setException(Throw mode);
01438 
01445         friend inline void operator++(Thread &th)
01446                 {if (th._start) th._start->post();};
01447 
01448         friend inline void operator--(Thread &th)
01449                 {if (th._start) th._start->wait();};
01450 
01451 #ifdef WIN32
01452         bool isCancelled();
01453 
01454         static DWORD waitThread(HANDLE hRef, timeout_t timeout);
01455 #endif
01456 
01464         static Cancel enterCancel(void);
01465 
01471         static void exitCancel(Cancel cancel);
01472 };
01473 
01483 class __EXPORT Cancellation
01484 {
01485 private:
01486         Thread::Cancel prior;
01487 
01488 public:
01489         Cancellation(Thread::Cancel cancel);
01490         ~Cancellation();
01491 };
01492 
01493 #if !defined(WIN32) && !defined(__MINGW32__)
01494 typedef int             signo_t;
01495 
01496 class PosixThread: public Thread
01497 {
01498 private:
01499 #ifndef WIN32
01500 
01501         friend class ThreadImpl;
01502         friend class Thread;
01503 #endif
01504 #ifndef CCXX_SIG_THREAD_ALARM
01505         static PosixThread *_timer;
01506         static Mutex _arm;
01507 #endif
01508         
01509         time_t  _alarm;
01510         static void signalThread(Thread* th,signo_t signo);
01511 protected:
01512                 
01519         inline void signalParent(signo_t signo)
01520                 { signalThread(_parent,signo); };
01521         
01528         inline void signalMain(signo_t signo)
01529                 { signalThread(_main,signo);};
01530 
01535         virtual void onTimer(void)
01536                 {return;};
01537 
01542         virtual void onHangup(void)
01543                 {return;};
01544 
01549         virtual void onException(void)
01550                 {return;};
01551 
01556         virtual void onDisconnect(void)
01557                 {return;};
01558 
01563         virtual void onPolling(void)
01564                 {return;};
01565 
01572         virtual void onSignal(int)
01573                 {return;};
01574         
01587         void setTimer(timeout_t timer, bool periodic = false);
01588         
01595         timeout_t getTimer(void) const;
01596         
01602         void endTimer(void);
01603 
01604 #if defined(HAVE_SIGWAIT) || defined(HAVE_SIGWAIT2)     
01605 
01611         void waitSignal(signo_t signo);
01612 #endif
01613         
01620         void setSignal(int signo, bool active);
01621 
01628         pthread_attr_t *getPthreadAttrPtr(void);
01629 
01634         pthread_t getPthreadId(void);
01635 
01636 public:
01637 
01638         PosixThread(int pri = 0, size_t stack = 0);
01639         
01645         inline void signalThread(int signo)
01646                 {signalThread(this, signo);};
01647 
01654         static void sigInstall(int signo);
01655 };
01656 #endif
01657 
01672 class __EXPORT ThreadKey
01673 {
01674 private:
01675 #ifndef WIN32
01676         pthread_key_t key;
01677         typedef void (*TDestruct)(void*);
01678         friend class ThreadImpl;
01679         ThreadKey(TDestruct destruct);
01680 #else
01681         DWORD   key;
01682 #endif
01683 
01684 public:
01688         ThreadKey();
01692         virtual ~ThreadKey();
01700         void *getKey(void);
01708         void setKey(void *);
01709 };
01710 
01721 class __EXPORT TimerPort
01722 {
01723 #ifndef WIN32
01724         struct timeval timer;
01725 #else
01726         DWORD timer;
01727 #endif
01728         bool active;
01729 
01730 public:
01737         TimerPort();
01738 
01747         void setTimer(timeout_t timeout = 0);
01748 
01758         void incTimer(timeout_t timeout);
01759 
01765         void endTimer(void);
01766 
01778         timeout_t getTimer(void) const;
01779 
01789         timeout_t getElapsed(void) const;
01790 };
01791 
01792 
01793 
01794 // FIXME: not in win32 implementation
01795 #if !defined(WIN32)
01796 
01797 // FIXME: private declaration ???
01798 struct  timespec *getTimeout(struct timespec *spec, timeout_t timeout); 
01799 
01800 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
01801 void    wait(signo_t signo);
01802 #endif
01803 
01804 #endif // !WIN32
01805 
01806 #ifdef USE_POLL
01807 
01815 class Poller 
01816 {
01817 private:
01818         int nufds;
01819         pollfd *ufds;
01820 
01821 public:
01822         Poller();
01823 
01824         virtual ~Poller();
01825 
01833         pollfd *getList(int cnt);
01834 
01840         inline  pollfd *getList(void)
01841                 {return ufds;};
01842 };
01843 #endif
01844 
01845 inline Thread *getThread(void)
01846         {return Thread::get();}
01847 
01877 class __EXPORT SysTime
01878 {
01879 private:
01880                 static Mutex timeLock;
01881 
01882 protected:
01883                 inline static void lock(void)
01884                         {timeLock.enterMutex();}
01885 
01886                 inline static void unlock(void)
01887                         {timeLock.leaveMutex();}
01888 
01889 public:
01890         static time_t getTime(time_t *tloc = NULL);
01891         static time_t time(time_t *tloc) 
01892                         { return getTime(tloc); };
01893 
01894         static int getTimeOfDay(struct timeval *tp);
01895         static int gettimeofday(struct timeval *tp, struct timezone *tzp)
01896                         { return getTimeOfDay(tp); };
01897         
01898         static struct tm *getLocalTime(const time_t *clock, struct tm *result);
01899         static struct tm *locatime(const time_t *clock, struct tm *result)
01900                         { return getLocalTime(clock, result); };
01901 
01902                 static struct tm *getGMTTime(const time_t *clock, struct tm *result);
01903                 static struct tm *gmtime(const time_t *clock, struct tm *result)
01904                         { return getGMTTime(clock, result);};
01905 }; 
01906 
01907 #ifndef HAVE_LOCALTIME_R
01908 
01909 inline struct tm *localtime_r(const time_t *t, struct tm *b)
01910         {return SysTime::getLocalTime(t, b);};
01911 inline char *ctime_r(const time_t *t, char *buf)
01912         {return ctime(t);};
01913 inline struct tm *gmtime_r(const time_t *t, struct tm *b) \
01914 {return SysTime::getGMTTime(t, b);};
01915 inline char *asctime_r(const struct tm *tm, char *b) \
01916         {return asctime(tm);};
01917 
01918 #endif 
01919         
01920 #ifdef  CCXX_NAMESPACES
01921 }
01922 #endif
01923 
01924 #endif
01925 

Generated on Tue Jan 18 14:32:37 2005 for GNU CommonC++ by  doxygen 1.3.9.1