ucommon
|
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