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