Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   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 #ifndef CCXX_THREAD_H_
00042 #define CCXX_THREAD_H_
00043 
00044 #ifndef WIN32
00045 #define CCXX_POSIX
00046 #endif // !WIN32
00047 
00048 #ifndef CCXX_CONFIG_H_
00049 #include <cc++/config.h>
00050 #endif
00051 
00052 #ifndef CCXX_EXCEPTION_H_
00053 #include <cc++/exception.h>
00054 #endif
00055 
00056 #ifndef WIN32
00057 #if defined(__FreeBSD__) && __FreeBSD__ <= 3
00058 #define CCXX_SYSV_SEMAPHORES
00059 #endif
00060 
00061 #ifndef HAVE_PTHREAD_H
00062 #include <pthread.h>
00063 #ifndef CCXX_SYSV_SEMAPHORES
00064 #include <semaphore.h>
00065 #endif
00066 #endif
00067 #endif // !WIN32
00068 
00069 #include <setjmp.h> // for jmp_buf, longjmp
00070 
00071 #ifndef WIN32
00072 #include <time.h>
00073 #include <signal.h>
00074 #include <unistd.h>
00075 
00076 #ifdef  __linux__
00077 #define CCXX_SIG_THREAD_ALARM
00078 #define CCXX_SIG_THREAD_STOPCONT 
00079 #endif
00080 
00081 #ifdef  _THR_UNIXWARE
00082 #undef  PTHREAD_MUTEXTYPE_RECURSIVE
00083 #endif
00084 
00085 typedef pthread_t       cctid_t;
00086 typedef unsigned long   timeout_t;
00087 #else // WIN32
00088 typedef DWORD   cctid_t;
00089 typedef DWORD   timeout_t;
00090 
00091 #define MAX_SEM_VALUE   1000000
00092 #if defined(__MINGW32__) || defined(__CYGWIN32__)
00093 #include <Windows32/CommonFunctions.h>
00094 #else
00095 __declspec(dllimport) long __stdcall InterlockedIncrement(long *);
00096 __declspec(dllimport) long __stdcall InterlockedDecrement(long *);
00097 __declspec(dllimport) long __stdcall InterlockedExchange(long *, long);
00098 #endif
00099 
00100 #endif // !WIN32
00101 
00102 #ifdef  CCXX_NAMESPACES
00103 namespace ost {
00104 #endif
00105 
00106 enum throw_t {
00107         THROW_NOTHING, 
00108         THROW_OBJECT, 
00109         THROW_EXCEPTION
00110 };
00111 typedef enum throw_t throw_t;
00112 class Thread;
00113 
00114 #define TIMEOUT_INF ~((timeout_t) 0)
00115 
00116 #define ENTER_CRITICAL  EnterMutex();
00117 #define LEAVE_CRITICAL  LeaveMutex();
00118 #define ENTER_DEFERRED  setCancel(THREAD_CANCEL_DEFERRED);
00119 #define LEAVE_DEFERRED  setCancel(THREAD_CANCEL_IMMEDIATE);
00120 
00121 enum thread_cancel_t
00122 {
00123         THREAD_CANCEL_INITIAL=0,
00124         THREAD_CANCEL_DEFERRED=1,
00125         THREAD_CANCEL_IMMEDIATE,
00126         THREAD_CANCEL_DISABLED,
00127         THREAD_CANCEL_DEFAULT=THREAD_CANCEL_DEFERRED
00128 };
00129 typedef enum thread_cancel_t thread_cancel_t;
00130 
00131 enum thread_suspend_t
00132 {
00133         THREAD_SUSPEND_ENABLE,
00134         THREAD_SUSPEND_DISABLE
00135 };
00136 typedef enum thread_suspend_t thread_suspend_t;
00137 
00138 #ifndef WIN32
00139 // These macros override common functions with thread-safe versions. In
00140 // particular the common "libc" sleep() has problems since it normally
00141 // uses SIGARLM (as actually defined by "posix").  The pthread_delay and
00142 // usleep found in libpthread are gaurenteed not to use SIGALRM and offer
00143 // higher resolution.  psleep() is defined to call the old process sleep.
00144 
00145 #undef  sleep
00146 #define psleep(x)       (sleep)(x)
00147 
00148 #ifndef CCXX_SIG_THREAD_STOPCONT
00149 #ifndef _THR_SUNOS5
00150 static RETSIGTYPE ccxx_sigsuspend(int);
00151 #endif
00152 #endif
00153 extern "C" void execHandler(Thread *th);
00154 
00155 #endif // !WIN32
00156 
00157 
00158 CCXX_EXPORT(Thread*) getThread(void);
00159 CCXX_EXPORT(throw_t) getException(void);
00160 CCXX_EXPORT(void) setException(throw_t mode);
00161 CCXX_EXPORT(void) ccxx_sleep(timeout_t msec);
00162 CCXX_EXPORT(void) ccxx_yield(void);
00163 
00164 #undef Yield
00165 #define sleep(x)        ccxx_sleep((x) * 1000)
00166 #define yield()         ccxx_yield()
00167 
00168 #ifdef WIN32
00169 CCXX_EXPORT(DWORD) waitThread(HANDLE hRef, timeout_t timeout);
00170 #endif
00171 
00172 class Conditional;
00173 class CCXX_CLASS_EXPORT Event;
00174 
00218 class CCXX_CLASS_EXPORT Mutex
00219 {
00220         friend class Conditional;
00221         friend class Event;
00222 private:
00223 #ifndef WIN32
00224 #ifndef PTHREAD_MUTEXTYPE_RECURSIVE
00225         volatile int _level;
00226         volatile Thread *_tid;
00227 #endif
00228 
00236         pthread_mutex_t _mutex;
00237 #else
00238         HANDLE mutex;
00239 #endif
00240 
00241 public:
00245         Mutex();
00246 
00252         virtual ~Mutex();
00253 
00261         void EnterMutex(void);
00262 
00273         bool TryEnterMutex(void);
00274 
00285         void LeaveMutex(void);
00286 };
00287 
00309 class MutexLock
00310 {
00311 private:
00312         Mutex& mutex;
00313 public:
00317         MutexLock( Mutex& _mutex ) : mutex( _mutex ) 
00318                 { mutex.EnterMutex(); }
00322         // this should be not-virtual
00323         ~MutexLock()
00324                 { mutex.LeaveMutex(); }
00325 };
00326 
00335 class CCXX_CLASS_EXPORT ThreadLock
00336 {
00337 private:
00338 #ifdef HAVE_PTHREAD_RWLOCK
00339         pthread_rwlock_t _lock;
00340 #else
00341         Mutex mutex;
00342 #endif
00343 
00344 public:
00348         ThreadLock();
00349 
00353         virtual ~ThreadLock();
00354 
00358         void ReadLock(void);
00359 
00363         void WriteLock(void);
00364 
00370         bool TryReadLock(void);
00371 
00377         bool TryWriteLock(void);
00378 
00382         void Unlock(void);
00383 };
00384 
00394 class CCXX_CLASS_EXPORT MutexCounter : public Mutex
00395 {
00396 private:
00397         int     counter;
00398 
00399 public:
00400         MutexCounter();
00401         MutexCounter(int initial);
00402 
00403         friend CCXX_EXPORT(int) operator++(MutexCounter &mc);
00404         friend CCXX_EXPORT(int) operator--(MutexCounter &mc);
00405 };
00406 
00417 class CCXX_CLASS_EXPORT AtomicCounter
00418 {
00419 #ifndef WIN32
00420 private:
00421 #ifdef  HAVE_ATOMIC
00422         atomic_t atomic;
00423 #else
00424         int counter;
00425         Mutex lock;
00426 #endif
00427 
00428 public:
00432         AtomicCounter();
00433 
00439         AtomicCounter(int value);
00440 
00441         int operator++(void);
00442         int operator--(void);
00443         int operator+=(int change);
00444         int operator-=(int change);
00445         int operator+(int change);
00446         int operator-(int change);
00447         int operator=(int value);
00448         bool operator!(void);
00449         operator int();
00450 #else
00451 private:
00452         long atomic;
00453 
00454 public:
00455         inline AtomicCounter()
00456                 {atomic = 0;};
00457 
00458         inline AtomicCounter(int value)
00459                 {atomic = value;};
00460 
00461         inline int operator++(void)
00462                 {return InterlockedIncrement(&atomic);};
00463 
00464         inline int operator--(void)
00465                 {return InterlockedDecrement(&atomic);};
00466 
00467         int operator+=(int change);
00468 
00469         int operator-=(int change);
00470 
00471         inline int operator+(int change)
00472                 {return atomic + change;};
00473 
00474         inline int operator-(int change)
00475                 {return atomic - change;};
00476         
00477         inline int operator=(int value)
00478                 {return InterlockedExchange(&atomic, value);};
00479 
00480         inline bool operator!(void)
00481                 {return (atomic == 0) ? true : false;};
00482 
00483         inline operator int()
00484                 {return atomic;};
00485 #endif
00486 };
00487 
00488 // FIXME: implement Conditional class for win32
00489 #ifndef WIN32
00490 
00500 class Conditional : public Mutex
00501 {
00502 private:
00503         pthread_cond_t _cond;
00504 
00505 public:
00509         Conditional();
00510 
00514         virtual ~Conditional();
00515 
00521         void Signal(bool broadcast);
00522 
00526         void Wait(timeout_t timer = 0); 
00527 };
00528 #endif
00529 
00547 class CCXX_CLASS_EXPORT Semaphore
00548 {
00549 private:
00550 #ifndef WIN32
00551 #ifdef  CCXX_SYSV_SEMAPHORES
00552         int _semaphore;
00553 #else
00554         sem_t _semaphore;
00555 #endif
00556 #else // WIN32
00557         HANDLE  semObject;
00558 #endif // !WIN32
00559 
00560 public:
00569         Semaphore(size_t resource = 0);
00570 
00577         virtual ~Semaphore();
00578 
00592         void Wait(void);
00593 
00605         bool TryWait(void);
00606 
00618         void Post(void);
00619 
00620         // FIXME: how implement getValue for posix compatibility ?
00626 #ifndef WIN32
00627 #ifndef __CYGWIN32__
00628         int getValue(void);
00629 #endif
00630 #endif
00631 };
00632 
00646 class CCXX_CLASS_EXPORT Event
00647 {
00648 private:
00649 #ifndef WIN32
00650         Mutex mutex;
00651         pthread_cond_t _cond;
00652         bool _signaled;
00653         int _count;
00654 #else
00655         HANDLE cond;
00656 #endif
00657 
00658 public:
00659         Event();
00660 
00661         virtual ~Event();
00662 
00669         void Reset(void);
00670 
00674         void Signal(void);
00675 
00684         bool Wait(timeout_t timer);
00685         bool Wait(void);
00686 };
00687 
00709 class CCXX_CLASS_EXPORT Buffer
00710 {
00711 private:
00712         Mutex lock_head, lock_tail;
00713         Semaphore size_head, size_tail;
00714         size_t _size;
00715         size_t _used;
00716 
00717 protected:
00723         virtual int OnPeek(void *buf) = 0;
00729         virtual int OnWait(void *buf) = 0;
00735         virtual int OnPost(void *buf) = 0;
00736 
00737 public:
00742         Buffer(size_t capacity);
00747         virtual ~Buffer()
00748                 {return;};
00749 
00754         inline size_t getSize(void)
00755                 {return _size;};
00756         
00763         inline size_t getUsed(void)
00764                 {return _used;};
00765 
00774         int Wait(void *buf);
00775 
00783         int Post(void *buf);
00784 
00791         int Peek(void *buf);
00792 
00797         virtual bool isValid(void)
00798                 {return true;};
00799 };
00800 
00808 class CCXX_CLASS_EXPORT FixedBuffer : public Buffer
00809 {
00810 private:
00811         char *buf, *head, *tail;
00812         size_t objsize;
00813 
00814 protected:
00820         int OnPeek(void *buf);
00821 
00827         int OnWait(void *buf);
00828 
00834         int OnPost(void *buf);  
00835 
00836 public:
00844         FixedBuffer(size_t capacity, size_t objsize);
00845 
00852         FixedBuffer(const FixedBuffer &fb);
00853 
00857         virtual ~FixedBuffer();
00858 
00859         FixedBuffer &operator=(const FixedBuffer &fb);
00860 
00861         bool isValid(void);
00862 };
00863 
01011 class Thread
01012 {
01013 #ifndef WIN32
01014 friend class PosixThread;
01015 friend RETSIGTYPE ccxx_sigsuspend(int);
01016 #endif
01017 private:
01018         friend class Slog;
01019 
01020         static Thread *_main;
01021 
01022         Thread *_parent;
01023 #ifndef WIN32
01024         pthread_t _tid;
01025         pthread_attr_t _attr;
01026         AtomicCounter _suspendcount;
01027 #else
01028         DWORD _tid;
01029         HANDLE _cancellation;
01030 #endif
01031         thread_cancel_t _cancel;
01032         jmp_buf _env;
01033         Semaphore *_start;
01034         int _msgpos;
01035         char _msgbuf[128];
01036         throw_t _throw;
01037 
01038 #ifndef WIN32
01039         friend void execHandler(Thread *th);
01040         friend Thread *getThread(void);
01041 #else
01042         bool _active:1;
01043         bool _suspendEnable:1;
01044         static unsigned __stdcall Execute(Thread *th);
01045         HANDLE  _hThread;
01046 #endif
01047 
01048 protected:
01058         virtual void Run(void) = 0;
01059 
01072         CCXX_MEMBER_EXPORT(virtual void) Final(void)
01073                 {return;};
01074 
01085         CCXX_MEMBER_EXPORT(virtual void) Initial(void)
01086                 {return;};
01087 
01097         CCXX_MEMBER_EXPORT(virtual void*) getExtended(void)
01098                 {return NULL;};
01099 
01107         CCXX_MEMBER_EXPORT(virtual void) Notify(Thread *th)
01108                 {return;};
01109 
01119         CCXX_MEMBER_EXPORT(void) Sleep(timeout_t msec)
01120 #ifndef WIN32
01121                 {ccxx_sleep(msec);}
01122 #endif
01123         ;
01124 
01125         // FIXME: _env can not initialized
01131         inline void Exit(void)
01132                 {longjmp(_env, 1);};
01133 
01138         CCXX_MEMBER_EXPORT(void) Yield(void);
01139 
01143         CCXX_MEMBER_EXPORT(void) testCancel(void);
01144 
01153         CCXX_MEMBER_EXPORT(void) setCancel(thread_cancel_t mode);
01154 
01162         CCXX_MEMBER_EXPORT(void) setSuspend(thread_suspend_t mode);
01163 
01172         CCXX_MEMBER_EXPORT(void) Terminate(void);
01173 
01177         inline void clrParent(void)
01178                 {_parent = NULL;};
01179 
01180 #ifdef WIN32
01181         // FIXME: should be private
01182         CCXX_MEMBER_EXPORT(DWORD) WaitHandle(HANDLE obj, timeout_t timeout);
01183 #endif
01184 
01185 public:
01194         CCXX_MEMBER_EXPORT(CCXX_EMPTY) Thread(bool isMain);
01195 
01208         CCXX_MEMBER_EXPORT(CCXX_EMPTY) Thread(int pri = 0, size_t stack = 0);
01209 
01210         // FIXME: win32 lack copy constructor
01211 #ifndef WIN32
01212 
01219         Thread(const Thread &th);
01220 #endif
01221 
01228         CCXX_MEMBER_EXPORT(virtual) ~Thread()
01229                 {Terminate();};
01230 
01243         CCXX_MEMBER_EXPORT(int) Start(Semaphore *start = 0);
01244 
01253         CCXX_MEMBER_EXPORT(int) Detach(Semaphore *start = 0);
01254 
01261         inline Thread *getParent(void)
01262                 {return _parent;};
01263 
01270         CCXX_MEMBER_EXPORT(void) Suspend(void);
01271 
01275         CCXX_MEMBER_EXPORT(void) Resume(void);
01276 
01283         inline thread_cancel_t getCancel(void)
01284                 {return _cancel;};
01285 
01292         bool isRunning(void)
01293 #ifdef WIN32
01294                 {return (_tid != 0) ? true : false;}
01295 #endif
01296         ;
01297 
01304         bool isThread(void)
01305 #ifdef WIN32
01306                 {return ((_tid == GetCurrentThreadId())) ? true : false;}
01307 #endif
01308         ;
01309 
01315         friend CCXX_EXPORT(throw_t) getException(void);
01316 
01322         friend CCXX_EXPORT(void) setException(throw_t mode);
01323 
01324         // FIXME: _start can be NULL
01331         friend inline void operator++(Thread &th)
01332                 {th._start->Post();};
01333 
01334         friend inline void operator--(Thread &th)
01335                 {th._start->Wait();};
01336 
01342         friend CCXX_EXPORT(void) ccxx_sleep(timeout_t msec);
01343 
01347         friend CCXX_EXPORT(void) ccxx_yield(void);
01348 
01349 #ifdef WIN32
01350         // FIXME: not defined in posix
01351         inline bool isCancelled(void)
01352                 {return waitThread(_cancellation, 0) == WAIT_OBJECT_0; };
01353 
01354         inline bool isCancelled(timeout_t timer)
01355                 {return waitThread(_cancellation, timer) == WAIT_OBJECT_0; };
01356                 
01357         friend CCXX_EXPORT(DWORD) waitThread(HANDLE hRef, timeout_t timeout);
01358 #endif
01359 };
01360 
01361 #ifndef WIN32
01362 extern "C" void sigHandler(int signo);
01363 
01364 typedef int             signo_t;
01365 
01366 class PosixThread: public Thread
01367 {
01368 private:
01369 #ifndef WIN32
01370         friend void execHandler(Thread *th);
01371 #endif
01372 #ifndef CCXX_SIG_THREAD_ALARM
01373         static PosixThread *_timer;
01374         static Mutex _arm;
01375 #endif
01376         
01377         time_t  _alarm;
01378         friend void sigHandler(int signo);
01379         inline static void SignalThread(Thread* th,signo_t signo)
01380                 {pthread_kill(th->_tid, signo);};
01381 protected:
01382                 
01389         inline void SignalParent(signo_t signo)
01390                 { SignalThread(_parent,signo); };
01391         
01398         inline void SignalMain(signo_t signo)
01399                 { SignalThread(_main,signo);};
01400 
01405         virtual void OnTimer(void)
01406                 {return;};
01407 
01412         virtual void OnHangup(void)
01413                 {return;};
01414 
01419         virtual void OnException(void)
01420                 {return;};
01421 
01426         virtual void OnDisconnect(void)
01427                 {return;};
01428 
01433         virtual void OnPolling(void)
01434                 {return;};
01435 
01442         virtual void OnSignal(int signo)
01443                 {return;};
01444         
01454         void setTimer(timeout_t timer);
01455         
01462         timeout_t getTimer(void);
01463         
01469         void endTimer(void);
01470         
01477         void WaitSignal(signo_t signo);
01478         
01485         void setSignal(int signo, bool mode);
01486 public:
01487         
01493         inline void SignalThread(int signo)
01494                 {SignalThread(this, signo);};
01495 
01502         friend void siginstall(int signo);
01503 };
01504 #endif
01505 
01520 class CCXX_CLASS_EXPORT ThreadKey
01521 {
01522 private:
01523 #ifndef WIN32
01524         pthread_key_t key;
01525 #else
01526         DWORD   key;
01527 #endif
01528 
01529 public:
01533         ThreadKey();
01537         virtual ~ThreadKey();
01545         void *getKey(void);
01553         void setKey(void *);
01554 };
01555 
01566 class CCXX_CLASS_EXPORT TimerPort
01567 {
01568 #ifndef WIN32
01569         struct timeval timer;
01570 #else
01571         DWORD timer;
01572 #endif
01573         bool active;
01574 
01575 public:
01582         TimerPort();
01583 
01592         void setTimer(timeout_t timeout = 0);
01593 
01603         void incTimer(timeout_t timeout);
01604 
01610         void endTimer(void);
01611 
01622         timeout_t getTimer(void);
01623 
01632         timeout_t getElapsed(void);
01633 };
01634 
01635 inline int get(Buffer &b, void *o)
01636         {return b.Wait(o);};
01637 
01638 inline int put(Buffer &b, void *o)
01639         {return b.Post(o);};
01640 
01641 inline int peek(Buffer &b, void *o)
01642         {return b.Peek(o);};
01643 
01644 
01645 // FIXME: not in win32 implementation
01646 #ifndef WIN32
01647 
01648 // FIXME: private declaration ???
01649 struct  timespec *gettimeout(struct timespec *spec, timeout_t timeout); 
01650 void    wait(signo_t signo);
01651 
01660 void    pdetach(void);
01661 #endif // !WIN32
01662 
01663 // FIXME: no way to implement in win32
01664 #ifndef WIN32
01665 #if defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H)
01666 #if defined(HAVE_SYS_STREAM_H)
01667 #if defined(__linux__)
01668 #define CCXX_USE_POLL 1
01669 #endif
01670 #else
01671 #define CCXX_USE_POLL 1
01672 #endif
01673 #endif
01674 
01675 #ifdef CCXX_USE_POLL
01676 
01684 class Poller 
01685 {
01686 private:
01687         int nufds;
01688         pollfd *ufds;
01689 
01690 public:
01691         Poller();
01692 
01693         virtual ~Poller();
01694 
01702         pollfd *getList(int cnt);
01703 
01709         inline  pollfd *getList(void)
01710                 {return ufds;};
01711 };
01712 #endif
01713 #endif // !WIN32
01714 
01715 #ifdef  COMMON_STD_EXCEPTION
01716 
01722 class ThrException : public Exception
01723 {
01724 public:
01725         ThrException(const std::string &what_arg) : Exception(what_arg) {};
01726 };
01727 
01734 class SyncException : public ThrException
01735 {
01736 public:
01737         SyncException(const std::string &what_arg) : ThrException(what_arg) {};
01738 };
01739 #endif
01740 
01741 #ifdef  CCXX_NAMESPACES
01742 };
01743 #endif
01744 
01745 #endif
01746 

Generated at Fri Dec 21 08:31:30 2001 for CommonC++ by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001