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 #ifndef HAVE_PTHREAD_SUSPEND
00151 static RETSIGTYPE ccxx_sigsuspend(int);
00152 #endif
00153 #endif
00154 #endif
00155 extern "C" void execHandler(Thread *th);
00156 
00157 #endif // !WIN32
00158 
00159 
00160 CCXX_EXPORT(Thread*) getThread(void);
00161 CCXX_EXPORT(throw_t) getException(void);
00162 CCXX_EXPORT(void) setException(throw_t mode);
00163 CCXX_EXPORT(void) ccxx_sleep(timeout_t msec);
00164 CCXX_EXPORT(void) ccxx_yield(void);
00165 
00166 #undef Yield
00167 #define sleep(x)        ccxx_sleep((x) * 1000)
00168 #define yield()         ccxx_yield()
00169 
00170 #ifdef WIN32
00171 CCXX_EXPORT(DWORD) waitThread(HANDLE hRef, timeout_t timeout);
00172 #endif
00173 
00174 class Conditional;
00175 class CCXX_CLASS_EXPORT Event;
00176 
00220 class CCXX_CLASS_EXPORT Mutex
00221 {
00222         friend class Conditional;
00223         friend class Event;
00224 private:
00225 #ifndef WIN32
00226 #ifndef PTHREAD_MUTEXTYPE_RECURSIVE
00227         volatile int _level;
00228         volatile Thread *_tid;
00229 #endif
00230 
00238         pthread_mutex_t _mutex;
00239 #else
00240         HANDLE mutex;
00241 #endif
00242 
00243 public:
00247         Mutex();
00248 
00254         virtual ~Mutex();
00255 
00263         void EnterMutex(void);
00264 
00275         bool TryEnterMutex(void);
00276 
00287         void LeaveMutex(void);
00288 };
00289 
00311 class MutexLock
00312 {
00313 private:
00314         Mutex& mutex;
00315 public:
00319         MutexLock( Mutex& _mutex ) : mutex( _mutex ) 
00320                 { mutex.EnterMutex(); }
00324         // this should be not-virtual
00325         ~MutexLock()
00326                 { mutex.LeaveMutex(); }
00327 };
00328 
00337 class CCXX_CLASS_EXPORT ThreadLock
00338 {
00339 private:
00340 #ifdef HAVE_PTHREAD_RWLOCK
00341         pthread_rwlock_t _lock;
00342 #else
00343         Mutex mutex;
00344 #endif
00345 
00346 public:
00350         ThreadLock();
00351 
00355         virtual ~ThreadLock();
00356 
00360         void ReadLock(void);
00361 
00365         void WriteLock(void);
00366 
00372         bool TryReadLock(void);
00373 
00379         bool TryWriteLock(void);
00380 
00384         void Unlock(void);
00385 };
00386 
00396 class CCXX_CLASS_EXPORT MutexCounter : public Mutex
00397 {
00398 private:
00399         int     counter;
00400 
00401 public:
00402         MutexCounter();
00403         MutexCounter(int initial);
00404 
00405         friend CCXX_EXPORT(int) operator++(MutexCounter &mc);
00406         friend CCXX_EXPORT(int) operator--(MutexCounter &mc);
00407 };
00408 
00419 class CCXX_CLASS_EXPORT AtomicCounter
00420 {
00421 #ifndef WIN32
00422 private:
00423 #ifdef  HAVE_ATOMIC
00424         atomic_t atomic;
00425 #else
00426         int counter;
00427         Mutex lock;
00428 #endif
00429 
00430 public:
00434         AtomicCounter();
00435 
00441         AtomicCounter(int value);
00442 
00443         int operator++(void);
00444         int operator--(void);
00445         int operator+=(int change);
00446         int operator-=(int change);
00447         int operator+(int change);
00448         int operator-(int change);
00449         int operator=(int value);
00450         bool operator!(void);
00451         operator int();
00452 #else
00453 private:
00454         long atomic;
00455 
00456 public:
00457         inline AtomicCounter()
00458                 {atomic = 0;};
00459 
00460         inline AtomicCounter(int value)
00461                 {atomic = value;};
00462 
00463         inline int operator++(void)
00464                 {return InterlockedIncrement(&atomic);};
00465 
00466         inline int operator--(void)
00467                 {return InterlockedDecrement(&atomic);};
00468 
00469         int operator+=(int change);
00470 
00471         int operator-=(int change);
00472 
00473         inline int operator+(int change)
00474                 {return atomic + change;};
00475 
00476         inline int operator-(int change)
00477                 {return atomic - change;};
00478         
00479         inline int operator=(int value)
00480                 {return InterlockedExchange(&atomic, value);};
00481 
00482         inline bool operator!(void)
00483                 {return (atomic == 0) ? true : false;};
00484 
00485         inline operator int()
00486                 {return atomic;};
00487 #endif
00488 };
00489 
00490 // FIXME: implement Conditional class for win32
00491 #ifndef WIN32
00492 
00502 class Conditional : public Mutex
00503 {
00504 private:
00505         pthread_cond_t _cond;
00506 
00507 public:
00511         Conditional();
00512 
00516         virtual ~Conditional();
00517 
00523         void Signal(bool broadcast);
00524 
00528         void Wait(timeout_t timer = 0); 
00529 };
00530 #endif
00531 
00549 class CCXX_CLASS_EXPORT Semaphore
00550 {
00551 private:
00552 #ifndef WIN32
00553 #ifdef  CCXX_SYSV_SEMAPHORES
00554         int _semaphore;
00555 #else
00556         sem_t _semaphore;
00557 #endif
00558 #else // WIN32
00559         HANDLE  semObject;
00560 #endif // !WIN32
00561 
00562 public:
00571         Semaphore(size_t resource = 0);
00572 
00579         virtual ~Semaphore();
00580 
00594         void Wait(void);
00595 
00607         bool TryWait(void);
00608 
00620         void Post(void);
00621 
00622         // FIXME: how implement getValue for posix compatibility ?
00628 #ifndef WIN32
00629 #ifndef __CYGWIN32__
00630         int getValue(void);
00631 #endif
00632 #endif
00633 };
00634 
00648 class CCXX_CLASS_EXPORT Event
00649 {
00650 private:
00651 #ifndef WIN32
00652         Mutex mutex;
00653         pthread_cond_t _cond;
00654         bool _signaled;
00655         int _count;
00656 #else
00657         HANDLE cond;
00658 #endif
00659 
00660 public:
00661         Event();
00662 
00663         virtual ~Event();
00664 
00671         void Reset(void);
00672 
00676         void Signal(void);
00677 
00686         bool Wait(timeout_t timer);
00687         bool Wait(void);
00688 };
00689 
00711 class CCXX_CLASS_EXPORT Buffer
00712 {
00713 private:
00714         Mutex lock_head, lock_tail;
00715         Semaphore size_head, size_tail;
00716         size_t _size;
00717         size_t _used;
00718 
00719 protected:
00725         virtual int OnPeek(void *buf) = 0;
00731         virtual int OnWait(void *buf) = 0;
00737         virtual int OnPost(void *buf) = 0;
00738 
00739 public:
00744         Buffer(size_t capacity);
00749         virtual ~Buffer()
00750                 {return;};
00751 
00756         inline size_t getSize(void)
00757                 {return _size;};
00758         
00765         inline size_t getUsed(void)
00766                 {return _used;};
00767 
00776         int Wait(void *buf);
00777 
00785         int Post(void *buf);
00786 
00793         int Peek(void *buf);
00794 
00799         virtual bool isValid(void)
00800                 {return true;};
00801 };
00802 
00810 class CCXX_CLASS_EXPORT FixedBuffer : public Buffer
00811 {
00812 private:
00813         char *buf, *head, *tail;
00814         size_t objsize;
00815 
00816 protected:
00822         int OnPeek(void *buf);
00823 
00829         int OnWait(void *buf);
00830 
00836         int OnPost(void *buf);  
00837 
00838 public:
00846         FixedBuffer(size_t capacity, size_t objsize);
00847 
00854         FixedBuffer(const FixedBuffer &fb);
00855 
00859         virtual ~FixedBuffer();
00860 
00861         FixedBuffer &operator=(const FixedBuffer &fb);
00862 
00863         bool isValid(void);
00864 };
00865 
01013 class Thread
01014 {
01015 #ifndef WIN32
01016 friend class PosixThread;
01017 friend RETSIGTYPE ccxx_sigsuspend(int);
01018 #endif
01019 private:
01020         friend class Slog;
01021 
01022         static Thread *_main;
01023 
01024         Thread *_parent;
01025 #ifndef WIN32
01026         pthread_t _tid;
01027         pthread_attr_t _attr;
01028         AtomicCounter _suspendcount;
01029 #else
01030         DWORD _tid;
01031         HANDLE _cancellation;
01032 #endif
01033         thread_cancel_t _cancel;
01034         jmp_buf _env;
01035         Semaphore *_start;
01036         int _msgpos;
01037         char _msgbuf[128];
01038         throw_t _throw;
01039 
01040 #ifndef WIN32
01041         friend void execHandler(Thread *th);
01042         friend Thread *getThread(void);
01043 #else
01044         bool _active:1;
01045         bool _suspendEnable:1;
01046         static unsigned __stdcall Execute(Thread *th);
01047         HANDLE  _hThread;
01048 #endif
01049 
01050 protected:
01060         virtual void Run(void) = 0;
01061 
01074         CCXX_MEMBER_EXPORT(virtual void) Final(void)
01075                 {return;};
01076 
01087         CCXX_MEMBER_EXPORT(virtual void) Initial(void)
01088                 {return;};
01089 
01099         CCXX_MEMBER_EXPORT(virtual void*) getExtended(void)
01100                 {return NULL;};
01101 
01109         CCXX_MEMBER_EXPORT(virtual void) Notify(Thread *th)
01110                 {return;};
01111 
01121         CCXX_MEMBER_EXPORT(void) Sleep(timeout_t msec)
01122 #ifndef WIN32
01123                 {ccxx_sleep(msec);}
01124 #endif
01125         ;
01126 
01127         // FIXME: _env can not initialized
01133         inline void Exit(void)
01134                 {longjmp(_env, 1);};
01135 
01140         CCXX_MEMBER_EXPORT(void) Yield(void);
01141 
01145         CCXX_MEMBER_EXPORT(void) testCancel(void);
01146 
01155         CCXX_MEMBER_EXPORT(void) setCancel(thread_cancel_t mode);
01156 
01164         CCXX_MEMBER_EXPORT(void) setSuspend(thread_suspend_t mode);
01165 
01174         CCXX_MEMBER_EXPORT(void) Terminate(void);
01175 
01179         inline void clrParent(void)
01180                 {_parent = NULL;};
01181 
01182 #ifdef WIN32
01183         // FIXME: should be private
01184         CCXX_MEMBER_EXPORT(DWORD) WaitHandle(HANDLE obj, timeout_t timeout);
01185 #endif
01186 
01187 public:
01196         CCXX_MEMBER_EXPORT(CCXX_EMPTY) Thread(bool isMain);
01197 
01210         CCXX_MEMBER_EXPORT(CCXX_EMPTY) Thread(int pri = 0, size_t stack = 0);
01211 
01212         // FIXME: win32 lack copy constructor
01213 #ifndef WIN32
01214 
01221         Thread(const Thread &th);
01222 #endif
01223 
01230         CCXX_MEMBER_EXPORT(virtual) ~Thread()
01231                 {Terminate();};
01232 
01245         CCXX_MEMBER_EXPORT(int) Start(Semaphore *start = 0);
01246 
01255         CCXX_MEMBER_EXPORT(int) Detach(Semaphore *start = 0);
01256 
01263         inline Thread *getParent(void)
01264                 {return _parent;};
01265 
01272         CCXX_MEMBER_EXPORT(void) Suspend(void);
01273 
01277         CCXX_MEMBER_EXPORT(void) Resume(void);
01278 
01285         inline thread_cancel_t getCancel(void)
01286                 {return _cancel;};
01287 
01294         bool isRunning(void)
01295 #ifdef WIN32
01296                 {return (_tid != 0) ? true : false;}
01297 #endif
01298         ;
01299 
01306         bool isThread(void)
01307 #ifdef WIN32
01308                 {return ((_tid == GetCurrentThreadId())) ? true : false;}
01309 #endif
01310         ;
01311 
01317         friend CCXX_EXPORT(throw_t) getException(void);
01318 
01324         friend CCXX_EXPORT(void) setException(throw_t mode);
01325 
01326         // FIXME: _start can be NULL
01333         friend inline void operator++(Thread &th)
01334                 {th._start->Post();};
01335 
01336         friend inline void operator--(Thread &th)
01337                 {th._start->Wait();};
01338 
01344         friend CCXX_EXPORT(void) ccxx_sleep(timeout_t msec);
01345 
01349         friend CCXX_EXPORT(void) ccxx_yield(void);
01350 
01351 #ifdef WIN32
01352         // FIXME: not defined in posix
01353         inline bool isCancelled(void)
01354                 {return waitThread(_cancellation, 0) == WAIT_OBJECT_0; };
01355 
01356         inline bool isCancelled(timeout_t timer)
01357                 {return waitThread(_cancellation, timer) == WAIT_OBJECT_0; };
01358                 
01359         friend CCXX_EXPORT(DWORD) waitThread(HANDLE hRef, timeout_t timeout);
01360 #endif
01361 };
01362 
01363 #if !defined(WIN32) && !defined(__CYGWIN32__)  && !defined(__MINGW32__)
01364 extern "C" void sigHandler(int signo);
01365 
01366 typedef int             signo_t;
01367 
01368 class PosixThread: public Thread
01369 {
01370 private:
01371 #ifndef WIN32
01372         friend void execHandler(Thread *th);
01373 #endif
01374 #ifndef CCXX_SIG_THREAD_ALARM
01375         static PosixThread *_timer;
01376         static Mutex _arm;
01377 #endif
01378         
01379         time_t  _alarm;
01380         friend void sigHandler(int signo);
01381         inline static void SignalThread(Thread* th,signo_t signo)
01382                 {pthread_kill(th->_tid, signo);};
01383 protected:
01384                 
01391         inline void SignalParent(signo_t signo)
01392                 { SignalThread(_parent,signo); };
01393         
01400         inline void SignalMain(signo_t signo)
01401                 { SignalThread(_main,signo);};
01402 
01407         virtual void OnTimer(void)
01408                 {return;};
01409 
01414         virtual void OnHangup(void)
01415                 {return;};
01416 
01421         virtual void OnException(void)
01422                 {return;};
01423 
01428         virtual void OnDisconnect(void)
01429                 {return;};
01430 
01435         virtual void OnPolling(void)
01436                 {return;};
01437 
01444         virtual void OnSignal(int signo)
01445                 {return;};
01446         
01456         void setTimer(timeout_t timer);
01457         
01464         timeout_t getTimer(void);
01465         
01471         void endTimer(void);
01472         
01479         void WaitSignal(signo_t signo);
01480         
01487         void setSignal(int signo, bool mode);
01488 public:
01489         
01495         inline void SignalThread(int signo)
01496                 {SignalThread(this, signo);};
01497 
01504         friend void siginstall(int signo);
01505 };
01506 #endif
01507 
01522 class CCXX_CLASS_EXPORT ThreadKey
01523 {
01524 private:
01525 #ifndef WIN32
01526         pthread_key_t key;
01527 #else
01528         DWORD   key;
01529 #endif
01530 
01531 public:
01535         ThreadKey();
01539         virtual ~ThreadKey();
01547         void *getKey(void);
01555         void setKey(void *);
01556 };
01557 
01568 class CCXX_CLASS_EXPORT TimerPort
01569 {
01570 #ifndef WIN32
01571         struct timeval timer;
01572 #else
01573         DWORD timer;
01574 #endif
01575         bool active;
01576 
01577 public:
01584         TimerPort();
01585 
01594         void setTimer(timeout_t timeout = 0);
01595 
01605         void incTimer(timeout_t timeout);
01606 
01612         void endTimer(void);
01613 
01624         timeout_t getTimer(void);
01625 
01634         timeout_t getElapsed(void);
01635 };
01636 
01637 inline int get(Buffer &b, void *o)
01638         {return b.Wait(o);};
01639 
01640 inline int put(Buffer &b, void *o)
01641         {return b.Post(o);};
01642 
01643 inline int peek(Buffer &b, void *o)
01644         {return b.Peek(o);};
01645 
01646 
01647 // FIXME: not in win32 implementation
01648 #if !defined(WIN32)
01649 
01650 // FIXME: private declaration ???
01651 struct  timespec *gettimeout(struct timespec *spec, timeout_t timeout); 
01652 
01653 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
01654 void    wait(signo_t signo);
01655 #endif
01656 
01665 void    pdetach(void);
01666 #endif // !WIN32
01667 
01668 // FIXME: no way to implement in win32
01669 #ifndef WIN32
01670 #if defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H)
01671 #if defined(HAVE_SYS_STREAM_H)
01672 #if defined(__linux__)
01673 #define CCXX_USE_POLL 1
01674 #endif
01675 #else
01676 #define CCXX_USE_POLL 1
01677 #endif
01678 #endif
01679 
01680 #ifdef CCXX_USE_POLL
01681 
01689 class Poller 
01690 {
01691 private:
01692         int nufds;
01693         pollfd *ufds;
01694 
01695 public:
01696         Poller();
01697 
01698         virtual ~Poller();
01699 
01707         pollfd *getList(int cnt);
01708 
01714         inline  pollfd *getList(void)
01715                 {return ufds;};
01716 };
01717 #endif
01718 #endif // !WIN32
01719 
01720 #ifdef  COMMON_STD_EXCEPTION
01721 
01727 class ThrException : public Exception
01728 {
01729 public:
01730         ThrException(const std::string &what_arg) : Exception(what_arg) {};
01731 };
01732 
01739 class SyncException : public ThrException
01740 {
01741 public:
01742         SyncException(const std::string &what_arg) : ThrException(what_arg) {};
01743 };
01744 #endif
01745 
01746 #ifdef  CCXX_NAMESPACES
01747 };
01748 #endif
01749 
01750 #endif
01751 

Generated at Fri Jan 4 18:51:46 2002 for CommonC++ by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001