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 _SYSV_SEMAPHORES
00059 #endif
00060 
00061 #ifndef HAVE_PTHREAD_H
00062 #include <pthread.h>
00063 #ifndef _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 _SIG_THREAD_ALARM
00078 #endif
00079 
00080 #ifdef  _THR_UNIXWARE
00081 #undef  PTHREAD_MUTEXTYPE_RECURSIVE
00082 #endif
00083 
00084 typedef pthread_t       cctid_t;
00085 typedef unsigned long   timeout_t;
00086 #else // WIN32
00087 typedef DWORD   cctid_t;
00088 typedef DWORD   timeout_t;
00089 
00090 #define MAX_SEM_VALUE   1000000
00091 #if defined(__MINGW32__) || defined(__CYGWIN32__)
00092 #include <Windows32/CommonFunctions.h>
00093 #else
00094 __declspec(dllimport) long __stdcall InterlockedIncrement(long *);
00095 __declspec(dllimport) long __stdcall InterlockedDecrement(long *);
00096 __declspec(dllimport) long __stdcall InterlockedExchange(long *, long);
00097 #endif
00098 
00099 #endif // !WIN32
00100 
00101 #ifdef  CCXX_NAMESPACES
00102 namespace ost {
00103 #endif
00104 
00105 enum throw_t {
00106         THROW_NOTHING, 
00107         THROW_OBJECT, 
00108         THROW_EXCEPTION
00109 };
00110 typedef enum throw_t throw_t;
00111 class Thread;
00112 
00113 #define TIMEOUT_INF ~((timeout_t) 0)
00114 
00115 #define ENTER_CRITICAL  EnterMutex();
00116 #define LEAVE_CRITICAL  LeaveMutex();
00117 #define ENTER_DEFERRED  setCancel(THREAD_CANCEL_DEFERRED);
00118 #define LEAVE_DEFERRED  setCancel(THREAD_CANCEL_IMMEDIATE);
00119 
00120 enum thread_cancel_t
00121 {
00122         THREAD_CANCEL_INITIAL=0,
00123         THREAD_CANCEL_DEFERRED=1,
00124         THREAD_CANCEL_IMMEDIATE,
00125         THREAD_CANCEL_DISABLED,
00126         THREAD_CANCEL_DEFAULT=THREAD_CANCEL_DEFERRED
00127 };
00128 typedef enum thread_cancel_t thread_cancel_t;
00129 
00130 enum thread_suspend_t
00131 {
00132         THREAD_SUSPEND_ENABLE,
00133         THREAD_SUSPEND_DISABLE
00134 };
00135 typedef enum thread_suspend_t thread_suspend_t;
00136 
00137 #ifndef WIN32
00138 // These macros override common functions with thread-safe versions. In
00139 // particular the common "libc" sleep() has problems since it normally
00140 // uses SIGARLM (as actually defined by "posix").  The pthread_delay and
00141 // usleep found in libpthread are gaurenteed not to use SIGALRM and offer
00142 // higher resolution.  psleep() is defined to call the old process sleep.
00143 
00144 #undef  sleep
00145 #define psleep(x)       (sleep)(x)
00146 
00147 static RETSIGTYPE ccxx_sigsuspend(int);
00148 extern "C" void execHandler(Thread *th);
00149 
00150 #endif // !WIN32
00151 
00152 
00153 CCXX_EXPORT(Thread*) getThread(void);
00154 CCXX_EXPORT(throw_t) getException(void);
00155 CCXX_EXPORT(void) setException(throw_t mode);
00156 CCXX_EXPORT(void) ccxx_sleep(timeout_t msec);
00157 CCXX_EXPORT(void) ccxx_yield(void);
00158 
00159 #undef Yield
00160 #define sleep(x)        ccxx_sleep((x) * 1000)
00161 #define yield()         ccxx_yield()
00162 
00163 #ifdef WIN32
00164 CCXX_EXPORT(DWORD) waitThread(HANDLE hRef, timeout_t timeout);
00165 #endif
00166 
00167 class Conditional;
00168 class CCXX_CLASS_EXPORT Event;
00169 
00213 class CCXX_CLASS_EXPORT Mutex
00214 {
00215         friend class Conditional;
00216         friend class Event;
00217 private:
00218 #ifndef WIN32
00219 #ifndef PTHREAD_MUTEXTYPE_RECURSIVE
00220         volatile int _level;
00221         volatile Thread *_tid;
00222 #endif
00223 
00231         pthread_mutex_t _mutex;
00232 #else
00233         HANDLE mutex;
00234 #endif
00235 
00236 public:
00240         Mutex();
00241 
00247         virtual ~Mutex();
00248 
00256         void EnterMutex(void);
00257 
00268         bool TryEnterMutex(void);
00269 
00280         void LeaveMutex(void);
00281 };
00282 
00304 class MutexLock
00305 {
00306 private:
00307         Mutex& mutex;
00308 public:
00312         MutexLock( Mutex& _mutex ) : mutex( _mutex ) 
00313                 { mutex.EnterMutex(); }
00317         // this should be not-virtual
00318         ~MutexLock()
00319                 { mutex.LeaveMutex(); }
00320 };
00321 
00330 class CCXX_CLASS_EXPORT ThreadLock
00331 {
00332 private:
00333 #ifdef HAVE_PTHREAD_RWLOCK
00334         pthread_rwlock_t _lock;
00335 #else
00336         Mutex mutex;
00337 #endif
00338 
00339 public:
00343         ThreadLock();
00344 
00348         virtual ~ThreadLock();
00349 
00353         void ReadLock(void);
00354 
00358         void WriteLock(void);
00359 
00365         bool TryReadLock(void);
00366 
00372         bool TryWriteLock(void);
00373 
00377         void Unlock(void);
00378 };
00379 
00389 class CCXX_CLASS_EXPORT MutexCounter : public Mutex
00390 {
00391 private:
00392         int     counter;
00393 
00394 public:
00395         MutexCounter();
00396         MutexCounter(int initial);
00397 
00398         friend CCXX_EXPORT(int) operator++(MutexCounter &mc);
00399         friend CCXX_EXPORT(int) operator--(MutexCounter &mc);
00400 };
00401 
00412 class CCXX_CLASS_EXPORT AtomicCounter
00413 {
00414 #ifndef WIN32
00415 private:
00416 #ifdef  HAVE_ATOMIC
00417         atomic_t atomic;
00418 #else
00419         int counter;
00420         Mutex lock;
00421 #endif
00422 
00423 public:
00427         AtomicCounter();
00428 
00434         AtomicCounter(int value);
00435 
00436         int operator++(void);
00437         int operator--(void);
00438         int operator+=(int change);
00439         int operator-=(int change);
00440         int operator+(int change);
00441         int operator-(int change);
00442         int operator=(int value);
00443         bool operator!(void);
00444         operator int();
00445 #else
00446 private:
00447         long atomic;
00448 
00449 public:
00450         inline AtomicCounter()
00451                 {atomic = 0;};
00452 
00453         inline AtomicCounter(int value)
00454                 {atomic = value;};
00455 
00456         inline int operator++(void)
00457                 {return InterlockedIncrement(&atomic);};
00458 
00459         inline int operator--(void)
00460                 {return InterlockedDecrement(&atomic);};
00461 
00462         int operator+=(int change);
00463 
00464         int operator-=(int change);
00465 
00466         inline int operator+(int change)
00467                 {return atomic + change;};
00468 
00469         inline int operator-(int change)
00470                 {return atomic - change;};
00471         
00472         inline int operator=(int value)
00473                 {return InterlockedExchange(&atomic, value);};
00474 
00475         inline bool operator!(void)
00476                 {return (atomic == 0) ? true : false;};
00477 
00478         inline operator int()
00479                 {return atomic;};
00480 #endif
00481 };
00482 
00483 // FIXME: implement Conditional class for win32
00484 #ifndef WIN32
00485 
00495 class Conditional : public Mutex
00496 {
00497 private:
00498         pthread_cond_t _cond;
00499 
00500 public:
00504         Conditional();
00505 
00509         virtual ~Conditional();
00510 
00516         void Signal(bool broadcast);
00517 
00521         void Wait(timeout_t timer = 0); 
00522 };
00523 #endif
00524 
00542 class CCXX_CLASS_EXPORT Semaphore
00543 {
00544 private:
00545 #ifndef WIN32
00546 #ifdef  _SYSV_SEMAPHORES
00547         int _semaphore;
00548 #else
00549         sem_t _semaphore;
00550 #endif
00551 #else // WIN32
00552         HANDLE  semObject;
00553 #endif // !WIN32
00554 
00555 public:
00564         Semaphore(size_t resource = 0);
00565 
00572         virtual ~Semaphore();
00573 
00587         void Wait(void);
00588 
00600         bool TryWait(void);
00601 
00613         void Post(void);
00614 
00615         // FIXME: how implement getValue for posix compatibility ?
00621 #ifndef WIN32
00622 #ifndef __CYGWIN32__
00623         int getValue(void);
00624 #endif
00625 #endif
00626 };
00627 
00641 class CCXX_CLASS_EXPORT Event
00642 {
00643 private:
00644 #ifndef WIN32
00645         Mutex mutex;
00646         pthread_cond_t _cond;
00647         bool _signaled;
00648         int _count;
00649 #else
00650         HANDLE cond;
00651 #endif
00652 
00653 public:
00654         Event();
00655 
00656         virtual ~Event();
00657 
00664         void Reset(void);
00665 
00669         void Signal(void);
00670 
00679         bool Wait(timeout_t timer);
00680         bool Wait(void);
00681 };
00682 
00704 class CCXX_CLASS_EXPORT Buffer
00705 {
00706 private:
00707         Mutex lock_head, lock_tail;
00708         Semaphore size_head, size_tail;
00709         size_t _size;
00710         size_t _used;
00711 
00712 protected:
00718         virtual int OnPeek(void *buf) = 0;
00724         virtual int OnWait(void *buf) = 0;
00730         virtual int OnPost(void *buf) = 0;
00731 
00732 public:
00737         Buffer(size_t capacity);
00742         virtual ~Buffer()
00743                 {return;};
00744 
00749         inline size_t getSize(void)
00750                 {return _size;};
00751         
00758         inline size_t getUsed(void)
00759                 {return _used;};
00760 
00769         int Wait(void *buf);
00770 
00778         int Post(void *buf);
00779 
00786         int Peek(void *buf);
00787 
00792         virtual bool isValid(void)
00793                 {return true;};
00794 };
00795 
00803 class CCXX_CLASS_EXPORT FixedBuffer : public Buffer
00804 {
00805 private:
00806         char *buf, *head, *tail;
00807         size_t objsize;
00808 
00809 protected:
00815         int OnPeek(void *buf);
00816 
00822         int OnWait(void *buf);
00823 
00829         int OnPost(void *buf);  
00830 
00831 public:
00839         FixedBuffer(size_t capacity, size_t objsize);
00840 
00847         FixedBuffer(const FixedBuffer &fb);
00848 
00852         virtual ~FixedBuffer();
00853 
00854         FixedBuffer &operator=(const FixedBuffer &fb);
00855 
00856         bool isValid(void);
00857 };
00858 
01006 class Thread
01007 {
01008 #ifndef WIN32
01009 friend class PosixThread;
01010 friend RETSIGTYPE ccxx_sigsuspend(int);
01011 #endif
01012 private:
01013         friend class Slog;
01014 
01015         static Thread *_main;
01016 
01017         Thread *_parent;
01018 #ifndef WIN32
01019         pthread_t _tid;
01020         pthread_attr_t _attr;
01021         AtomicCounter _suspendcount;
01022 #else
01023         DWORD _tid;
01024         HANDLE _cancellation;
01025 #endif
01026         thread_cancel_t _cancel;
01027         jmp_buf _env;
01028         Semaphore *_start;
01029         int _msgpos;
01030         char _msgbuf[128];
01031         throw_t _throw;
01032 
01033 #ifndef WIN32
01034         friend void execHandler(Thread *th);
01035         friend Thread *getThread(void);
01036 #else
01037         bool _active:1;
01038         bool _suspendEnable:1;
01039         static unsigned __stdcall Execute(Thread *th);
01040         HANDLE  _hThread;
01041 #endif
01042 
01043 protected:
01053         virtual void Run(void) = 0;
01054 
01067         CCXX_MEMBER_EXPORT(virtual void) Final(void)
01068                 {return;};
01069 
01080         CCXX_MEMBER_EXPORT(virtual void) Initial(void)
01081                 {return;};
01082 
01092         CCXX_MEMBER_EXPORT(virtual void*) getExtended(void)
01093                 {return NULL;};
01094 
01102         CCXX_MEMBER_EXPORT(virtual void) Notify(Thread *th)
01103                 {return;};
01104 
01114         CCXX_MEMBER_EXPORT(void) Sleep(timeout_t msec)
01115 #ifndef WIN32
01116                 {ccxx_sleep(msec);}
01117 #endif
01118         ;
01119 
01120         // FIXME: _env can not initialized
01126         inline void Exit(void)
01127                 {longjmp(_env, 1);};
01128 
01133         CCXX_MEMBER_EXPORT(void) Yield(void);
01134 
01138         CCXX_MEMBER_EXPORT(void) testCancel(void);
01139 
01148         CCXX_MEMBER_EXPORT(void) setCancel(thread_cancel_t mode);
01149 
01157         CCXX_MEMBER_EXPORT(void) setSuspend(thread_suspend_t mode);
01158 
01167         CCXX_MEMBER_EXPORT(void) Terminate(void);
01168 
01172         inline void clrParent(void)
01173                 {_parent = NULL;};
01174 
01175 #ifdef WIN32
01176         // FIXME: should be private
01177         CCXX_MEMBER_EXPORT(DWORD) WaitHandle(HANDLE obj, timeout_t timeout);
01178 #endif
01179 
01180 public:
01189         CCXX_MEMBER_EXPORT(CCXX_EMPTY) Thread(bool isMain);
01190 
01203         CCXX_MEMBER_EXPORT(CCXX_EMPTY) Thread(int pri = 0, size_t stack = 0);
01204 
01205         // FIXME: win32 lack copy constructor
01206 #ifndef WIN32
01207 
01214         Thread(const Thread &th);
01215 #endif
01216 
01223         CCXX_MEMBER_EXPORT(virtual) ~Thread()
01224                 {Terminate();};
01225 
01238         CCXX_MEMBER_EXPORT(int) Start(Semaphore *start = 0);
01239 
01248         CCXX_MEMBER_EXPORT(int) Detach(Semaphore *start = 0);
01249 
01256         inline Thread *getParent(void)
01257                 {return _parent;};
01258 
01265         CCXX_MEMBER_EXPORT(void) Suspend(void);
01266 
01270         CCXX_MEMBER_EXPORT(void) Resume(void);
01271 
01278         inline thread_cancel_t getCancel(void)
01279                 {return _cancel;};
01280 
01287         bool isRunning(void)
01288 #ifdef WIN32
01289                 {return (_tid != 0) ? true : false;}
01290 #endif
01291         ;
01292 
01299         bool isThread(void)
01300 #ifdef WIN32
01301                 {return ((_tid == GetCurrentThreadId())) ? true : false;}
01302 #endif
01303         ;
01304 
01310         friend CCXX_EXPORT(throw_t) getException(void);
01311 
01317         friend CCXX_EXPORT(void) setException(throw_t mode);
01318 
01319         // FIXME: _start can be NULL
01326         friend inline void operator++(Thread &th)
01327                 {th._start->Post();};
01328 
01329         friend inline void operator--(Thread &th)
01330                 {th._start->Wait();};
01331 
01337         friend CCXX_EXPORT(void) ccxx_sleep(timeout_t msec);
01338 
01342         friend CCXX_EXPORT(void) ccxx_yield(void);
01343 
01344 #ifdef WIN32
01345         // FIXME: not defined in posix
01346         inline bool isCancelled(void)
01347                 {return waitThread(_cancellation, 0) == WAIT_OBJECT_0; };
01348 
01349         inline bool isCancelled(timeout_t timer)
01350                 {return waitThread(_cancellation, timer) == WAIT_OBJECT_0; };
01351                 
01352         friend CCXX_EXPORT(DWORD) waitThread(HANDLE hRef, timeout_t timeout);
01353 #endif
01354 };
01355 
01356 #ifndef WIN32
01357 extern "C" void sigHandler(int signo);
01358 
01359 typedef int             signo_t;
01360 
01361 class PosixThread: public Thread
01362 {
01363 private:
01364 #ifndef WIN32
01365         friend void execHandler(Thread *th);
01366 #endif
01367 #ifndef _SIG_THREAD_ALARM
01368         static PosixThread *_timer;
01369         static Mutex _arm;
01370 #endif
01371         
01372         time_t  _alarm;
01373         friend void sigHandler(int signo);
01374         inline static void SignalThread(Thread* th,signo_t signo)
01375                 {pthread_kill(th->_tid, signo);};
01376 protected:
01377                 
01384         inline void SignalParent(signo_t signo)
01385                 { SignalThread(_parent,signo); };
01386         
01393         inline void SignalMain(signo_t signo)
01394                 { SignalThread(_main,signo);};
01395 
01400         virtual void OnTimer(void)
01401                 {return;};
01402 
01407         virtual void OnHangup(void)
01408                 {return;};
01409 
01414         virtual void OnException(void)
01415                 {return;};
01416 
01421         virtual void OnDisconnect(void)
01422                 {return;};
01423 
01428         virtual void OnPolling(void)
01429                 {return;};
01430 
01437         virtual void OnSignal(int signo)
01438                 {return;};
01439         
01449         void setTimer(timeout_t timer);
01450         
01457         timeout_t getTimer(void);
01458         
01464         void endTimer(void);
01465         
01472         void WaitSignal(signo_t signo);
01473         
01480         void setSignal(int signo, bool mode);
01481 public:
01482         
01488         inline void SignalThread(int signo)
01489                 {SignalThread(this, signo);};
01490 
01497         friend void siginstall(int signo);
01498 };
01499 #endif
01500 
01515 class CCXX_CLASS_EXPORT ThreadKey
01516 {
01517 private:
01518 #ifndef WIN32
01519         pthread_key_t key;
01520 #else
01521         DWORD   key;
01522 #endif
01523 
01524 public:
01528         ThreadKey();
01532         virtual ~ThreadKey();
01540         void *getKey(void);
01548         void setKey(void *);
01549 };
01550 
01561 class CCXX_CLASS_EXPORT TimerPort
01562 {
01563 #ifndef WIN32
01564         struct timeval timer;
01565 #else
01566         DWORD timer;
01567 #endif
01568         bool active;
01569 
01570 public:
01577         TimerPort();
01578 
01587         void setTimer(timeout_t timeout = 0);
01588 
01598         void incTimer(timeout_t timeout);
01599 
01605         void endTimer(void);
01606 
01617         timeout_t getTimer(void);
01618 
01627         timeout_t getElapsed(void);
01628 };
01629 
01630 inline int get(Buffer &b, void *o)
01631         {return b.Wait(o);};
01632 
01633 inline int put(Buffer &b, void *o)
01634         {return b.Post(o);};
01635 
01636 inline int peek(Buffer &b, void *o)
01637         {return b.Peek(o);};
01638 
01639 
01640 // FIXME: not in win32 implementation
01641 #ifndef WIN32
01642 
01643 // FIXME: private declaration ???
01644 struct  timespec *gettimeout(struct timespec *spec, timeout_t timeout); 
01645 void    wait(signo_t signo);
01646 
01655 void    pdetach(void);
01656 #endif // !WIN32
01657 
01658 // FIXME: no way to implement in win32
01659 #ifndef WIN32
01660 #if defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H)
01661 #if defined(HAVE_SYS_STREAM_H)
01662 #if defined(__linux__)
01663 #define __CCXX_USE_POLL 1
01664 #endif
01665 #else
01666 #define __CCXX_USE_POLL 1
01667 #endif
01668 #endif
01669 
01670 #ifdef __CCXX_USE_POLL
01671 
01679 class Poller 
01680 {
01681 private:
01682         int nufds;
01683         pollfd *ufds;
01684 
01685 public:
01686         Poller();
01687 
01688         virtual ~Poller();
01689 
01697         pollfd *getList(int cnt);
01698 
01704         inline  pollfd *getList(void)
01705                 {return ufds;};
01706 };
01707 #endif
01708 #endif // !WIN32
01709 
01710 #ifdef  COMMON_STD_EXCEPTION
01711 
01717 class ThrException : public Exception
01718 {
01719 public:
01720         ThrException(const std::string &what_arg) : Exception(what_arg) {};
01721 };
01722 
01729 class SyncException : public ThrException
01730 {
01731 public:
01732         SyncException(const std::string &what_arg) : ThrException(what_arg) {};
01733 };
01734 #endif
01735 
01736 #ifdef  CCXX_NAMESPACES
01737 };
01738 #endif
01739 
01740 #endif
01741 

Generated at Wed Dec 5 07:05:25 2001 for CommonC++ by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001