ucommon
commoncpp/thread.h
Go to the documentation of this file.
00001 // Copyright (C) 1999-2005 Open Source Telecom Corporation.
00002 // Copyright (C) 2006-2014 David Sugar, Tycho Softworks.
00003 //
00004 // This program is free software; you can redistribute it and/or modify
00005 // it under the terms of the GNU General Public License as published by
00006 // the Free Software Foundation; either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser General Public License
00015 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 //
00017 // As a special exception, you may use this file as part of a free software
00018 // library without restriction.  Specifically, if other files instantiate
00019 // templates or use macros or inline functions from this file, or you compile
00020 // this file and link it with other files to produce an executable, this
00021 // file does not by itself cause the resulting executable to be covered by
00022 // the GNU General Public License.  This exception does not however
00023 // invalidate any other reasons why the executable file might be covered by
00024 // the GNU General Public License.
00025 //
00026 // This exception applies only to the code released under the name GNU
00027 // Common C++.  If you copy code from other releases into a copy of GNU
00028 // Common C++, as the General Public License permits, the exception does
00029 // not apply to the code that you add in this way.  To avoid misleading
00030 // anyone as to the status of such modified files, you must delete
00031 // this exception notice from them.
00032 //
00033 // If you write modifications of your own for GNU Common C++, it is your choice
00034 // whether to permit this exception to apply to your modifications.
00035 // If you do not wish that, delete this exception notice.
00036 //
00037 
00043 #ifndef COMMONCPP_THREAD_H_
00044 #define COMMONCPP_THREAD_H_
00045 
00046 #ifndef COMMONCPP_CONFIG_H_
00047 #include <commoncpp/config.h>
00048 #endif
00049 
00050 #ifndef COMMONCPP_STRING_H_
00051 #include <commoncpp/string.h>
00052 #endif
00053 
00054 #define ENTER_CRITICAL  enterMutex();
00055 #define LEAVE_CRITICAL  leaveMutex();
00056 
00057 #include <time.h>
00058 
00059 namespace ost {
00060 
00061 class __EXPORT Mutex : protected ucommon::RecursiveMutex
00062 {
00063 public:
00064     inline Mutex() : RecursiveMutex() {}
00065 
00066     inline void enterMutex(void)
00067         {RecursiveMutex::lock();}
00068 
00069     inline void leaveMutex(void)
00070         {RecursiveMutex::release();}
00071 
00072     inline bool tryEnterMutex(void)
00073         {return RecursiveMutex::lock(0l);}
00074 
00075     inline void enter(void)
00076         {RecursiveMutex::lock();}
00077 
00078     inline void leave(void)
00079         {RecursiveMutex::release();}
00080 
00081     inline bool test(void)
00082         {return RecursiveMutex::lock(0l);}
00083 
00084 };
00085 
00095 class __EXPORT MutexCounter : public Mutex
00096 {
00097 protected:
00098     volatile int    counter;
00099 
00100 public:
00104     MutexCounter();
00105 
00112     MutexCounter(int initial);
00113 
00114     int operator++();
00115     int operator--();
00116 };
00117 
00141 class __EXPORT MutexLock
00142 {
00143 private:
00144     Mutex& mutex;
00145 
00146 public:
00152     inline MutexLock( Mutex& _mutex ) : mutex( _mutex )
00153         { mutex.enterMutex(); }
00154 
00158     // this should be not-virtual
00159     inline ~MutexLock()
00160         { mutex.leaveMutex(); }
00161 };
00162 
00163 class __EXPORT ThreadLock : protected ucommon::ThreadLock
00164 {
00165 public:
00166     inline ThreadLock() : ucommon::ThreadLock() {}
00167 
00168     inline void readLock(void)
00169         {ucommon::ThreadLock::access();}
00170 
00171     inline void writeLock(void)
00172         {ucommon::ThreadLock::modify();}
00173 
00174     inline void tryReadLock(void)
00175         {ucommon::ThreadLock::access(0);}
00176 
00177     inline void tryWriteLock(void)
00178         {ucommon::ThreadLock::modify(0);}
00179 
00180     inline void unlock(void)
00181         {ucommon::ThreadLock::release();}
00182 };
00183 
00204 class __EXPORT ReadLock
00205 {
00206 private:
00207     ThreadLock& tl;
00208 
00209 public:
00215     inline ReadLock( ThreadLock& _tl ) : tl( _tl )
00216         { tl.readLock(); }
00220     // this should be not-virtual
00221     inline ~ReadLock()
00222         { tl.unlock(); }
00223 };
00224 
00245 class __EXPORT WriteLock
00246 {
00247 private:
00248     ThreadLock& tl;
00249 
00250 public:
00256     inline WriteLock( ThreadLock& _tl ) : tl( _tl )
00257         { tl.writeLock(); }
00261     // this should be not-virtual
00262     inline ~WriteLock()
00263         { tl.unlock(); }
00264 };
00265 
00266 class __EXPORT Conditional : private ucommon::Conditional
00267 {
00268 public:
00269     inline Conditional() : ucommon::Conditional() {}
00270 
00271     bool wait(timeout_t timeout, bool locked = false);
00272 
00273     void signal(bool broadcast);
00274 
00275     inline void enterMutex(void)
00276         {ucommon::Conditional::lock();}
00277 
00278     inline void leaveMutex(void)
00279         {ucommon::Conditional::unlock();}
00280 };
00281 
00282 class __EXPORT Semaphore : private ucommon::Semaphore
00283 {
00284 public:
00285     inline Semaphore(unsigned size = 0) : ucommon::Semaphore(size) {}
00286 
00287     inline bool wait(timeout_t timeout)
00288         {return ucommon::Semaphore::wait(timeout);}
00289 
00290     inline void wait(void)
00291         {ucommon::Semaphore::wait();}
00292 
00293     inline void post(void)
00294         {ucommon::Semaphore::release();}
00295 };
00296 
00316 class __EXPORT SemaphoreLock
00317 {
00318 private:
00319     Semaphore& sem;
00320 
00321 public:
00325     inline SemaphoreLock( Semaphore& _sem ) : sem( _sem )
00326         { sem.wait(); }
00330     // this should be not-virtual
00331     inline ~SemaphoreLock()
00332         { sem.post(); }
00333 };
00334 
00335 class __EXPORT Event : private ucommon::TimedEvent
00336 {
00337 public:
00338     inline Event() : ucommon::TimedEvent() {}
00339 
00340     inline void wait(void)
00341         {ucommon::TimedEvent::wait();}
00342 
00343     inline bool wait(timeout_t timeout)
00344         {return ucommon::TimedEvent::wait(timeout);}
00345 
00346     inline void signal(void)
00347         {ucommon::TimedEvent::signal();}
00348 
00349     inline void reset(void)
00350         {ucommon::TimedEvent::reset();}
00351 
00352     inline void set(timeout_t timeout = 0)
00353         {ucommon::TimedEvent::set(timeout);}
00354 };
00355 
00356 class __EXPORT Thread : protected ucommon::JoinableThread
00357 {
00358 public:
00362     typedef enum Throw {
00363         throwNothing,  
00364         throwObject,   
00365         throwException 
00366     } Throw;
00367 
00368 private:
00369     friend class Slog;
00370 
00371     Throw exceptions;
00372     bool detached, terminated;
00373     Thread *parent;
00374     size_t msgpos;
00375     char msgbuf[128];
00376 
00377 public:
00378     Thread(int pri = 0, size_t stack = 0);
00379 
00380     virtual ~Thread();
00381 
00382     inline void map(void)
00383         {JoinableThread::map();}
00384 
00385     virtual void initial(void);
00386     virtual void notify(Thread *thread);
00387     virtual void final(void);
00388     virtual void run(void) = 0;
00389 
00390     void terminate(void);
00391     void finalize(void);
00392 
00393     void detach(void);
00394     void start(void);
00395     void exit(void);
00396 
00397     inline void join(void)
00398         {JoinableThread::join();}
00399 
00400     inline void sync(void)
00401         {Thread::exit();}
00402 
00403     static inline Thread *get(void)
00404         {return (Thread *)JoinableThread::get();}
00405 
00406     inline static void yield(void)
00407         {ucommon::Thread::yield();}
00408 
00409     inline static void sleep(timeout_t msec = TIMEOUT_INF)
00410         {ucommon::Thread::sleep(msec);}
00411 
00412     bool isRunning(void);
00413 
00414     bool isThread(void);
00415 
00421     static Throw getException(void);
00422 
00428     static void setException(Throw mode);
00429 
00433     inline pthread_t getId(void)
00434         {return tid;}
00435 };
00436 
00466 class __EXPORT SysTime
00467 {
00468 public:
00469     static time_t getTime(time_t *tloc = NULL);
00470     static time_t time(time_t *tloc)
00471         {return getTime(tloc);}
00472 
00473     static int getTimeOfDay(struct timeval *tp);
00474     static int gettimeofday(struct timeval *tp, struct timezone *)
00475         {return getTimeOfDay(tp);}
00476 
00477     static struct tm *getLocalTime(const time_t *clock, struct tm *result);
00478     static struct tm *locatime(const time_t *clock, struct tm *result)
00479         {return getLocalTime(clock, result);}
00480 
00481     static struct tm *getGMTTime(const time_t *clock, struct tm *result);
00482     static struct tm *gmtime(const time_t *clock, struct tm *result)
00483         {return getGMTTime(clock, result);}
00484 };
00485 
00496 class __EXPORT TimerPort
00497 {
00498 #ifndef _MSWINDOWS_
00499     struct timeval timer;
00500 #else
00501     DWORD timer;
00502 #endif
00503     bool active;
00504 
00505 public:
00512     TimerPort();
00513 
00522     void setTimer(timeout_t timeout = 0);
00523 
00533     void incTimer(timeout_t timeout);
00534 
00544     void decTimer(timeout_t timeout);
00545 
00550     void sleepTimer(void);
00551 
00557     void endTimer(void);
00558 
00570     timeout_t getTimer(void) const;
00571 
00581     timeout_t getElapsed(void) const;
00582 };
00583 
00584 #ifndef _MSWINDOWS_
00585 struct  timespec *getTimeout(struct timespec *spec, timeout_t timeout);
00586 #endif
00587 
00588 #if !defined(_MSWINDOWS_) || defined(_MSTHREADS_)
00589 inline struct tm *localtime_r(const time_t *t, struct tm *b)
00590     {return SysTime::getLocalTime(t, b);}
00591 
00592 inline char *ctime_r(const time_t *t, char *buf)
00593     {return ctime(t);}
00594 
00595 inline struct tm *gmtime_r(const time_t *t, struct tm *b)
00596     {return SysTime::getGMTTime(t, b);}
00597 
00598 inline char *asctime_r(const struct tm *tm, char *b)
00599     {return asctime(tm);}
00600 #endif
00601 
00602 inline Thread *getThread(void)
00603     {return Thread::get();}
00604 
00626 #ifdef  _MSWINDOWS_
00627 class __EXPORT Buffer : public Mutex
00628 #else
00629 class __EXPORT Buffer : public Conditional
00630 #endif
00631 {
00632 private:
00633 #ifdef  _MSWINDOWS_
00634     HANDLE  sem_head, sem_tail;
00635 #endif
00636     size_t _size;
00637     size_t _used;
00638 
00639 protected:
00645     virtual size_t onPeek(void *buf) = 0;
00646 
00652     virtual size_t onWait(void *buf) = 0;
00653 
00659     virtual size_t onPost(void *buf) = 0;
00660 
00661 public:
00666     static const size_t timeout;
00667 
00672     Buffer(size_t capacity);
00677     virtual ~Buffer();
00678 
00683     inline size_t getSize(void)
00684         {return _size;}
00685 
00692     inline size_t getUsed(void)
00693         {return _used;}
00694 
00704     size_t wait(void *buf, timeout_t timeout = 0);
00705 
00714     size_t post(void *buf, timeout_t timeout = 0);
00715 
00722     size_t peek(void *buf);
00723 
00728     virtual bool isValid(void);
00729 };
00730 
00738 class __EXPORT FixedBuffer : public Buffer
00739 {
00740 private:
00741     char *buf, *head, *tail;
00742     size_t objsize;
00743 
00744 protected:
00750     size_t onPeek(void *buf);
00751 
00757     size_t onWait(void *buf);
00758 
00764     size_t onPost(void *buf);
00765 
00766 public:
00774     FixedBuffer(size_t capacity, size_t objsize);
00775 
00782     FixedBuffer(const FixedBuffer &fb);
00783 
00787     virtual ~FixedBuffer();
00788 
00789     FixedBuffer &operator=(const FixedBuffer &fb);
00790 
00791     bool isValid(void);
00792 };
00793 
00809 class __EXPORT ThreadQueue : public Mutex, public Thread, public Semaphore
00810 {
00811 private:
00812     void run(void);         // private run method
00813 
00814 protected:
00815     typedef struct _data {
00816         struct _data *next;
00817         unsigned len;
00818         char data[1];
00819     }   data_t;
00820 
00821     timeout_t timeout;
00822     bool started;
00823 
00824     data_t *first, *last;       // head/tail of list
00825 
00826     String name;
00827 
00828     /*
00829      * Overloading of final(). It demarks Semaphore to avoid deadlock.
00830      */
00831     virtual void final();
00832 
00837     virtual void startQueue(void);
00838 
00844     virtual void stopQueue(void);
00845 
00849     virtual void onTimer(void);
00850 
00859     virtual void runQueue(void *data) = 0;
00860 
00861 public:
00869     ThreadQueue(const char *id, int pri, size_t stack = 0);
00870 
00874     virtual ~ThreadQueue();
00875 
00883     void setTimer(timeout_t timeout);
00884 
00893     void post(const void *data, unsigned len);
00894 };
00895 
00896 
00898 inline size_t get(Buffer &b, void *o, timeout_t t = 0)
00899     {return b.wait(o, t);}
00900 
00902 inline size_t put(Buffer &b, void *o, timeout_t t = 0)
00903     {return b.post(o, t);}
00904 
00906 inline size_t peek(Buffer &b, void *o)
00907     {return b.peek(o);}
00908 
00909 } // namespace ost
00910 
00911 #endif