UCommon
thread.h
Go to the documentation of this file.
1 // Copyright (C) 1999-2005 Open Source Telecom Corporation.
2 // Copyright (C) 2006-2014 David Sugar, Tycho Softworks.
3 // Copyright (C) 2015 Cherokees of Idaho.
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // As a special exception, you may use this file as part of a free software
19 // library without restriction. Specifically, if other files instantiate
20 // templates or use macros or inline functions from this file, or you compile
21 // this file and link it with other files to produce an executable, this
22 // file does not by itself cause the resulting executable to be covered by
23 // the GNU General Public License. This exception does not however
24 // invalidate any other reasons why the executable file might be covered by
25 // the GNU General Public License.
26 //
27 // This exception applies only to the code released under the name GNU
28 // Common C++. If you copy code from other releases into a copy of GNU
29 // Common C++, as the General Public License permits, the exception does
30 // not apply to the code that you add in this way. To avoid misleading
31 // anyone as to the status of such modified files, you must delete
32 // this exception notice from them.
33 //
34 // If you write modifications of your own for GNU Common C++, it is your choice
35 // whether to permit this exception to apply to your modifications.
36 // If you do not wish that, delete this exception notice.
37 //
38 
44 #ifndef COMMONCPP_THREAD_H_
45 #define COMMONCPP_THREAD_H_
46 
47 #ifndef COMMONCPP_CONFIG_H_
48 #include <commoncpp/config.h>
49 #endif
50 
51 #ifndef COMMONCPP_STRING_H_
52 #include <commoncpp/string.h>
53 #endif
54 
55 #define ENTER_CRITICAL enterMutex();
56 #define LEAVE_CRITICAL leaveMutex();
57 
58 #include <time.h>
59 
60 namespace ost {
61 
62 class __EXPORT Mutex : protected ucommon::RecursiveMutex
63 {
64 private:
65  __DELETE_COPY(Mutex);
66 
67 public:
68  inline Mutex() : RecursiveMutex() {}
69 
70  inline void enterMutex(void) {
71  RecursiveMutex::lock();
72  }
73 
74  inline void leaveMutex(void) {
75  RecursiveMutex::release();
76  }
77 
78  inline bool tryEnterMutex(void) {
79  return RecursiveMutex::lock(0l);
80  }
81 
82  inline void enter(void) {
83  RecursiveMutex::lock();
84  }
85 
86  inline void leave(void) {
87  RecursiveMutex::release();
88  }
89 
90  inline bool test(void) {
91  return RecursiveMutex::lock(0l);
92  }
93 };
94 
104 class __EXPORT MutexCounter : public Mutex
105 {
106 private:
107  __DELETE_COPY(MutexCounter);
108 
109 protected:
110  volatile int counter;
111 
112 public:
117 
124  MutexCounter(int initial);
125 
126  int operator++();
127  int operator--();
128 };
129 
153 class __EXPORT MutexLock
154 {
155 private:
156  Mutex& mutex;
157 
158  __DELETE_COPY(MutexLock);
159 
160 public:
166  inline MutexLock( Mutex& _mutex ) : mutex( _mutex ) {
167  mutex.enterMutex();
168  }
169 
173  // this should be not-virtual
174  inline ~MutexLock() {
175  mutex.leaveMutex();
176  }
177 };
178 
179 class __EXPORT ThreadLock : protected ucommon::RWLock
180 {
181 private:
182  __DELETE_COPY(ThreadLock);
183 
184 public:
185  inline ThreadLock() : ucommon::RWLock() {}
186 
187  inline void readLock(void) {
189  }
190 
191  inline void writeLock(void) {
193  }
194 
195  inline void tryReadLock(void) {
197  }
198 
199  inline void tryWriteLock(void) {
201  }
202 
203  inline void unlock(void) {
205  }
206 };
207 
228 class __EXPORT ReadLock
229 {
230 private:
231  ThreadLock& tl;
232 
233  __DELETE_COPY(ReadLock);
234 
235 public:
241  inline ReadLock( ThreadLock& _tl ) : tl( _tl ) {
242  tl.readLock();
243  }
247  // this should be not-virtual
248  inline ~ReadLock() {
249  tl.unlock();
250  }
251 };
252 
273 class __EXPORT WriteLock
274 {
275 private:
276  ThreadLock& tl;
277 
278  __DELETE_COPY(WriteLock);
279 
280 public:
286  inline WriteLock( ThreadLock& _tl ) : tl( _tl ) {
287  tl.writeLock();
288  }
292  // this should be not-virtual
293  inline ~WriteLock() {
294  tl.unlock();
295  }
296 };
297 
298 class __EXPORT Conditional : private ucommon::Conditional
299 {
300 private:
301  __DELETE_COPY(Conditional);
302 
303 public:
304  inline Conditional() : ucommon::Conditional() {}
305 
306  bool wait(timeout_t timeout, bool locked = false);
307 
308  void signal(bool broadcast);
309 
310  inline void enterMutex(void) {
312  }
313 
314  inline void leaveMutex(void) {
316  }
317 };
318 
319 class __EXPORT Semaphore : protected ucommon::Semaphore
320 {
321 public:
322  inline Semaphore(unsigned size = 0) : ucommon::Semaphore(size) {}
323 
324  inline bool wait(timeout_t timeout) {
325  return ucommon::Semaphore::wait(timeout);
326  }
327 
328  inline void wait(void) {
330  }
331 
332  inline void post(void) {
334  }
335 };
336 
356 class __EXPORT SemaphoreLock
357 {
358 private:
359  Semaphore& sem;
360 
361 public:
365  inline SemaphoreLock( Semaphore& _sem ) : sem( _sem ) {
366  sem.wait();
367  }
371  // this should be not-virtual
372  inline ~SemaphoreLock() {
373  sem.post();
374  }
375 };
376 
377 class __EXPORT Event : private ucommon::TimedEvent
378 {
379 private:
380  __DELETE_COPY(Event);
381 
382 public:
383  inline Event() : ucommon::TimedEvent() {}
384 
385  inline void wait(void) {
387  }
388 
389  inline bool wait(timeout_t timeout) {
390  return ucommon::TimedEvent::wait(timeout);
391  }
392 
393  inline void signal(void) {
395  }
396 
397  inline void reset(void) {
399  }
400 
401  inline void set(timeout_t timeout = 0) {
402  ucommon::TimedEvent::set(timeout);
403  }
404 };
405 
406 class __EXPORT Thread : protected ucommon::JoinableThread
407 {
408 public:
412  typedef enum Throw {
413  throwNothing,
414  throwObject,
415  throwException
416  } Throw;
417 
418 private:
419  friend class Slog;
420 
421  Throw exceptions;
422  bool detached, terminated;
423  Thread *parent;
424  size_t msgpos;
425  char msgbuf[128];
426 
427  __DELETE_COPY(Thread);
428 
429 public:
430  Thread(int pri = 0, size_t stack = 0);
431 
432  virtual ~Thread();
433 
434  inline void map(void) {
435  JoinableThread::map();
436  }
437 
438  virtual void initial(void);
439  virtual void notify(Thread *thread);
440  virtual void final(void);
441  virtual void run(void) __OVERRIDE = 0;
442 
443  void terminate(void);
444  void finalize(void);
445 
446  void detach(void);
447  void start(void);
448  void exit(void);
449 
450  inline void join(void) {
451  JoinableThread::join();
452  }
453 
454  inline void sync(void) {
455  Thread::exit();
456  }
457 
458  static inline Thread *get(void) {
459  return (Thread *)JoinableThread::get();
460  }
461 
462  inline static void yield(void) {
464  }
465 
466  inline static void sleep(timeout_t msec = TIMEOUT_INF) {
468  }
469 
470  bool isRunning(void);
471 
472  bool isThread(void);
473 
479  static Throw getException(void);
480 
486  static void setException(Throw mode);
487 
491  inline pthread_t getId(void) const {
492  return tid;
493  }
494 };
495 
525 class __EXPORT SysTime
526 {
527 private:
528  __DELETE_DEFAULTS(SysTime);
529 
530 public:
531  static time_t getTime(time_t *tloc = NULL);
532  static time_t time(time_t *tloc) {
533  return getTime(tloc);
534  }
535 
536  static int getTimeOfDay(struct timeval *tp);
537  static int gettimeofday(struct timeval *tp, struct timezone *) {
538  return getTimeOfDay(tp);
539  }
540 
541  static struct tm *getLocalTime(const time_t *clock, struct tm *result);
542  static struct tm *locatime(const time_t *clock, struct tm *result) {
543  return getLocalTime(clock, result);
544  }
545 
546  static struct tm *getGMTTime(const time_t *clock, struct tm *result);
547  static struct tm *gmtime(const time_t *clock, struct tm *result) {
548  return getGMTTime(clock, result);
549  }
550 };
551 
562 class __EXPORT TimerPort
563 {
564 private:
565 #ifndef _MSWINDOWS_
566  struct timeval timer;
567 #else
568  DWORD timer;
569 #endif
570  bool active;
571 
572  __DELETE_COPY(TimerPort);
573 
574 public:
582 
591  void setTimer(timeout_t timeout = 0);
592 
602  void incTimer(timeout_t timeout);
603 
613  void decTimer(timeout_t timeout);
614 
619  void sleepTimer(void);
620 
626  void endTimer(void);
627 
639  timeout_t getTimer(void) const;
640 
650  timeout_t getElapsed(void) const;
651 };
652 
653 #ifndef _MSWINDOWS_
654 struct timespec *getTimeout(struct timespec *spec, timeout_t timeout);
655 #endif
656 
657 #if !defined(_MSWINDOWS_) || defined(_MSTHREADS_)
658 inline struct tm *localtime_r(const time_t *t, struct tm *b) {
659  return SysTime::getLocalTime(t, b);
660 }
661 
662 inline char *ctime_r(const time_t *t, char *buf) {
663  return ctime(t);
664 }
665 
666 inline struct tm *gmtime_r(const time_t *t, struct tm *b) {
667  return SysTime::getGMTTime(t, b);
668 }
669 
670 inline char *asctime_r(const struct tm *tm, char *b) {
671  return asctime(tm);
672 }
673 #endif
674 
675 inline Thread *getThread(void) {
676  return Thread::get();
677 }
678 
700 #ifdef _MSWINDOWS_
701 class __EXPORT Buffer : public Mutex
702 #else
703 class __EXPORT Buffer : public Conditional
704 #endif
705 {
706 private:
707 #ifdef _MSWINDOWS_
708  HANDLE sem_head, sem_tail;
709 #endif
710  size_t _size;
711  size_t _used;
712 
713 protected:
719  virtual size_t onPeek(void *buf) = 0;
720 
726  virtual size_t onWait(void *buf) = 0;
727 
733  virtual size_t onPost(void *buf) = 0;
734 
735 public:
740  static const size_t timeout;
741 
746  Buffer(size_t capacity);
751  virtual ~Buffer();
752 
757  inline size_t getSize(void) const {
758  return _size;
759  }
760 
767  inline size_t getUsed(void) const {
768  return _used;
769  }
770 
780  size_t wait(void *buf, timeout_t timeout = 0);
781 
790  size_t post(void *buf, timeout_t timeout = 0);
791 
798  size_t peek(void *buf);
799 
804  virtual bool isValid(void);
805 };
806 
814 class __EXPORT FixedBuffer : public Buffer
815 {
816 private:
817  char *buf, *head, *tail;
818  size_t objsize;
819 
820 protected:
826  size_t onPeek(void *buf) __OVERRIDE;
827 
833  size_t onWait(void *buf) __OVERRIDE;
834 
840  size_t onPost(void *buf) __OVERRIDE;
841 
842 public:
850  FixedBuffer(size_t capacity, size_t objsize);
851 
859 
863  virtual ~FixedBuffer();
864 
865  FixedBuffer &operator=(const FixedBuffer &fb);
866 
867  bool isValid(void) __OVERRIDE;
868 };
869 
885 class __EXPORT ThreadQueue : public Mutex, public Thread, public Semaphore
886 {
887 private:
888  void run(void) __FINAL; // private run method
889 
890  __DELETE_COPY(ThreadQueue);
891 
892 protected:
893  typedef struct _data {
894  struct _data *next;
895  unsigned len;
896  char data[1];
897  } data_t;
898 
899  timeout_t timeout;
900  bool started;
901 
902  data_t *first, *last; // head/tail of list
903 
904  String name;
905 
906  /*
907  * Overloading of final(). It demarks Semaphore to avoid deadlock.
908  */
909  virtual void final() __OVERRIDE;
910 
915  virtual void startQueue(void);
916 
922  virtual void stopQueue(void);
923 
927  virtual void onTimer(void);
928 
937  virtual void runQueue(void *data) = 0;
938 
939 public:
947  ThreadQueue(const char *id, int pri, size_t stack = 0);
948 
952  virtual ~ThreadQueue();
953 
961  void setTimer(timeout_t timeout);
962 
971  void post(const void *data, unsigned len);
972 };
973 
974 
976 inline size_t get(Buffer &b, void *o, timeout_t t = 0) {
977  return b.wait(o, t);
978 }
979 
981 inline size_t put(Buffer &b, void *o, timeout_t t = 0) {
982  return b.post(o, t);
983 }
984 
986 inline size_t peek(Buffer &b, void *o) {
987  return b.peek(o);
988 }
989 
990 } // namespace ost
991 
992 #endif
ost::Buffer::isValid
virtual bool isValid(void)
New virtual to test if buffer is a valid object.
ost::SemaphoreLock
The SemaphoreLock class is used to protect a section of code through a semaphore so that only x insta...
Definition: thread.h:357
ucommon::String
A copy-on-write string class that operates by reference count.
Definition: string.h:79
ost::WriteLock
The WriteLock class is used to protect a section of code through a ThreadLock for "write" access to t...
Definition: thread.h:274
ost::MutexCounter::MutexCounter
MutexCounter()
Create and optionally name a mutex protected counter.
ucommon::Semaphore::wait
void wait(void)
Wait until the semphore usage count is less than the thread limit.
ost::Buffer::wait
size_t wait(void *buf, timeout_t timeout=0)
Let one or more threads wait for an object to become available in the buffer.
ost::FixedBuffer::onPeek
size_t onPeek(void *buf)
Return the first object in the buffer.
ucommon::Semaphore::release
void release(void)
Release the semaphore after waiting for it.
ucommon::TimedEvent::signal
void signal(void)
Signal pending event.
ost::TimerPort::decTimer
void decTimer(timeout_t timeout)
Adjust a timeout based on the current time reference value either from object creation or the last se...
ost::SemaphoreLock::~SemaphoreLock
~SemaphoreLock()
Post the semaphore automatically.
Definition: thread.h:372
ost::TimerPort::incTimer
void incTimer(timeout_t timeout)
Set a timeout based on the current time reference value either from object creation or the last setTi...
ost::FixedBuffer::onPost
size_t onPost(void *buf)
Post an object of the appropriate size into the buffer.
ost::Buffer::post
size_t post(void *buf, timeout_t timeout=0)
Post an object into the buffer and enable a waiting thread to receive it.
ucommon::Thread::sleep
static void sleep(timeout_t timeout)
Sleep current thread for a specified time period.
ost::ReadLock
The ReadLock class is used to protect a section of code through a ThreadLock for "read" access to the...
Definition: thread.h:229
ucommon::Semaphore
A portable counting semaphore class.
Definition: condition.h:656
ost::TimerPort::setTimer
void setTimer(timeout_t timeout=0)
Set a new start time for the object based on when this call is made and optionally activate the timer...
ucommon::JoinableThread
A child thread object that may be joined by parent.
Definition: thread.h:824
ost::MutexCounter
The Mutex Counter is a counter variable which can safely be incremented or decremented by multiple th...
Definition: thread.h:105
ost::ThreadQueue::post
void post(const void *data, unsigned len)
Put some unspecified data into this queue.
string.h
Common C++ generic string class.
ost::ThreadQueue::stopQueue
virtual void stopQueue(void)
End of dequeing, we expect the queue is empty for now.
ost::Buffer::onPeek
virtual size_t onPeek(void *buf)=0
Invoke derived class buffer peeking method.
ost::ThreadQueue::runQueue
virtual void runQueue(void *data)=0
Virtual callback method to handle processing of a queued data items.
ost::Buffer::peek
size_t peek(void *buf)
Peek at the current content (first object) in the buffer.
ucommon::Timer::set
void set(void)
Set (update) the timer with current time.
ucommon::ConditionMutex::unlock
void unlock(void)
Unlock the conditional's supporting mutex.
Definition: condition.h:107
ucommon::ConditionMutex::lock
void lock(void)
Lock the conditional's supporting mutex.
Definition: condition.h:100
ost::MutexLock::~MutexLock
~MutexLock()
Release the mutex automatically.
Definition: thread.h:174
ucommon::RecursiveMutex
Portable recursive exclusive lock.
Definition: thread.h:370
ost::ThreadQueue::ThreadQueue
ThreadQueue(const char *id, int pri, size_t stack=0)
Create instance of our queue and give it a process priority.
ost::ThreadQueue::setTimer
void setTimer(timeout_t timeout)
Set the queue timeout.
ost::ReadLock::ReadLock
ReadLock(ThreadLock &_tl)
Wait for read access.
Definition: thread.h:241
ost::SemaphoreLock::SemaphoreLock
SemaphoreLock(Semaphore &_sem)
Wait for the semaphore.
Definition: thread.h:365
ucommon
Common namespace for all ucommon objects.
Definition: access.h:47
ost::TimerPort::getTimer
timeout_t getTimer(void) const
This is used by service threads to determine how much time remains before the timer expires based on ...
ost::TimerPort::sleepTimer
void sleepTimer(void)
Sleep until the current timer expires.
ost::TimerPort
Timer ports are used to provide synchronized timing events when managed under a "service thread" such...
Definition: thread.h:563
ost::WriteLock::~WriteLock
~WriteLock()
Post the semaphore automatically.
Definition: thread.h:293
ucommon::TimedEvent
Event notification to manage scheduled realtime threads.
Definition: thread.h:279
ucommon::RWLock::release
void release(void)
Release the lock.
ost::Buffer::getSize
size_t getSize(void) const
Return the capacity of the buffer as specified at creation.
Definition: thread.h:757
ost::ReadLock::~ReadLock
~ReadLock()
Post the semaphore automatically.
Definition: thread.h:248
ost::WriteLock::WriteLock
WriteLock(ThreadLock &_tl)
Wait for write access.
Definition: thread.h:286
ost::FixedBuffer::onWait
size_t onWait(void *buf)
Wait for and return a fixed object in the buffer.
ost::Buffer::onPost
virtual size_t onPost(void *buf)=0
Invoke derived class posting of object to buffer.
ost::ThreadQueue::onTimer
virtual void onTimer(void)
A derivable method to call when the timout is expired.
ost::ThreadQueue::~ThreadQueue
virtual ~ThreadQueue()
Destroy the queue.
ost::TimerPort::getElapsed
timeout_t getElapsed(void) const
This is used to determine how much time has elapsed since a timer port setTimer benchmark time was in...
ost::Buffer::~Buffer
virtual ~Buffer()
In derived functions, may be used to free the actual memory used to hold buffered data.
ost::Buffer::Buffer
Buffer(size_t capacity)
Create a buffer object of known capacity.
ost::FixedBuffer::isValid
bool isValid(void)
New virtual to test if buffer is a valid object.
ucommon::ConditionalAccess::modify
void modify(void)
Exclusive mode write thread scheduling.
ost::FixedBuffer::~FixedBuffer
virtual ~FixedBuffer()
Destroy the fixed buffer and free the memory used to store objects.
ost::Buffer::onWait
virtual size_t onWait(void *buf)=0
Invoke derived class object request from buffer.
ucommon::ConditionalAccess::access
void access(void)
Access mode shared thread scheduling.
ost::FixedBuffer
A buffer class that holds a known capacity of fixed sized objects defined during creation.
Definition: thread.h:815
ost::FixedBuffer::FixedBuffer
FixedBuffer(size_t capacity, size_t objsize)
Create a buffer of known capacity for objects of a specified size.
ost::SysTime
This class is used to access non-reentrant date and time functions in the standard C library.
Definition: thread.h:526
ost::FixedBuffer::FixedBuffer
FixedBuffer(const FixedBuffer &fb)
Create a copy of an existing fixed size buffer and duplicate it's contents.
ucommon::TimedEvent::wait
void wait(void)
A simple wait until triggered.
ucommon::RWLock
A generic and portable implementation of Read/Write locking.
Definition: thread.h:84
ost::ThreadQueue
Somewhat generic queue processing class to establish a producer consumer queue.
Definition: thread.h:886
ost::Buffer::getUsed
size_t getUsed(void) const
Return the current capacity in use for the buffer.
Definition: thread.h:767
ost::MutexCounter::MutexCounter
MutexCounter(int initial)
Create and optionally name a mutex protected counter with an initial value.
ucommon::Conditional
The conditional is a common base for other thread synchronizing classes.
Definition: condition.h:228
ost::TimerPort::endTimer
void endTimer(void)
This is used to "disable" the service thread from expiring the timer object.
ucommon::TimedEvent::reset
void reset(void)
Reset triggered conditional.
ucommon::Thread::yield
static void yield(void)
Yield execution context of the current thread.
ost::Buffer::timeout
static const size_t timeout
value to return when a timed operation returned with a timeout.
Definition: thread.h:740
ost::Buffer
The buffer class represents an IPC service that is built upon a buffer of fixed capacity that can be ...
Definition: thread.h:705
ost::MutexLock
The MutexLock class is used to protect a section of code so that at any given time only a single thre...
Definition: thread.h:154
ost::TimerPort::TimerPort
TimerPort()
Create a timer, mark it as inactive, and set the initial "start" time to the creation time of the tim...
ost::MutexLock::MutexLock
MutexLock(Mutex &_mutex)
Acquire the mutex.
Definition: thread.h:166
ost::ThreadQueue::startQueue
virtual void startQueue(void)
Start of dequeing.