GNU CommonC++
thread.h
Go to the documentation of this file.
1 // Copyright (C) 1999-2005 Open Source Telecom Corporation.
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 2 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 //
17 // As a special exception, you may use this file as part of a free software
18 // library without restriction. Specifically, if other files instantiate
19 // templates or use macros or inline functions from this file, or you compile
20 // this file and link it with other files to produce an executable, this
21 // file does not by itself cause the resulting executable to be covered by
22 // the GNU General Public License. This exception does not however
23 // invalidate any other reasons why the executable file might be covered by
24 // the GNU General Public License.
25 //
26 // This exception applies only to the code released under the name GNU
27 // Common C++. If you copy code from other releases into a copy of GNU
28 // Common C++, as the General Public License permits, the exception does
29 // not apply to the code that you add in this way. To avoid misleading
30 // anyone as to the status of such modified files, you must delete
31 // this exception notice from them.
32 //
33 // If you write modifications of your own for GNU Common C++, it is your choice
34 // whether to permit this exception to apply to your modifications.
35 // If you do not wish that, delete this exception notice.
36 //
37 
43 #ifndef CCXX_THREAD_H_
44 #define CCXX_THREAD_H_
45 
46 #include <cc++/config.h>
47 
48 #ifndef WIN32
49 #define CCXX_POSIX
50 #endif // !WIN32
51 
52 #include <ctime>
53 
54 #ifndef WIN32
55 #include <pthread.h>
56 #endif // !WIN32
57 
58 #undef CCXX_USE_WIN32_ATOMIC
59 #ifndef WIN32
60 #include <time.h>
61 #include <signal.h>
62 #include <unistd.h>
63 
64 #ifdef _THR_UNIXWARE
65 #undef PTHREAD_MUTEXTYPE_RECURSIVE
66 #endif
67 
68 typedef pthread_t cctid_t;
69 typedef unsigned long timeout_t;
70 
71 /*
72 #if defined(__CYGWIN32__)
73 __declspec(dllimport) long __stdcall InterlockedIncrement(long *);
74 __declspec(dllimport) long __stdcall InterlockedDecrement(long *);
75 __declspec(dllimport) long __stdcall InterlockedExchange(long *, long);
76 #define CCXX_USE_WIN32_ATOMIC 1
77 #endif
78 */
79 
80 #else // WIN32
81 typedef DWORD cctid_t;
82 typedef DWORD timeout_t;
83 
84 #define MAX_SEM_VALUE 1000000
85 #define CCXX_USE_WIN32_ATOMIC 1
86 
87 #endif // !WIN32
88 
89 #ifdef HAVE_GCC_CXX_BITS_ATOMIC
90 #include <ios>
91 #endif
92 
93 #ifdef CCXX_NAMESPACES
94 namespace ost {
95 #ifdef __BORLANDC__
96 # if __BORLANDC__ >= 0x0560
97 using std::time_t;
98 using std::tm;
99 # endif
100 #endif
101 #endif
102 
103 #ifdef HAVE_GCC_CXX_BITS_ATOMIC
104 using namespace __gnu_cxx;
105 #endif
106 
109 
110 #define TIMEOUT_INF ~((timeout_t) 0)
111 
112 #define ENTER_CRITICAL enterMutex();
113 #define LEAVE_CRITICAL leaveMutex();
114 #define ENTER_DEFERRED setCancel(cancelDeferred);
115 #define LEAVE_DEFERRED setCancel(cancelImmediate);
116 
117 #ifndef WIN32
118 // These macros override common functions with thread-safe versions. In
119 // particular the common "libc" sleep() has problems since it normally
120 // uses SIGARLM (as actually defined by "posix"). The pthread_delay and
121 // usleep found in libpthread are gaurenteed not to use SIGALRM and offer
122 // higher resolution. psleep() is defined to call the old process sleep.
123 
124 #undef sleep
125 #define psleep(x) (sleep)(x)
126 
127 #ifdef signal
128 #undef signal
129 #endif
130 
131 #endif // !WIN32
132 
133 #undef Yield
134 
137 
182 {
183 private:
184  static bool _debug;
185  const char *_name;
186 #ifndef WIN32
187 #ifndef PTHREAD_MUTEXTYPE_RECURSIVE
188  int volatile _level;
189  Thread *volatile _tid;
190 #endif
191  /*
192  * Pthread mutex object. This is protected rather than private
193  * because some mixed mode pthread operations require a mutex as
194  * well as their primary pthread object. A good example of this
195  * is the Event class, as waiting on a conditional object must be
196  * associated with an accessable mutex. An alternative would be
197  * to make such classes "friend" classes of the Mutex.
198  */
199  pthread_mutex_t _mutex;
200 #else // WIN32
201 
202 # if defined(MUTEX_UNDERGROUND_WIN32_MUTEX) && defined(MUTEX_UNDERGROUND_WIN32_CRITICALSECTION)
203 # error "Can't determine underground for Mutex"
204 # endif
205 
206 #ifdef MUTEX_UNDERGROUND_WIN32_MUTEX
207  HANDLE _mutex;
208 #endif
209 #ifdef MUTEX_UNDERGROUND_WIN32_CRITICALSECTION
210  CRITICAL_SECTION _criticalSection;
211 #endif
212 
213 #endif // WIN32
214 
215 public:
221  Mutex(const char *name = NULL);
222 
228  virtual ~Mutex();
229 
235  static void setDebug(bool mode)
236  {_debug = mode;};
237 
243  inline void nameMutex(const char *name)
244  {_name = name;};
245 
253  void enterMutex(void);
254 
258  inline void enter(void)
259  {enterMutex();};
260 
264  inline void leave(void)
265  {leaveMutex();};
266 
272  inline bool test(void)
273  {return tryEnterMutex();};
274 
285  bool tryEnterMutex(void);
286 
297  void leaveMutex(void);
298 };
299 
324 {
325 private:
326  Mutex& mutex;
327 public:
333  MutexLock( Mutex& _mutex ) : mutex( _mutex )
334  { mutex.enterMutex(); }
335 
339  // this should be not-virtual
341  { mutex.leaveMutex(); }
342 };
343 
353 {
354 private:
355 #ifdef HAVE_PTHREAD_RWLOCK
356  pthread_rwlock_t _lock;
357 #else
358  Mutex mutex;
359 #endif
360 
361 public:
365  ThreadLock();
366 
370  virtual ~ThreadLock();
371 
375  void readLock(void);
376 
380  void writeLock(void);
381 
387  bool tryReadLock(void);
388 
394  bool tryWriteLock(void);
395 
399  void unlock(void);
400 };
401 
423 {
424 private:
425  ThreadLock& tl;
426 
427 public:
433  ReadLock( ThreadLock& _tl ) : tl( _tl )
434  { tl.readLock(); }
438  // this should be not-virtual
440  { tl.unlock(); }
441 };
442 
464 {
465 private:
466  ThreadLock& tl;
467 
468 public:
474  WriteLock( ThreadLock& _tl ) : tl( _tl )
475  { tl.writeLock(); }
479  // this should be not-virtual
481  { tl.unlock(); }
482 };
483 
484 
495 {
496 private:
497  volatile int counter;
498 
499 public:
505  MutexCounter(const char *id = NULL);
506 
514  MutexCounter(int initial, const char *id = NULL);
515 
516  friend __EXPORT int operator++(MutexCounter &mc);
517  friend __EXPORT int operator--(MutexCounter &mc);
518 };
519 
531 {
532 #ifndef CCXX_USE_WIN32_ATOMIC
533 private:
534 #if defined(HAVE_ATOMIC_AIX)
535  volatile int counter;
536 #elif defined(HAVE_GCC_BITS_ATOMIC)
537  volatile _Atomic_word counter;
538 #elif defined(HAVE_GCC_CXX_BITS_ATOMIC)
539  volatile _Atomic_word counter;
540 // __gnu_cxx::_Atomic_word counter;
541 #elif defined(HAVE_ATOMIC)
542  atomic_t atomic;
543 #else
544  volatile int counter;
545  pthread_mutex_t _mutex;
546 #endif
547 
548 public:
552  AtomicCounter();
553 
559  AtomicCounter(int value);
560 
561  ~AtomicCounter();
562 
563  int operator++(void);
564  int operator--(void);
565  int operator+=(int change);
566  int operator-=(int change);
567  int operator+(int change);
568  int operator-(int change);
569  int operator=(int value);
570  bool operator!(void);
571  operator int();
572 #else
573 private:
574  long atomic;
575 
576 public:
577  inline AtomicCounter()
578  {atomic = 0;};
579 
580  inline AtomicCounter(int value)
581  {atomic = value;};
582 
583  inline int operator++(void)
584  {return InterlockedIncrement(&atomic);};
585 
586  inline int operator--(void)
587  {return InterlockedDecrement(&atomic);};
588 
589  int operator+=(int change);
590 
591  int operator-=(int change);
592 
593  inline int operator+(int change)
594  {return atomic + change;};
595 
596  inline int operator-(int change)
597  {return atomic - change;};
598 
599  inline int operator=(int value)
600  {return InterlockedExchange(&atomic, value);};
601 
602  inline bool operator!(void)
603  {return (atomic == 0) ? true : false;};
604 
605  inline operator int()
606  {return atomic;};
607 #endif
608 };
609 
610 #ifndef WIN32
611 
632 {
633 private:
634  pthread_cond_t _cond;
635  pthread_mutex_t _mutex;
636 
637 public:
643  Conditional(const char *id = NULL);
644 
648  virtual ~Conditional();
649 
655  void signal(bool broadcast);
656 
663  bool wait(timeout_t timer = 0, bool locked = false);
664 
671  void enterMutex(void);
672 
681  inline void lock(void)
682  {enterMutex();};
683 
694  bool tryEnterMutex(void);
695 
696  inline bool test(void)
697  {return tryEnterMutex();};
698 
704  void leaveMutex(void);
705 
706  inline void unlock(void)
707  {return leaveMutex();};
708 };
709 #endif
710 
729 {
730 private:
731 #ifndef WIN32
732  unsigned _count, _waiters;
733  pthread_mutex_t _mutex;
734  pthread_cond_t _cond;
735 #else
736  HANDLE semObject;
737 #endif // !WIN32
738 
739 public:
748  Semaphore(unsigned resource = 0);
749 
756  virtual ~Semaphore();
757 
773  bool wait(timeout_t timeout = 0);
774 
786  void post(void);
787 
788  // FIXME: how implement getValue for posix compatibility ?
789  // not portable...
790 
791 #if 0
792 
797  int getValue(void);
798 #endif
799 };
800 
821 {
822 private:
823  Semaphore& sem;
824 
825 public:
829  SemaphoreLock( Semaphore& _sem ) : sem( _sem )
830  { sem.wait(); }
834  // this should be not-virtual
836  { sem.post(); }
837 };
838 
853 {
854 private:
855 #ifndef WIN32
856  pthread_mutex_t _mutex;
857  pthread_cond_t _cond;
858  bool _signaled;
859  int _count;
860 #else
861  HANDLE cond;
862 #endif
863 
864 public:
865  Event();
866 
867  virtual ~Event();
868 
875  void reset(void);
876 
880  void signal(void);
881 
890  bool wait(timeout_t timer);
891  bool wait(void);
892 };
893 
894 
1077 {
1078 public:
1082  typedef enum Throw {
1085  throwException
1086  } Throw;
1087 
1091  typedef enum Cancel {
1092  cancelInitial=0,
1093  cancelDeferred=1,
1096  cancelManual,
1098  cancelDefault=cancelDeferred
1100  } Cancel;
1101 
1105  typedef enum Suspend {
1107  suspendDisable
1108  } Suspend;
1109 
1110 #ifndef WIN32
1111 
1112 friend class PosixThread;
1113 #endif
1114 
1115 friend class DummyThread;
1116 private:
1117  friend class Cancellation;
1118  friend class postream_type;
1119  friend class Slog;
1120 
1121  Semaphore joinSem;
1122  static Thread* _main;
1123 
1124  Thread *_parent;
1125  Cancel _cancel;
1126  Semaphore *_start;
1127 
1128  // private data
1129  friend class ThreadImpl;
1130  class ThreadImpl* priv;
1131 
1132 public:
1133  static Thread *get(void);
1134 
1135 private:
1136 #ifdef WIN32
1137  static unsigned __stdcall Execute(Thread *th);
1138 #endif
1139 
1140  // close current thread, free all and call Notify
1141  void close();
1142 
1143 private:
1144  char _name[32];
1145  static size_t _autostack;
1146 
1147 #ifdef WIN32
1148  DWORD waitHandle(HANDLE obj, timeout_t timeout);
1149 #endif
1150 
1151 protected:
1159  void setName(const char *text);
1160 
1170  virtual void run(void) = 0;
1171 
1193  virtual void final(void);
1194 
1206  virtual void initial(void);
1207 
1217  virtual void* getExtended(void);
1218 
1226  virtual void notify(Thread*);
1227 
1233  void exit(void);
1234 
1238  void sync(void);
1239 
1243  bool testCancel(void);
1244 
1254  void setCancel(Cancel mode);
1255 
1263  void setSuspend(Suspend mode);
1264 
1273  void terminate(void);
1274 
1278  inline void clrParent(void)
1279  {_parent = NULL;};
1280 
1281 public:
1290  Thread(bool isMain);
1291 
1303  Thread(int pri = 0, size_t stack = 0);
1304 
1305 #ifndef WIN32
1306 
1314  Thread(const Thread &th);
1315 #endif
1316 
1323  virtual ~Thread();
1324 
1330  static void setStack(size_t size = 0)
1331  {_autostack = size;};
1332 
1342  static void sleep(timeout_t msec);
1343 
1348  static void yield(void);
1349 
1362  int start(Semaphore *start = 0);
1363 
1372  int detach(Semaphore *start = 0);
1373 
1380  inline Thread *getParent(void)
1381  {return _parent;};
1382 
1389  void suspend(void);
1390 
1394  void resume(void);
1395 
1402  inline Cancel getCancel(void)
1403  {return _cancel;};
1404 
1411  bool isRunning(void) const;
1412 
1418  bool isDetached(void) const;
1419 
1423  void join(void);
1424 
1431  bool isThread(void) const;
1432 
1438  cctid_t getId(void) const;
1439 
1446  const char *getName(void) const
1447  {return _name;};
1448 
1454  static Throw getException(void);
1455 
1461  static void setException(Throw mode);
1462 
1469  friend inline void operator++(Thread &th)
1470  {if (th._start) th._start->post();};
1471 
1472  friend inline void operator--(Thread &th)
1473  {if (th._start) th._start->wait();};
1474 
1475 #ifdef WIN32
1476  bool isCancelled() const;
1477 
1478  static DWORD waitThread(HANDLE hRef, timeout_t timeout);
1479 #endif
1480 
1488  static Cancel enterCancel(void);
1489 
1495  static void exitCancel(Cancel cancel);
1496 };
1497 
1508 {
1509 private:
1510  Thread::Cancel prior;
1511 
1512 public:
1513  Cancellation(Thread::Cancel cancel);
1514  ~Cancellation();
1515 };
1516 
1517 #if !defined(WIN32) && !defined(__MINGW32__)
1518 typedef int signo_t;
1519 
1520 class PosixThread: public Thread
1521 {
1522 private:
1523 #ifndef WIN32
1524 
1525  friend class ThreadImpl;
1526  friend class Thread;
1527 #endif
1528 #ifndef CCXX_SIG_THREAD_ALARM
1529  static PosixThread *_timer;
1530  static Mutex _arm;
1531 #endif
1532 
1533  time_t _alarm;
1534  static void signalThread(Thread* th,signo_t signo);
1535 protected:
1536 
1543  inline void signalParent(signo_t signo)
1544  { signalThread(_parent,signo); };
1545 
1552  inline void signalMain(signo_t signo)
1553  { signalThread(_main,signo);};
1554 
1559  virtual void onTimer(void);
1560 
1565  virtual void onHangup(void);
1566 
1571  virtual void onException(void);
1572 
1577  virtual void onDisconnect(void);
1578 
1583  virtual void onPolling(void);
1584 
1591  virtual void onSignal(int);
1592 
1605  void setTimer(timeout_t timer, bool periodic = false);
1606 
1613  timeout_t getTimer(void) const;
1614 
1620  void endTimer(void);
1621 
1622 #if defined(HAVE_SIGWAIT) || defined(HAVE_SIGWAIT2)
1623 
1629  void waitSignal(signo_t signo);
1630 #endif
1631 
1638  void setSignal(int signo, bool active);
1639 
1646  pthread_attr_t *getPthreadAttrPtr(void);
1647 
1652  pthread_t getPthreadId(void);
1653 
1654 public:
1655 
1656  PosixThread(int pri = 0, size_t stack = 0);
1657 
1663  inline void signalThread(int signo)
1664  {signalThread(this, signo);};
1665 
1672  static void sigInstall(int signo);
1673 };
1674 #endif
1675 
1691 {
1692 private:
1693 #ifndef WIN32
1694  pthread_key_t key;
1695  typedef void (*TDestruct)(void*);
1696  friend class ThreadImpl;
1697  ThreadKey(TDestruct destruct);
1698 #else
1699  DWORD key;
1700 #endif
1701 
1702 public:
1706  ThreadKey();
1707 
1711  virtual ~ThreadKey();
1712 
1720  void *getKey(void);
1721 
1729  void setKey(void *);
1730 };
1731 
1743 {
1744 #ifndef WIN32
1745  struct timeval timer;
1746 #else
1747  DWORD timer;
1748 #endif
1749  bool active;
1750 
1751 public:
1758  TimerPort();
1759 
1768  void setTimer(timeout_t timeout = 0);
1769 
1779  void incTimer(timeout_t timeout);
1780 
1790  void decTimer(timeout_t timeout);
1791 
1796  void sleepTimer(void);
1797 
1803  void endTimer(void);
1804 
1816  timeout_t getTimer(void) const;
1817 
1827  timeout_t getElapsed(void) const;
1828 };
1829 
1830 
1831 
1832 // FIXME: not in win32 implementation
1833 #if !defined(WIN32)
1834 
1835 // FIXME: private declaration ???
1836 struct timespec *getTimeout(struct timespec *spec, timeout_t timeout);
1837 
1838 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
1839 void wait(signo_t signo);
1840 #endif
1841 
1842 #endif // !WIN32
1843 
1844 #ifdef USE_POLL
1845 
1853 class Poller
1854 {
1855 private:
1856  int nufds;
1857  pollfd *ufds;
1858 
1859 public:
1860  Poller();
1861 
1862  virtual ~Poller();
1863 
1871  pollfd *getList(int cnt);
1872 
1878  inline pollfd *getList(void)
1879  {return ufds;};
1880 };
1881 #endif
1882 
1883 inline Thread *getThread(void)
1884  {return Thread::get();}
1885 
1916 {
1917 private:
1918  static Mutex timeLock;
1919 
1920 protected:
1921  inline static void lock(void)
1922  {timeLock.enterMutex();}
1923 
1924  inline static void unlock(void)
1925  {timeLock.leaveMutex();}
1926 
1927 public:
1928  static time_t getTime(time_t *tloc = NULL);
1929  static time_t time(time_t *tloc)
1930  { return getTime(tloc); };
1931 
1932  static int getTimeOfDay(struct timeval *tp);
1933  static int gettimeofday(struct timeval *tp, struct timezone *)
1934  { return getTimeOfDay(tp); };
1935 
1936  static struct tm *getLocalTime(const time_t *clock, struct tm *result);
1937  static struct tm *locatime(const time_t *clock, struct tm *result)
1938  { return getLocalTime(clock, result); };
1939 
1940  static struct tm *getGMTTime(const time_t *clock, struct tm *result);
1941  static struct tm *gmtime(const time_t *clock, struct tm *result)
1942  { return getGMTTime(clock, result);};
1943 };
1944 
1945 #ifndef HAVE_LOCALTIME_R
1946 
1947 inline struct tm *localtime_r(const time_t *t, struct tm *b)
1948  {return SysTime::getLocalTime(t, b);};
1949 inline char *ctime_r(const time_t *t, char *buf)
1950  {return ctime(t);};
1951 inline struct tm *gmtime_r(const time_t *t, struct tm *b) \
1952 {return SysTime::getGMTTime(t, b);};
1953 inline char *asctime_r(const struct tm *tm, char *b) \
1954  {return asctime(tm);};
1955 
1956 #endif
1957 
1958 #ifdef CCXX_NAMESPACES
1959 }
1960 #endif
1961 
1962 #endif
1963