Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound 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 #ifndef CCXX_EXCEPTION_H_
00058 #include <cc++/exception.h>
00059 #endif
00060 
00061 #ifndef WIN32
00062 #if (defined(__FreeBSD__) && __FreeBSD__ <= 3) || defined(_AIX)
00063 #define CCXX_SYSV_SEMAPHORES
00064 #endif
00065 
00066 #ifdef  MACOSX
00067 #define CCXX_NAMED_SEMAPHORES
00068 #define CCXX_BROKEN_SEMGETVALUE
00069 #endif
00070 
00071 #ifndef HAVE_PTHREAD_H
00072 #include <pthread.h>
00073 #ifndef CCXX_SYSV_SEMAPHORES
00074 #include <semaphore.h>
00075 #endif
00076 #endif
00077 #endif // !WIN32
00078 
00079 #undef CCXX_USE_WIN32_ATOMIC
00080 #ifndef WIN32
00081 #include <time.h>
00082 #include <signal.h>
00083 #include <unistd.h>
00084 
00085 #ifdef  _THR_UNIXWARE
00086 #undef  PTHREAD_MUTEXTYPE_RECURSIVE
00087 #endif
00088 
00089 typedef pthread_t       cctid_t;
00090 typedef unsigned long   timeout_t;
00091 
00092 /*
00093 #if defined(__CYGWIN32__) 
00094 __declspec(dllimport) long __stdcall InterlockedIncrement(long *);
00095 __declspec(dllimport) long __stdcall InterlockedDecrement(long *);
00096 __declspec(dllimport) long __stdcall InterlockedExchange(long *, long);
00097 #define CCXX_USE_WIN32_ATOMIC 1
00098 #endif
00099 */
00100 
00101 #else // WIN32
00102 typedef DWORD   cctid_t;
00103 typedef DWORD   timeout_t;
00104 
00105 #define MAX_SEM_VALUE   1000000
00106 #define CCXX_USE_WIN32_ATOMIC 1
00107 #if defined(__CYGWIN32__) 
00108 //#include <Windows32/CommonFunctions.h>
00109 #else
00110 #if _MSC_VER < 1300
00111 __declspec(dllimport) long __stdcall InterlockedIncrement(long *);
00112 __declspec(dllimport) long __stdcall InterlockedDecrement(long *);
00113 __declspec(dllimport) long __stdcall InterlockedExchange(long *, long);
00114 #endif
00115 #endif
00116 
00117 #endif // !WIN32
00118 
00119 #ifdef  CCXX_NAMESPACES
00120 namespace ost {
00121 #endif
00122 
00123 class CCXX_CLASS_EXPORT Thread;
00124 class CCXX_CLASS_EXPORT ThreadKey;
00125 
00126 #define TIMEOUT_INF ~((timeout_t) 0)
00127 
00128 #define ENTER_CRITICAL  enterMutex();
00129 #define LEAVE_CRITICAL  leaveMutex();
00130 #define ENTER_DEFERRED  setCancel(cancelDeferred);
00131 #define LEAVE_DEFERRED  setCancel(cancelImmediate);
00132 
00133 #ifndef WIN32
00134 // These macros override common functions with thread-safe versions. In
00135 // particular the common "libc" sleep() has problems since it normally
00136 // uses SIGARLM (as actually defined by "posix").  The pthread_delay and
00137 // usleep found in libpthread are gaurenteed not to use SIGALRM and offer
00138 // higher resolution.  psleep() is defined to call the old process sleep.
00139 
00140 #undef  sleep
00141 #define psleep(x)       (sleep)(x)
00142 
00143 #endif // !WIN32
00144 
00145 #undef Yield
00146 
00147 #ifdef WIN32
00148 CCXX_EXPORT(DWORD) waitThread(HANDLE hRef, timeout_t timeout);
00149 #endif
00150 
00151 class Conditional;
00152 class CCXX_CLASS_EXPORT Event;
00153 
00197 class CCXX_CLASS_EXPORT Mutex
00198 {
00199         friend class Conditional;
00200         friend class Event;
00201 private:
00202 #ifndef WIN32
00203 #ifndef PTHREAD_MUTEXTYPE_RECURSIVE
00204         volatile int _level;
00205         volatile Thread *_tid;
00206 #endif
00207         /*
00208          * Pthread mutex object.  This is protected rather than private
00209          * because some mixed mode pthread operations require a mutex as
00210          * well as their primary pthread object.  A good example of this
00211          * is the Event class, as waiting on a conditional object must be
00212          * associated with an accessable mutex.  An alternative would be
00213          * to make such classes "friend" classes of the Mutex.
00214          */
00215         pthread_mutex_t _mutex;
00216 #else
00217         HANDLE mutex;
00218 #endif
00219 
00220 public:
00224         Mutex();
00225 
00231         virtual ~Mutex();
00232 
00240         void enterMutex(void);
00241 
00252         bool tryEnterMutex(void);
00253 
00264         void leaveMutex(void);
00265 };
00266 
00288 class MutexLock
00289 {
00290 private:
00291         Mutex& mutex;
00292 public:
00296         MutexLock( Mutex& _mutex ) : mutex( _mutex ) 
00297                 { mutex.enterMutex(); }
00301         // this should be not-virtual
00302         ~MutexLock()
00303                 { mutex.leaveMutex(); }
00304 };
00305 
00314 class CCXX_CLASS_EXPORT ThreadLock
00315 {
00316 private:
00317 #ifdef HAVE_PTHREAD_RWLOCK
00318         pthread_rwlock_t _lock;
00319 #else
00320         Mutex mutex;
00321 #endif
00322 
00323 public:
00327         ThreadLock();
00328 
00332         virtual ~ThreadLock();
00333 
00337         void readLock(void);
00338 
00342         void writeLock(void);
00343 
00349         bool tryReadLock(void);
00350 
00356         bool tryWriteLock(void);
00357 
00361         void unlock(void);
00362 };
00363 
00373 class CCXX_CLASS_EXPORT MutexCounter : public Mutex
00374 {
00375 private:
00376         int     counter;
00377 
00378 public:
00379         MutexCounter();
00380         MutexCounter(int initial);
00381 
00382         friend CCXX_EXPORT(int) operator++(MutexCounter &mc);
00383         friend CCXX_EXPORT(int) operator--(MutexCounter &mc);
00384 };
00385 
00396 class CCXX_CLASS_EXPORT AtomicCounter
00397 {
00398 #ifndef CCXX_USE_WIN32_ATOMIC
00399 private:
00400 #ifdef  HAVE_ATOMIC
00401         atomic_t atomic;
00402 #else
00403         int counter;
00404         Mutex lock;
00405 #endif
00406 
00407 public:
00411         AtomicCounter();
00412 
00418         AtomicCounter(int value);
00419 
00420         int operator++(void);
00421         int operator--(void);
00422         int operator+=(int change);
00423         int operator-=(int change);
00424         int operator+(int change);
00425         int operator-(int change);
00426         int operator=(int value);
00427         bool operator!(void);
00428         operator int();
00429 #else
00430 private:
00431         long atomic;
00432 
00433 public:
00434         inline AtomicCounter()
00435                 {atomic = 0;};
00436 
00437         inline AtomicCounter(int value)
00438                 {atomic = value;};
00439 
00440         inline int operator++(void)
00441                 {return InterlockedIncrement(&atomic);};
00442 
00443         inline int operator--(void)
00444                 {return InterlockedDecrement(&atomic);};
00445 
00446         int operator+=(int change);
00447 
00448         int operator-=(int change);
00449 
00450         inline int operator+(int change)
00451                 {return atomic + change;};
00452 
00453         inline int operator-(int change)
00454                 {return atomic - change;};
00455         
00456         inline int operator=(int value)
00457                 {return InterlockedExchange(&atomic, value);};
00458 
00459         inline bool operator!(void)
00460                 {return (atomic == 0) ? true : false;};
00461 
00462         inline operator int()
00463                 {return atomic;};
00464 #endif
00465 };
00466 
00467 #ifndef WIN32
00468 
00488 class Conditional : public Mutex
00489 {
00490 private:
00491         pthread_cond_t _cond;
00492 
00493 public:
00497         Conditional();
00498 
00502         virtual ~Conditional();
00503 
00509         void signal(bool broadcast);
00510 
00514         void wait(timeout_t timer = 0); 
00515 };
00516 #endif
00517 
00535 class CCXX_CLASS_EXPORT Semaphore
00536 {
00537 private:
00538 #ifndef WIN32
00539 #ifdef  CCXX_SYSV_SEMAPHORES
00540         int _semaphore;
00541 #else
00542         sem_t _semaphore;
00543         sem_t *_semobject;
00544 #endif
00545 #else // WIN32
00546         HANDLE  semObject;
00547 #endif // !WIN32
00548 
00549 public:
00558         Semaphore(size_t resource = 0);
00559 
00566         virtual ~Semaphore();
00567 
00581         void wait(void);
00582 
00594         bool tryWait(void);
00595 
00607         void post(void);
00608 
00609         // FIXME: how implement getValue for posix compatibility ?
00615 #ifndef WIN32
00616 #ifndef __CYGWIN32__
00617         int getValue(void);
00618 #endif
00619 #endif
00620 };
00621 
00635 class CCXX_CLASS_EXPORT Event
00636 {
00637 private:
00638 #ifndef WIN32
00639         Mutex mutex;
00640         pthread_cond_t _cond;
00641         bool _signaled;
00642         int _count;
00643 #else
00644         HANDLE cond;
00645 #endif
00646 
00647 public:
00648         Event();
00649 
00650         virtual ~Event();
00651 
00658         void reset(void);
00659 
00663         void signal(void);
00664 
00673         bool wait(timeout_t timer);
00674         bool wait(void);
00675 };
00676 
00698 class CCXX_CLASS_EXPORT Buffer
00699 {
00700 private:
00701         Mutex lock_head, lock_tail;
00702         Semaphore size_head, size_tail;
00703         size_t _size;
00704         size_t _used;
00705 
00706 protected:
00712         virtual int onPeek(void *buf) = 0;
00718         virtual int onWait(void *buf) = 0;
00724         virtual int onPost(void *buf) = 0;
00725 
00726 public:
00731         Buffer(size_t capacity);
00736         virtual ~Buffer()
00737                 {return;};
00738 
00743         inline size_t getSize(void)
00744                 {return _size;};
00745         
00752         inline size_t getUsed(void)
00753                 {return _used;};
00754 
00763         int wait(void *buf);
00764 
00772         int post(void *buf);
00773 
00780         int peek(void *buf);
00781 
00786         virtual bool isValid(void)
00787                 {return true;};
00788 };
00789 
00797 class CCXX_CLASS_EXPORT FixedBuffer : public Buffer
00798 {
00799 private:
00800         char *buf, *head, *tail;
00801         size_t objsize;
00802 
00803 protected:
00809         int onPeek(void *buf);
00810 
00816         int onWait(void *buf);
00817 
00823         int onPost(void *buf);  
00824 
00825 public:
00833         FixedBuffer(size_t capacity, size_t objsize);
00834 
00841         FixedBuffer(const FixedBuffer &fb);
00842 
00846         virtual ~FixedBuffer();
00847 
00848         FixedBuffer &operator=(const FixedBuffer &fb);
00849 
00850         bool isValid(void);
00851 };
00852 
01034 class CCXX_CLASS_EXPORT Thread
01035 {
01036 public:
01040         typedef enum Throw {
01041                 throwNothing,  
01042                 throwObject,   
01043                 throwException 
01044         } Throw;
01045         
01049         typedef enum Cancel
01050         {
01051                 cancelInitial=0,  
01052                 cancelDeferred=1, 
01053                 cancelImmediate,  
01054                 cancelDisabled,   
01055                 cancelManual,     
01057                 cancelDefault=cancelDeferred
01059         } Cancel;
01060 
01064         typedef enum Suspend
01065         {
01066                 suspendEnable, 
01067                 suspendDisable 
01068         } Suspend;
01069 
01070 #ifndef WIN32
01071 
01072 friend class PosixThread;
01073 #endif
01074 
01075 friend class DummyThread;
01076 private:
01077         friend class Slog;
01078 
01079         Semaphore joinSem;
01080         static Thread* _main;
01081 
01082         Thread *_parent;
01083         enum Cancel _cancel;
01084         Semaphore *_start;
01085 
01086         // private data
01087         friend class ThreadImpl;
01088         class ThreadImpl* priv;
01089 
01090 #ifndef WIN32
01091         friend Thread *getThread(void);
01092 #else
01093         static unsigned __stdcall Execute(Thread *th);
01094 #endif
01095 
01096         // close current thread, free all and call Notify
01097         void close();
01098         
01099 protected:
01109         virtual void run(void) = 0;
01110 
01132         virtual void final(void)
01133                 {return;};
01134 
01146         virtual void initial(void)
01147                 {return;};
01148 
01158         virtual void* getExtended(void)
01159                 {return NULL;};
01160 
01168         virtual void notify(Thread*)
01169                 {return;};
01170 
01176         void exit(void);
01177 
01181         bool testCancel(void);
01182 
01192         void setCancel(Cancel mode);
01193 
01201         void setSuspend(Suspend mode);
01202 
01211         void terminate(void);
01212 
01216         inline void clrParent(void)
01217                 {_parent = NULL;};
01218 
01219 #ifdef WIN32
01220         // FIXME: should be private
01221         DWORD waitHandle(HANDLE obj, timeout_t timeout);
01222 #endif
01223 
01224 public:
01233         Thread(bool isMain);
01234 
01246         Thread(int pri = 0, size_t stack = 0);
01247 
01248 #ifndef WIN32
01249 
01257         Thread(const Thread &th);
01258 #endif
01259 
01266         virtual ~Thread();
01267 
01277         static void sleep(timeout_t msec);
01278 
01283         static void yield(void);
01284 
01297         int start(Semaphore *start = 0);
01298 
01307         int detach(Semaphore *start = 0);
01308 
01315         inline Thread *getParent(void)
01316                 {return _parent;};
01317 
01324         void suspend(void);
01325 
01329         void resume(void);
01330 
01337         inline Cancel getCancel(void)
01338                 {return _cancel;};
01339 
01346         bool isRunning(void);
01347 
01353         bool isDetached(void);
01354 
01358         void join(void);
01359 
01366         bool isThread(void);
01367 
01373         friend CCXX_EXPORT(Throw) getException(void);
01374 
01380         friend CCXX_EXPORT(void) setException(Throw mode);
01381 
01388         friend inline void operator++(Thread &th)
01389                 {if (th._start) th._start->post();};
01390 
01391         friend inline void operator--(Thread &th)
01392                 {if (th._start) th._start->wait();};
01393 
01394 #ifdef WIN32
01395         // FIXME: not defined in posix
01396         bool isCancelled();
01397 
01398         friend CCXX_EXPORT(DWORD) waitThread(HANDLE hRef, timeout_t timeout);
01399 #endif
01400 };
01401 
01407 CCXX_EXPORT(Thread*) getThread(void);
01409 CCXX_EXPORT(Thread::Throw) getException(void);
01411 CCXX_EXPORT(void) setException(Thread::Throw mode);
01412 
01413 #if !defined(WIN32) && !defined(__MINGW32__)
01414 typedef int             signo_t;
01415 
01416 class PosixThread: public Thread
01417 {
01418 private:
01419 #ifndef WIN32
01420 
01421         friend class ThreadImpl;
01422         friend class Thread;
01423 #endif
01424 #ifndef CCXX_SIG_THREAD_ALARM
01425         static PosixThread *_timer;
01426         static Mutex _arm;
01427 #endif
01428         
01429         time_t  _alarm;
01430         static void signalThread(Thread* th,signo_t signo);
01431 protected:
01432                 
01439         inline void signalParent(signo_t signo)
01440                 { signalThread(_parent,signo); };
01441         
01448         inline void signalMain(signo_t signo)
01449                 { signalThread(_main,signo);};
01450 
01455         virtual void onTimer(void)
01456                 {return;};
01457 
01462         virtual void onHangup(void)
01463                 {return;};
01464 
01469         virtual void onException(void)
01470                 {return;};
01471 
01476         virtual void onDisconnect(void)
01477                 {return;};
01478 
01483         virtual void onPolling(void)
01484                 {return;};
01485 
01492         virtual void onSignal(int)
01493                 {return;};
01494         
01507         void setTimer(timeout_t timer, bool periodic = false);
01508         
01515         timeout_t getTimer(void) const;
01516         
01522         void endTimer(void);
01523         
01530         void waitSignal(signo_t signo);
01531         
01538         void setSignal(int signo, bool active);
01539 public:
01540 
01541         CCXX_MEMBER_EXPORT(CCXX_EMPTY) PosixThread(int pri = 0, size_t stack = 0);
01542         
01548         inline void signalThread(int signo)
01549                 {signalThread(this, signo);};
01550 
01557         friend void sigInstall(int signo);
01558 };
01559 #endif
01560 
01575 class ThreadKey
01576 {
01577 private:
01578 #ifndef WIN32
01579         pthread_key_t key;
01580         typedef void (*TDestruct)(void*);
01581         friend class ThreadImpl;
01582         ThreadKey(TDestruct destruct);
01583 #else
01584         DWORD   key;
01585 #endif
01586 
01587 public:
01591         ThreadKey();
01595         virtual ~ThreadKey();
01603         void *getKey(void);
01611         void setKey(void *);
01612 };
01613 
01624 class CCXX_CLASS_EXPORT TimerPort
01625 {
01626 #ifndef WIN32
01627         struct timeval timer;
01628 #else
01629         DWORD timer;
01630 #endif
01631         bool active;
01632 
01633 public:
01640         TimerPort();
01641 
01650         void setTimer(timeout_t timeout = 0);
01651 
01661         void incTimer(timeout_t timeout);
01662 
01668         void endTimer(void);
01669 
01681         timeout_t getTimer(void) const;
01682 
01692         timeout_t getElapsed(void) const;
01693 };
01694 
01696 inline int get(Buffer &b, void *o)
01697         {return b.wait(o);};
01698 
01700 inline int put(Buffer &b, void *o)
01701         {return b.post(o);};
01702 
01704 inline int peek(Buffer &b, void *o)
01705         {return b.peek(o);};
01706 
01707 
01708 // FIXME: not in win32 implementation
01709 #if !defined(WIN32)
01710 
01711 // FIXME: private declaration ???
01712 struct  timespec *getTimeout(struct timespec *spec, timeout_t timeout); 
01713 
01714 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
01715 void    wait(signo_t signo);
01716 #endif
01717 
01718 #endif // !WIN32
01719 
01720 // FIXME: no way to implement in win32
01721 #ifndef WIN32
01722 #if defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H)
01723 #if defined(HAVE_SYS_STREAM_H)
01724 #if defined(__linux__)
01725 #define CCXX_USE_POLL 1
01726 #endif
01727 #else
01728 #define CCXX_USE_POLL 1
01729 #endif
01730 #endif
01731 
01732 #ifdef CCXX_USE_POLL
01733 
01741 class Poller 
01742 {
01743 private:
01744         int nufds;
01745         pollfd *ufds;
01746 
01747 public:
01748         Poller();
01749 
01750         virtual ~Poller();
01751 
01759         pollfd *getList(int cnt);
01760 
01766         inline  pollfd *getList(void)
01767                 {return ufds;};
01768 };
01769 #endif
01770 #endif // !WIN32
01771 
01772 #ifdef  COMMON_STD_EXCEPTION
01773 
01779 class ThrException : public Exception
01780 {
01781 public:
01782         ThrException(const std::string &what_arg) : Exception(what_arg) {};
01783 };
01784 
01791 class SyncException : public ThrException
01792 {
01793 public:
01794         SyncException(const std::string &what_arg) : ThrException(what_arg) {};
01795 };
01796 
01797 class InterruptException : public ThrException
01798 {
01799 public:
01800         InterruptException() : ThrException("interrupted") {};
01801 };
01802 
01803 #endif
01804 
01805 // dummy class objects needed to make MACOSX reliably link Common C++
01806 // shared libraries.  This is very bizzare, but works for images that
01807 // reference cc++ functions on macosx but otherwise do not execute since
01808 // the cc++ shared libs and constructors are never fully linked?! by the
01809 // macosx dynamic loader...
01810 
01811 #ifdef  CCXX_NAMESPACES
01812 };
01813 #endif
01814 
01815 #endif
01816 

Generated on Thu Sep 25 13:14:31 2003 for GNU CommonC++ by doxygen 1.3.3