ucommon
commoncpp/thread.h
Go to the documentation of this file.
00001 // Copyright (C) 1999-2005 Open Source Telecom Corporation.
00002 // Copyright (C) 2006-2010 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 General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 
00023 #ifndef COMMONCPP_THREAD_H_
00024 #define COMMONCPP_THREAD_H_
00025 
00026 #ifndef COMMONCPP_CONFIG_H_
00027 #include <commoncpp/config.h>
00028 #endif
00029 
00030 #ifndef COMMONCPP_STRING_H_
00031 #include <commoncpp/string.h>
00032 #endif
00033 
00034 #define ENTER_CRITICAL  enterMutex();
00035 #define LEAVE_CRITICAL  leaveMutex();
00036 
00037 NAMESPACE_COMMONCPP
00038 
00039 class __EXPORT Mutex : protected ucommon::RecursiveMutex
00040 {
00041 public:
00042     inline Mutex() : RecursiveMutex() {};
00043 
00044     inline void enterMutex(void)
00045         {RecursiveMutex::lock();};
00046 
00047     inline void leaveMutex(void)
00048         {RecursiveMutex::release();};
00049 
00050     inline bool tryEnterMutex(void)
00051         {return RecursiveMutex::lock(0l);};
00052 
00053     inline void enter(void)
00054         {RecursiveMutex::lock();};
00055 
00056     inline void leave(void)
00057         {RecursiveMutex::release();};
00058 
00059     inline bool test(void)
00060         {return RecursiveMutex::lock(0l);};
00061 
00062 };
00063 
00073 class __EXPORT MutexCounter : public Mutex
00074 {
00075 protected:
00076     volatile int    counter;
00077 
00078 public:
00082     MutexCounter();
00083 
00090     MutexCounter(int initial);
00091 
00092     int operator++();
00093     int operator--();
00094 };
00095 
00119 class __EXPORT MutexLock
00120 {
00121 private:
00122     Mutex& mutex;
00123 
00124 public:
00130     inline MutexLock( Mutex& _mutex ) : mutex( _mutex )
00131         { mutex.enterMutex(); }
00132 
00136     // this should be not-virtual
00137     inline ~MutexLock()
00138         { mutex.leaveMutex(); }
00139 };
00140 
00141 class __EXPORT ThreadLock : protected ucommon::ThreadLock
00142 {
00143 public:
00144     inline ThreadLock() : ucommon::ThreadLock() {};
00145 
00146     inline void readLock(void)
00147         {ucommon::ThreadLock::access();};
00148 
00149     inline void writeLock(void)
00150         {ucommon::ThreadLock::modify();};
00151 
00152     inline void tryReadLock(void)
00153         {ucommon::ThreadLock::access(0);};
00154 
00155     inline void tryWriteLock(void)
00156         {ucommon::ThreadLock::modify(0);};
00157 
00158     inline void unlock(void)
00159         {ucommon::ThreadLock::release();};
00160 };
00161 
00182 class __EXPORT ReadLock
00183 {
00184 private:
00185     ThreadLock& tl;
00186 
00187 public:
00193     inline ReadLock( ThreadLock& _tl ) : tl( _tl )
00194         { tl.readLock(); }
00198     // this should be not-virtual
00199     inline ~ReadLock()
00200         { tl.unlock(); }
00201 };
00202 
00223 class __EXPORT WriteLock
00224 {
00225 private:
00226     ThreadLock& tl;
00227 
00228 public:
00234     inline WriteLock( ThreadLock& _tl ) : tl( _tl )
00235         { tl.writeLock(); }
00239     // this should be not-virtual
00240     inline ~WriteLock()
00241         { tl.unlock(); }
00242 };
00243 
00244 class __EXPORT Conditional : private ucommon::Conditional
00245 {
00246 public:
00247     inline Conditional() : ucommon::Conditional() {};
00248 
00249     bool wait(timeout_t timeout, bool locked = false);
00250 
00251     void signal(bool broadcast);
00252 
00253     inline void enterMutex(void)
00254         {ucommon::Conditional::lock();};
00255 
00256     inline void leaveMutex(void)
00257         {ucommon::Conditional::unlock();};
00258 };
00259 
00260 class __EXPORT Semaphore : private ucommon::Semaphore
00261 {
00262 public:
00263     inline Semaphore(unsigned size) : ucommon::Semaphore(size) {};
00264 
00265     inline bool wait(timeout_t timeout = 0)
00266         {return ucommon::Semaphore::wait(timeout);};
00267 
00268     inline void post(void)
00269         {ucommon::Semaphore::release();};
00270 };
00271 
00291 class __EXPORT SemaphoreLock
00292 {
00293 private:
00294     Semaphore& sem;
00295 
00296 public:
00300     inline SemaphoreLock( Semaphore& _sem ) : sem( _sem )
00301         { sem.wait(); }
00305     // this should be not-virtual
00306     inline ~SemaphoreLock()
00307         { sem.post(); }
00308 };
00309 
00310 class __EXPORT Event : private ucommon::TimedEvent
00311 {
00312 public:
00313     inline Event() : TimedEvent() {};
00314 
00315     inline void wait(void)
00316         {ucommon::TimedEvent::wait(Timer::inf);};
00317 
00318     inline bool wait(timeout_t timeout)
00319         {return ucommon::TimedEvent::wait(timeout);};
00320 
00321     inline void signal(void)
00322         {ucommon::TimedEvent::signal();};
00323 
00324     inline void reset(void)
00325         {ucommon::TimedEvent::reset();};
00326 };
00327 
00328 class __EXPORT Thread : protected ucommon::JoinableThread
00329 {
00330 public:
00334     typedef enum Throw {
00335         throwNothing,  
00336         throwObject,   
00337         throwException 
00338     } Throw;
00339 
00340 private:
00341     friend class Slog;
00342 
00343     Throw exceptions;
00344     bool detached, terminated;
00345     Thread *parent;
00346     size_t msgpos;
00347     char msgbuf[128];
00348 
00349 public:
00350     Thread(int pri = 0, size_t stack = 0);
00351 
00352     virtual ~Thread();
00353 
00354     inline void map(void)
00355         {JoinableThread::map();};
00356 
00357     virtual void initial(void);
00358     virtual void notify(Thread *thread);
00359     virtual void final(void);
00360     virtual void run(void) = 0;
00361 
00362     void terminate(void);
00363     void finalize(void);
00364 
00365     void detach(void);
00366     void start(void);
00367     void exit(void);
00368 
00369     inline void join(void)
00370         {JoinableThread::join();};
00371 
00372     inline void sync(void)
00373         {Thread::exit();};
00374 
00375     static inline Thread *get(void)
00376         {return (Thread *)JoinableThread::get();};
00377 
00378     inline static void yield(void)
00379         {ucommon::Thread::yield();};
00380 
00381     inline static void sleep(timeout_t msec = TIMEOUT_INF)
00382         {ucommon::Thread::sleep(msec);};
00383 
00384     bool isRunning(void);
00385 
00386     bool isThread(void);
00387 
00393     static Throw getException(void);
00394 
00400     static void setException(Throw mode);
00401 
00405     inline pthread_t getId(void)
00406         {return tid;};
00407 };
00408 
00438 class __EXPORT SysTime
00439 {
00440 public:
00441     static time_t getTime(time_t *tloc = NULL);
00442     static time_t time(time_t *tloc)
00443         { return getTime(tloc); };
00444 
00445     static int getTimeOfDay(struct timeval *tp);
00446     static int gettimeofday(struct timeval *tp, struct timezone *)
00447         { return getTimeOfDay(tp); };
00448 
00449     static struct tm *getLocalTime(const time_t *clock, struct tm *result);
00450     static struct tm *locatime(const time_t *clock, struct tm *result)
00451         { return getLocalTime(clock, result); };
00452 
00453     static struct tm *getGMTTime(const time_t *clock, struct tm *result);
00454     static struct tm *gmtime(const time_t *clock, struct tm *result)
00455         { return getGMTTime(clock, result);};
00456 };
00457 
00468 class __EXPORT TimerPort
00469 {
00470 #ifndef _MSWINDOWS_
00471     struct timeval timer;
00472 #else
00473     DWORD timer;
00474 #endif
00475     bool active;
00476 
00477 public:
00484     TimerPort();
00485 
00494     void setTimer(timeout_t timeout = 0);
00495 
00505     void incTimer(timeout_t timeout);
00506 
00516     void decTimer(timeout_t timeout);
00517 
00522     void sleepTimer(void);
00523 
00529     void endTimer(void);
00530 
00542     timeout_t getTimer(void) const;
00543 
00553     timeout_t getElapsed(void) const;
00554 };
00555 
00556 #ifndef _MSWINDOWS_
00557 struct  timespec *getTimeout(struct timespec *spec, timeout_t timeout);
00558 #endif
00559 
00560 inline struct tm *localtime_r(const time_t *t, struct tm *b)
00561     {return SysTime::getLocalTime(t, b);}
00562 
00563 inline char *ctime_r(const time_t *t, char *buf)
00564     {return ctime(t);}
00565 
00566 inline struct tm *gmtime_r(const time_t *t, struct tm *b)
00567     {return SysTime::getGMTTime(t, b);}
00568 
00569 inline char *asctime_r(const struct tm *tm, char *b)
00570     {return asctime(tm);}
00571 
00572 inline Thread *getThread(void)
00573     {return Thread::get();}
00574 
00596 #ifdef  _MSWINDOWS_
00597 class __EXPORT Buffer : public Mutex
00598 #else
00599 class __EXPORT Buffer : public Conditional
00600 #endif
00601 {
00602 private:
00603 #ifdef  _MSWINDOWS_
00604     HANDLE  sem_head, sem_tail;
00605 #endif
00606     size_t _size;
00607     size_t _used;
00608 
00609 protected:
00615     virtual size_t onPeek(void *buf) = 0;
00616 
00622     virtual size_t onWait(void *buf) = 0;
00623 
00629     virtual size_t onPost(void *buf) = 0;
00630 
00631 public:
00636     static const size_t timeout;
00637 
00642     Buffer(size_t capacity);
00647     virtual ~Buffer();
00648 
00653     inline size_t getSize(void)
00654         {return _size;};
00655 
00662     inline size_t getUsed(void)
00663         {return _used;};
00664 
00674     size_t wait(void *buf, timeout_t timeout = 0);
00675 
00684     size_t post(void *buf, timeout_t timeout = 0);
00685 
00692     size_t peek(void *buf);
00693 
00698     virtual bool isValid(void);
00699 };
00700 
00708 class __EXPORT FixedBuffer : public Buffer
00709 {
00710 private:
00711     char *buf, *head, *tail;
00712     size_t objsize;
00713 
00714 protected:
00720     size_t onPeek(void *buf);
00721 
00727     size_t onWait(void *buf);
00728 
00734     size_t onPost(void *buf);
00735 
00736 public:
00744     FixedBuffer(size_t capacity, size_t objsize);
00745 
00752     FixedBuffer(const FixedBuffer &fb);
00753 
00757     virtual ~FixedBuffer();
00758 
00759     FixedBuffer &operator=(const FixedBuffer &fb);
00760 
00761     bool isValid(void);
00762 };
00763 
00779 class __EXPORT ThreadQueue : public Mutex, public Thread, public Semaphore
00780 {
00781 private:
00782     void run(void);         // private run method
00783 
00784 protected:
00785     typedef struct _data {
00786         struct _data *next;
00787         unsigned len;
00788         char data[1];
00789     }   data_t;
00790 
00791     timeout_t timeout;
00792     bool started;
00793 
00794     data_t *first, *last;       // head/tail of list
00795 
00796     String name;
00797 
00798     /*
00799      * Overloading of final(). It demarks Semaphore to avoid deadlock.
00800      */
00801     virtual void final();
00802 
00807     virtual void startQueue(void);
00808 
00814     virtual void stopQueue(void);
00815 
00819     virtual void onTimer(void);
00820 
00829     virtual void runQueue(void *data) = 0;
00830 
00831 public:
00839     ThreadQueue(const char *id, int pri, size_t stack = 0);
00840 
00844     virtual ~ThreadQueue();
00845 
00853     void setTimer(timeout_t timeout);
00854 
00863     void post(const void *data, unsigned len);
00864 };
00865 
00866 
00868 inline size_t get(Buffer &b, void *o, timeout_t t = 0)
00869     {return b.wait(o, t);}
00870 
00872 inline size_t put(Buffer &b, void *o, timeout_t t = 0)
00873     {return b.post(o, t);}
00874 
00876 inline size_t peek(Buffer &b, void *o)
00877     {return b.peek(o);}
00878 
00879 END_NAMESPACE
00880 
00881 #endif