00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
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
00075
00076
00077
00078
00079
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
00111
00112
00113
00114
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
00185
00186
00187
00188
00189
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
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
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
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
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
00749
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
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
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
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
01778 #if !defined(WIN32)
01779
01780
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