Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

thread.h

Go to the documentation of this file.
00001 // Copyright (C) 1999-2001 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 //
00041 
00042 #ifndef __CCXX_THREAD_H__
00043 #define __CCXX_THREAD_H__
00044 #define __CCXX_POSIX
00045 
00046 #ifndef _REENTRANT
00047 #define _REENTRANT
00048 #endif
00049 
00050 #ifndef _THREAD_SAFE
00051 #define _THREAD_SAFE
00052 #endif
00053 
00054 #ifndef __CCXX_CONFIG_H__
00055 #ifdef  PACKAGE
00056 #undef  PACKAGE
00057 #endif
00058 #ifdef  VERSION
00059 #undef  VERSION
00060 #endif
00061 #include <cc++/config.h>
00062 #endif
00063 
00064 #if defined(__FreeBSD__) && __FreeBSD__ <= 3
00065 #define _SYSV_SEMAPHORES
00066 #endif
00067 
00068 #ifndef HAVE_PTHREAD_H
00069 #include <pthread.h>
00070 #ifndef _SYSV_SEMAPHORES
00071 #include <semaphore.h>
00072 #endif
00073 #endif
00074 
00075 #ifndef __CCXX_MACROS_H__
00076 #include <cc++/macros.h>
00077 #else
00078 #ifdef  __CCXX_NAMESPACE_H__
00079 #include <cc++/macros.h>
00080 #endif
00081 #endif
00082 
00083 #include <time.h>
00084 #include <signal.h>
00085 #include <setjmp.h>
00086 #include <unistd.h>
00087 
00088 #ifdef  __linux__
00089 #define _SIG_THREAD_STOPCONT
00090 #define _SIG_THREAD_ALARM
00091 #endif
00092 
00093 #ifdef  _THR_UNIXWARE
00094 #define _EFTSAFE
00095 #undef  PTHREAD_MUTEXTYPE_RECURSIVE
00096 #undef  _POSIX_THREAD_PRIORITY_SCHEDULING
00097 #define sigwait(x, y) _thr_sigwait(x, y)
00098 #endif
00099 
00100 typedef pthread_t       cctid_t;
00101 typedef unsigned long   timeout_t;
00102 typedef int             signo_t;
00103 
00104 typedef enum {
00105         THROW_NOTHING, 
00106         THROW_OBJECT, 
00107         THROW_EXCEPTION
00108 }               throw_t;
00109 
00110 #define TIMEOUT_INF ~((timeout_t) 0)
00111 
00112 // use a define so that if the sys/types.h header already defines caddr_t
00113 // as it may on BSD systems, we do not break it by redefining again.
00114 
00115 #undef caddr_t
00116 #define caddr_t         char *
00117 
00118 #define ENTER_CRITICAL  EnterMutex();
00119 #define LEAVE_CRITICAL  LeaveMutex();
00120 #define ENTER_DEFERRED  setCancel(THREAD_CANCEL_DEFERRED);
00121 #define LEAVE_DEFERRED  setCancel(THREAD_CANCEL_IMMEDIATE);
00122 
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 sleep(x)        ccxx_sleep((x) * 1000)
00131 #define yield()         ccxx_yield()
00132 #define psleep(x)       (sleep)(x)
00133 
00134 typedef enum
00135 {
00136         THREAD_CANCEL_INITIAL=0,
00137         THREAD_CANCEL_DEFERRED=1,
00138         THREAD_CANCEL_IMMEDIATE,
00139         THREAD_CANCEL_DISABLED,
00140         THREAD_CANCEL_DEFAULT=THREAD_CANCEL_DEFERRED,
00141         THREAD_CANCEL_INVALID
00142 } thread_cancel_t;
00143 
00144 typedef enum
00145 {
00146         THREAD_SUSPEND_ENABLE,
00147         THREAD_SUSPEND_DISABLE
00148 } thread_suspend_t;
00149 
00150 #define  THREAD_SIGNAL_BLOCKED  false
00151 #define  THREAD_SIGNAL_UNBLOCK  true
00152         
00153 #ifdef  _SIG_THREAD_STOPCONT
00154 #define _SIG_THREAD_SUSPEND SIGSTOP
00155 #define _SIG_THREAD_RESUME  SIGCONT
00156 #else
00157 #ifndef SIGUSR3
00158 #ifdef  SIGWINCH
00159 #define SIGUSR3 SIGWINCH
00160 #else
00161 #define SIGUSR3 SIGINT
00162 #endif
00163 #endif
00164 #define _SIG_THREAD_SUSPEND SIGUSR3
00165 #define _SIG_THREAD_RESUME SIGUSR3
00166 #endif
00167 
00168 class Thread;
00169 
00170 Thread *getThread(void);
00171 
00172 extern "C" {
00173         void execHandler(Thread *th);
00174         void sigHandler(int signo);
00175 };
00176 
00185 class ThreadLock
00186 {
00187 private:
00188 #ifdef HAVE_PTHREAD_RWLOCK
00189         pthread_rwlock_t _lock;
00190 #else
00191         pthread_mutex_t _lock;
00192 #endif
00193 
00194 public:
00198         ThreadLock();
00199 
00203         ~ThreadLock();
00204 
00208         void ReadLock(void);
00209 
00213         void WriteLock(void);
00214 
00220         bool TryReadLock(void);
00221 
00227         bool TryWriteLock(void);
00228 
00232         void Unlock(void);
00233 };
00234 
00278 class Mutex 
00279 {
00280 private:
00281 #ifndef PTHREAD_MUTEXTYPE_RECURSIVE
00282         volatile int _level;
00283         volatile Thread *_tid;
00284 #endif
00285 
00286 protected:
00295         pthread_mutex_t _mutex;
00296 
00297 public:
00301         Mutex();
00302 
00308         ~Mutex()
00309                 {pthread_mutex_destroy(&_mutex);};
00310 
00318 #ifdef  PTHREAD_MUTEXTYPE_RECURSIVE
00319         inline void EnterMutex(void)
00320                 {pthread_mutex_lock(&_mutex);};
00321 #else
00322         void    EnterMutex(void);
00323 #endif
00324 
00335         bool TryEnterMutex(void);
00336 
00347 #ifdef  PTHREAD_MUTEXTYPE_RECURSIVE
00348         inline void LeaveMutex(void)
00349                 {pthread_mutex_unlock(&_mutex);};
00350 #else
00351         void LeaveMutex(void);
00352 #endif
00353 };
00354 
00364 class MutexCounter : public Mutex
00365 {
00366 private:
00367         int     counter;
00368 
00369 public:
00370         MutexCounter(int initial = 0);
00371         
00372         friend int operator ++(MutexCounter &mc);
00373         friend int operator --(MutexCounter &mc);
00374 };
00375 
00386 class AtomicCounter
00387 {
00388 private:
00389 #ifdef  HAVE_ATOMIC
00390         atomic_t atomic;
00391 #else
00392         int counter;
00393         Mutex lock;
00394 #endif
00395 
00396 public:
00400         AtomicCounter();
00401 
00407         AtomicCounter(int value);
00408 
00409         int operator++(void);
00410         int operator--(void);
00411         int operator+=(int change);
00412         int operator-=(int change);
00413         int operator+(int change);
00414         int operator-(int change);
00415         int operator=(int value);
00416         bool operator!(void);
00417         operator int();
00418 };
00419 
00430 class Conditional : public Mutex
00431 {
00432 protected:
00433         pthread_cond_t _cond;
00434 
00435 public:
00439         Conditional();
00440 
00444         ~Conditional()
00445                 {pthread_cond_destroy(&_cond);};
00446 
00452         void Signal(bool broadcast);
00453 
00457         void Wait(timeout_t timer = 0); 
00458 };
00459 
00477 class Semaphore
00478 {
00479 protected:
00480 #ifdef  _SYSV_SEMAPHORES
00481         int _semaphore;
00482 #else
00483         sem_t _semaphore;
00484 #endif
00485 
00486 public:
00495         Semaphore(size_t resource = 0);
00496 
00503         ~Semaphore()
00504 #if !defined(__linux__) && !defined(_SYSV_SEMAPHORES)
00505                 {sem_destroy(&_semaphore);}
00506 #endif
00507         ;
00508 
00522         void Wait(void)
00523 #if !defined(__linux__) && !defined(_SYSV_SEMAPHORES)
00524                 {sem_wait(&_semaphore);}
00525 #endif
00526         ;
00527 
00539         bool TryWait(void)
00540 #if     !defined(__linux__) && !defined(_SYSV_SEMAPHORES)
00541                 { return ( sem_trywait(&_semaphore) == 0 ) ? true : false; }
00542 #endif
00543         ;
00544         
00556         void Post(void)
00557 #if !defined(__linux__) && !defined(_SYSV_SEMAPHORES)
00558                 {sem_post(&_semaphore);}
00559 #endif
00560         ;
00561 
00567         int getValue(void);
00568 };
00569 
00583 class Event : public Mutex
00584 {
00585 protected:
00586         pthread_cond_t _cond;
00587         bool _signaled;
00588         int _count;
00589 
00590 public:
00591         Event();
00592 
00593         ~Event()
00594                 {pthread_cond_destroy(&_cond);};
00595         
00602         void Reset(void)
00603                 {_signaled = false;};
00604 
00608         void Signal(void);
00617         bool Wait(timeout_t timer = 0);
00618 };
00619 
00641 class Buffer
00642 {
00643 private:
00644         Mutex lock_head, lock_tail;
00645         Semaphore size_head, size_tail;
00646         size_t _size;
00647         size_t _used;
00648 
00649 protected:
00655         virtual int OnPeek(void *buf) = 0;
00661         virtual int OnWait(void *buf) = 0;
00667         virtual int OnPost(void *buf) = 0;
00668 
00669 public:
00674         Buffer(size_t capacity);
00679         virtual ~Buffer()
00680                 {return;};
00681 
00686         inline size_t getSize(void)
00687                 {return _size;};
00688         
00695         inline size_t getUsed(void)
00696                 {return _used;};
00697 
00706         int Wait(void *buf);
00707 
00715         int Post(void *buf);
00716 
00723         int Peek(void *buf);
00724 
00729         virtual bool isValid(void)
00730                 {return true;};
00731 };
00732 
00740 class FixedBuffer : public Buffer
00741 {
00742 private:
00743         char *buf, *head, *tail;
00744         size_t objsize;
00745 
00746 protected:
00752         int OnPeek(void *buf);
00753 
00759         int OnWait(void *buf);
00760 
00766         int OnPost(void *buf);  
00767 
00768 public:
00776         FixedBuffer(size_t capacity, size_t objsize);
00777 
00784         FixedBuffer(const FixedBuffer &fb);
00785 
00789         ~FixedBuffer();
00790 
00791         FixedBuffer &operator=(const FixedBuffer &fb);
00792 
00793         bool isValid(void);
00794 };
00795 
00943 class Thread
00944 {
00945 private:
00946         friend class Slog;
00947 
00948         static Thread *_main;
00949 
00950 #ifndef _SIG_THREAD_ALARM
00951         static Thread *_timer;
00952         static Mutex _arm;
00953 #endif
00954         
00955         Thread *_parent;
00956         pthread_t _tid;
00957         pthread_attr_t _attr;
00958         thread_cancel_t _cancel;
00959         jmp_buf _env;
00960         time_t  _alarm;
00961         Semaphore *_start;
00962         int _msgpos;
00963         char _msgbuf[128];
00964         throw_t _throw;
00965 
00966         friend void execHandler(Thread *th);
00967         friend void sigHandler(int signo);
00968         friend Thread *getThread(void);
00969 
00970 protected:
00980         virtual void Run(void) = 0;
00981 
00988         virtual void First(void)
00989                 {return;};
00990         
01003         virtual void Final(void)
01004                 {return;};
01005 
01016         virtual void Initial(void)
01017                 {return;};
01018         
01028         virtual void *getExtended(void)
01029                 {return NULL;};
01030 
01038         virtual void Notify(Thread *th)
01039                 {return;};
01040 
01047         inline void SignalParent(signo_t signo)
01048                 {_parent->SignalThread(signo);};
01049 
01056         inline void SignalMain(signo_t signo)
01057                 {_main->SignalThread(signo);};
01058 
01063         virtual void OnTimer(void)
01064                 {return;};
01065 
01070         virtual void OnHangup(void)
01071                 {return;};
01072 
01077         virtual void OnException(void)
01078                 {return;};
01079 
01084         virtual void OnDisconnect(void)
01085                 {return;};
01086 
01091         virtual void OnPolling(void)
01092                 {return;};
01093 
01100         virtual void OnSignal(int signo)
01101                 {return;};
01102 
01112         inline void Sleep(timeout_t msec)
01113                 {ccxx_sleep(msec);};
01114 
01120         inline void Exit(void)
01121                 {longjmp(_env, 1);};
01122                
01132         void setTimer(timeout_t timer);
01139         timeout_t getTimer(void);
01145         void endTimer(void);
01152         void WaitSignal(signo_t signo);
01157         void Yield(void);
01161         void testCancel(void);
01170         void setCancel(thread_cancel_t mode);
01178         void setSuspend(thread_suspend_t mode);
01185         void setSignal(int signo, bool mode);
01194         void Terminate(void);
01195 
01199         inline void clrParent(void)
01200                 {_parent = NULL;};
01201 public:
01210         Thread(bool flag);
01223         Thread(Semaphore *start = NULL, int pri = 0, size_t stack = 0);
01231         Thread(const Thread &th);
01238         virtual ~Thread()
01239                 {Terminate();};
01240         
01253         int Start(Semaphore *start = NULL);
01254 
01263         int Detach(Semaphore *start = NULL);
01264 
01271         inline Thread *getParent(void)
01272                 {return _parent;};
01273                 
01279         inline void SignalThread(int signo)
01280                 {pthread_kill(_tid, signo);};
01281 
01288 #ifdef _THR_SUNOS5
01289         inline void Suspend(void)
01290                 {thr_suspend((thread_t)_tid);};
01291 #else
01292         inline void Suspend(void)
01293                 {pthread_kill(_tid, _SIG_THREAD_SUSPEND);};
01294 #endif
01295 
01299 #ifdef  _THR_SUNOS5
01300         inline void Resume(void)
01301                 {thr_continue((thread_t)_tid);};
01302 #else
01303         inline void Resume(void)
01304                 {pthread_kill(_tid, _SIG_THREAD_RESUME);};
01305 #endif
01306 
01313         inline int getCancel(void)
01314                 {return _cancel;};
01315 
01322         bool isRunning(void);
01323 
01330         bool isThread(void);
01331 
01337         friend throw_t getException(void);
01338 
01344         friend void setException(throw_t mode);
01345 
01351         friend void ccxx_sleep(timeout_t msec);
01352 
01358         friend void suspend(Thread &th)
01359                 {pthread_kill(th._tid, _SIG_THREAD_SUSPEND);};
01360 
01366         friend void resume(Thread &th)
01367                 {pthread_kill(th._tid, _SIG_THREAD_RESUME);};
01368 
01375         friend inline void operator++(Thread &th)
01376                 {th._start->Post();};
01377 
01378         friend inline void operator--(Thread &th)
01379                 {th._start->Wait();};
01380 
01384         friend inline int start(Thread &th, Semaphore *start)
01385                 {return th.Start(start);};
01386 
01394         friend void siginstall(int signo);
01395 };
01396 
01411 class ThreadKey
01412 {
01413 private:
01414         pthread_key_t key;
01415 
01416 public:
01420         ThreadKey();
01424         ~ThreadKey();
01432         void *getKey(void);
01440         void setKey(void *);
01441 };
01442 
01453 class TimerPort
01454 {
01455         struct timeval timer;
01456         bool active;
01457 
01458 public:
01465         TimerPort();
01466 
01475         void setTimer(timeout_t timeout = 0);
01476 
01486         void incTimer(timeout_t timeout);
01487 
01493         void endTimer(void);
01494 
01505         timeout_t getTimer(void);
01506 
01515         timeout_t getElapsed(void);
01516 };
01517 
01518 inline void *getKey(ThreadKey &tk)
01519         {return tk.getKey();};
01520 
01521 inline void setKey(ThreadKey &tk, void *ptr)
01522         {tk.setKey(ptr);};
01523 
01524 inline void operator ++(Mutex &m)
01525         {m.EnterMutex();};
01526                 
01527 inline void operator --(Mutex &m)
01528         {m.LeaveMutex();};
01529 
01530 inline void operator ++(Semaphore &s)
01531         {s.Post();};
01532 
01533 inline void operator --(Semaphore &s)
01534         {s.Wait();};
01535 
01536 inline void operator ++(Event &s)
01537         {s.Signal();};
01538 
01539 inline void operator --(Event &s)
01540         {s.Wait();};
01541 
01542 /*
01543  * on some systems, signal(signum, handler) is a macro
01544  */
01545 #undef signal
01546 inline void signal(Thread &th, int signo)
01547         {th.SignalThread(signo);};
01548 
01549 inline void signal(Event &ev)
01550         {ev.Signal();};
01551 
01552 inline void signal(Semaphore &sem)
01553         {sem.Post();};
01554 
01555 inline void wait(Semaphore &sem)
01556         {sem.Wait();};
01557 
01558 inline void wait(Event &ev, timeout_t timer)
01559         {ev.Wait(timer);};
01560 
01561 inline void reset(Event &ev)
01562         {ev.Reset();};
01563 
01564 inline int get(Buffer &b, void *o)
01565         {return b.Wait(o);};
01566 
01567 inline int put(Buffer &b, void *o)
01568         {return b.Post(o);};
01569 
01570 inline int peek(Buffer &b, void *o)
01571         {return b.Peek(o);};
01572 
01573 int operator++(MutexCounter &mc);
01574 int operator--(MutexCounter &mc);
01575 
01576 struct  timespec *gettimeout(struct timespec *spec, timeout_t timeout); 
01577 void    ccxx_sleep(timeout_t msec);
01578 void    ccxx_yield(void);
01579 void    wait(signo_t signo);
01588 void    pdetach(void);
01589 
01590 #ifdef  __CCXX_NAMESPACE_H__
01591 #undef  __CCXX_NAMESPACE_H__
01592 #include <cc++/namespace.h>
01593 #endif
01594 
01595 #if defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H)
01596 #if defined(HAVE_SYS_STREAM_H)
01597 #if defined(__linux__)
01598 #define __CCXX_USE_POLL 1
01599 #endif
01600 #else
01601 #define __CCXX_USE_POLL 1
01602 #endif
01603 #endif
01604 
01605 #ifdef __CCXX_USE_POLL
01606 
01614 class Poller 
01615 {
01616 private:
01617         int nufds;
01618         pollfd *ufds;
01619 
01620 public:
01621         Poller();
01622 
01623         ~Poller();
01624 
01632         pollfd *getList(int cnt);
01633 
01639         inline  pollfd *getList(void)
01640                 {return ufds;};
01641 };
01642 #endif
01643 
01644 
01645 #endif
01646 

Generated at Wed Sep 5 11:25:19 2001 for CommonC++ by doxygen1.2.5 written by Dimitri van Heesch, © 1997-2001