1 // Copyright (C) 1999-2005 Open Source Telecom Corporation.
2 // Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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 CCXX_THREAD_H_
45 #define CCXX_THREAD_H_
46
47 #include <cc++/config.h>
48
49 #ifndef CCXX_STRING_H_
51 #endif
52
53 #ifndef WIN32
55 #endif // !WIN32
56
57 #include <ctime>
58
59 #ifndef WIN32
60 #include <pthread.h>
61 #endif // !WIN32
62
63 #undef CCXX_USE_WIN32_ATOMIC
64 #ifndef WIN32
65 #include <time.h>
66 #include <signal.h>
67 #include <unistd.h>
68
69 #ifdef _THR_UNIXWARE
70 #undef PTHREAD_MUTEXTYPE_RECURSIVE
71 #endif
72
75
76 /*
77 #if defined(__CYGWIN32__)
78 __declspec(dllimport) long __stdcall InterlockedIncrement(long *);
79 __declspec(dllimport) long __stdcall InterlockedDecrement(long *);
80 __declspec(dllimport) long __stdcall InterlockedExchange(long *, long);
81 #define CCXX_USE_WIN32_ATOMIC 1
82 #endif
83 */
84
85 #else // WIN32
88
89 #define MAX_SEM_VALUE 1000000
90 #define CCXX_USE_WIN32_ATOMIC 1
91
92 #endif // !WIN32
93
94 #ifdef HAVE_GCC_CXX_BITS_ATOMIC
95 #include <ios>
96 #endif
97
98 #ifdef CCXX_NAMESPACES
99 namespace ost {
100 #ifdef __BORLANDC__
101 # if __BORLANDC__ >= 0x0560
102 using std::time_t;
103 using std::tm;
104 # endif
105 #endif
106 #endif
107
108 #ifdef HAVE_GCC_CXX_BITS_ATOMIC
109 using namespace __gnu_cxx;
110 #endif
111
114
115 #define TIMEOUT_INF ~((timeout_t) 0)
116
117 #define ENTER_CRITICAL enterMutex();
118 #define LEAVE_CRITICAL leaveMutex();
119 #define ENTER_DEFERRED setCancel(cancelDeferred);
120 #define LEAVE_DEFERRED setCancel(cancelImmediate);
121
122 #ifndef WIN32
123 // These macros override common functions with thread-safe versions. In
124 // particular the common "libc" sleep() has problems since it normally
125 // uses SIGARLM (as actually defined by "posix"). The pthread_delay and
126 // usleep found in libpthread are gaurenteed not to use SIGALRM and offer
127 // higher resolution. psleep() is defined to call the old process sleep.
128
129 #undef sleep
130 #define psleep(x) (sleep)(x)
131
132 #ifdef signal
133 #undef signal
134 #endif
135
136 #endif // !WIN32
137
138 #undef Yield
139
142
187 {
188 private:
191 #ifndef WIN32
192 #ifndef PTHREAD_MUTEXTYPE_RECURSIVE
195 #endif
196 /*
197 * Pthread mutex object. This is protected rather than private
198 * because some mixed mode pthread operations require a mutex as
199 * well as their primary pthread object. A good example of this
200 * is the Event class, as waiting on a conditional object must be
201 * associated with an accessable mutex. An alternative would be
202 * to make such classes "friend" classes of the Mutex.
203 */
205 #else // WIN32
206
207 # if defined(MUTEX_UNDERGROUND_WIN32_MUTEX) && defined(MUTEX_UNDERGROUND_WIN32_CRITICALSECTION)
208 # error "Can't determine underground for Mutex"
209 # endif
210
211 #ifdef MUTEX_UNDERGROUND_WIN32_MUTEX
213 #endif
214 #ifdef MUTEX_UNDERGROUND_WIN32_CRITICALSECTION
215 CRITICAL_SECTION _criticalSection;
216 #endif
217
218 #endif // WIN32
219
220 public:
226 Mutex(
const char *name = NULL);
227
234
241 {_debug = mode;};
242
249 {_name = name;};
250
258 void enterMutex(void);
259
264 {enterMutex();};
265
270 {leaveMutex();};
271
278 {return tryEnterMutex();};
279
290 bool tryEnterMutex(void);
291
302 void leaveMutex(void);
303 };
304
329 {
330 private:
332 public:
339 { mutex.enterMutex(); }
340
344 // this should be not-virtual
346 { mutex.leaveMutex(); }
347 };
348
358 {
359 private:
360 #ifdef HAVE_PTHREAD_RWLOCK
361 pthread_rwlock_t _lock;
362 #else
364 #endif
365
366 public:
371
376
380 void readLock(void);
381
385 void writeLock(void);
386
392 bool tryReadLock(void);
393
399 bool tryWriteLock(void);
400
404 void unlock(void);
405 };
406
428 {
429 private:
431
432 public:
439 { tl.readLock(); }
443 // this should be not-virtual
445 { tl.unlock(); }
446 };
447
469 {
470 private:
472
473 public:
480 { tl.writeLock(); }
484 // this should be not-virtual
486 { tl.unlock(); }
487 };
488
489
500 {
501 private:
503
504 public:
511
520
523 };
524
536 {
537 #ifndef CCXX_USE_WIN32_ATOMIC
538 private:
539 #if defined(HAVE_ATOMIC_AIX)
540 volatile int counter;
541 #elif defined(HAVE_GCC_BITS_ATOMIC)
542 volatile _Atomic_word counter;
543 #elif defined(HAVE_GCC_CXX_BITS_ATOMIC)
544 volatile _Atomic_word counter;
545 // __gnu_cxx::_Atomic_word counter;
546 #elif defined(HAVE_ATOMIC)
547 atomic_t atomic;
548 #else
551 #endif
552
553 public:
558
565
567
568 int operator++(void);
569 int operator--(void);
570 int operator+=(int change);
571 int operator-=(int change);
572 int operator+(int change);
573 int operator-(int change);
574 int operator=(int value);
575 bool operator!(void);
576 operator int();
577 #else
578 private:
579 long atomic;
580
581 public:
583 {atomic = 0;};
584
586 {atomic = value;};
587
588 inline int operator++(void)
589 {return InterlockedIncrement(&atomic);};
590
591 inline int operator--(void)
592 {return InterlockedDecrement(&atomic);};
593
594 int operator+=(int change);
595
596 int operator-=(int change);
597
598 inline int operator+(int change)
599 {return atomic + change;};
600
601 inline int operator-(int change)
602 {return atomic - change;};
603
604 inline int operator=(int value)
605 {return InterlockedExchange(&atomic, value);};
606
607 inline bool operator!(void)
608 {return (atomic == 0) ? true : false;};
609
610 inline operator int()
611 {return atomic;};
612 #endif
613 };
614
615 #ifndef WIN32
616
637 {
638 private:
641
642 public:
649
654
660 void signal(bool broadcast);
661
669
676 void enterMutex(void);
677
687 {enterMutex();};
688
699 bool tryEnterMutex(void);
700
702 {return tryEnterMutex();};
703
709 void leaveMutex(void);
710
712 {return leaveMutex();};
713 };
714 #endif
715
734 {
735 private:
736 #ifndef WIN32
740 #else
742 #endif // !WIN32
743
744 public:
754
762
779
791 void post(void);
792
793 #ifndef WIN32
794
802 void force_unlock_after_cancellation();
803
804 #endif // WIN32
805
806 // FIXME: how implement getValue for posix compatibility ?
807 // not portable...
808 #if 0
809
814 int getValue(void);
815 #endif
816 };
817
838 {
839 private:
841
842 public:
847 { sem.wait(); }
851 // this should be not-virtual
853 { sem.post(); }
854 };
855
870 {
871 private:
872 #ifndef WIN32
877 #else
879 #endif
880
881 public:
883
885
892 void reset(void);
893
897 void signal(void);
898
909 };
910
911
1094 {
1095 public:
1103 } Throw;
1104
1115 cancelDefault=cancelDeferred
1117 } Cancel;
1118
1125 } Suspend;
1126
1127 #ifndef WIN32
1128
1130 #endif
1131
1132 friend class DummyThread;
1133 private:
1135 friend class postream_type;
1137
1140
1144
1145 // private data
1146 friend class ThreadImpl;
1148
1149 public:
1150 static Thread *
get(void);
1151
1152 private:
1153 #ifdef WIN32
1154 static unsigned __stdcall Execute(
Thread *th);
1155 #endif
1156
1157 // close current thread, free all and call Notify
1158 void close();
1159
1160 private:
1163
1164 #ifdef WIN32
1166 #endif
1167
1168 protected:
1176 void setName(const char *text);
1177
1187 virtual void run(void) = 0;
1188
1210 virtual void final(void);
1211
1223 virtual void initial(void);
1224
1234 virtual void* getExtended(void);
1235
1243 virtual void notify(
Thread*);
1244
1250 void exit(void);
1251
1255 void sync(void);
1256
1260 bool testCancel(void);
1261
1271 void setCancel(
Cancel mode);
1272
1280 void setSuspend(
Suspend mode);
1281
1290 void terminate(void);
1291
1296 {_parent = NULL;};
1297
1298 public:
1308
1320 Thread(
int pri = 0,
size_t stack = 0);
1321
1322 #ifndef WIN32
1323
1332 #endif
1333
1341
1348 {_autostack = size;};
1349
1360
1365 static void yield(void);
1366
1380
1390
1398 {return _parent;};
1399
1406 void suspend(void);
1407
1411 void resume(void);
1412
1420 {return _cancel;};
1421
1428 bool isRunning(void) const;
1429
1435 bool isDetached(void) const;
1436
1440 void join(void);
1441
1448 bool isThread(void) const;
1449
1456
1464 {return _name;};
1465
1471 static Throw getException(void);
1472
1478 static void setException(Throw mode);
1479
1488
1491
1492 #ifdef WIN32
1493 bool isCancelled() const;
1494
1496 #endif
1497
1505 static Cancel enterCancel(void);
1506
1512 static void exitCancel(Cancel cancel);
1513 };
1514
1525 {
1526 private:
1528
1529 public:
1532 };
1533
1534 #if !defined(WIN32) && !defined(__MINGW32__)
1536
1538 {
1539 private:
1540 #ifndef WIN32
1541
1542 friend class ThreadImpl;
1544 #endif
1545 #ifndef CCXX_SIG_THREAD_ALARM
1548 #endif
1549
1552 protected:
1553
1561 { signalThread(
_parent,signo); };
1562
1570 { signalThread(
_main,signo);};
1571
1576 virtual void onTimer(void);
1577
1582 virtual void onHangup(void);
1583
1588 virtual void onException(void);
1589
1594 virtual void onDisconnect(void);
1595
1600 virtual void onPolling(void);
1601
1608 virtual void onSignal(int);
1609
1622 void setTimer(
timeout_t timer,
bool periodic =
false);
1623
1631
1637 void endTimer(void);
1638
1639 #if defined(HAVE_SIGWAIT) || defined(HAVE_SIGWAIT2)
1640
1646 void waitSignal(
signo_t signo);
1647 #endif
1648
1655 void setSignal(int signo, bool active);
1656
1663 pthread_attr_t *getPthreadAttrPtr(void);
1664
1669 pthread_t getPthreadId(void);
1670
1671 public:
1672
1674
1681 {signalThread(this, signo);};
1682
1689 static void sigInstall(int signo);
1690 };
1691 #endif
1692
1708 {
1709 private:
1710 #ifndef WIN32
1712 typedef void (*TDestruct)(
void*);
1713 friend class ThreadImpl;
1715 #else
1716 DWORD key;
1717 #endif
1718
1719 public:
1724
1729
1737 void *getKey(void);
1738
1746 void setKey(void *);
1747 };
1748
1760 {
1761 #ifndef WIN32
1762 struct timeval timer;
1763 #else
1764 DWORD timer;
1765 #endif
1767
1768 public:
1776
1786
1797
1808
1813 void sleepTimer(void);
1814
1820 void endTimer(void);
1821
1834
1845 };
1846
1847
1848
1849 // FIXME: not in win32 implementation
1850 #if !defined(WIN32)
1851
1852 // FIXME: private declaration ???
1854
1855 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
1857 #endif
1858
1859 #endif // !WIN32
1860
1861 #ifdef USE_POLL
1862
1870 class Poller
1871 {
1872 private:
1873 int nufds;
1874 pollfd *ufds;
1875
1876 public:
1877 Poller();
1878
1879 virtual ~Poller();
1880
1888 pollfd *getList(int cnt);
1889
1895 inline pollfd *getList(void)
1896 {return ufds;};
1897 };
1898 #endif
1899
1902
1933 {
1934 private:
1936
1937 protected:
1939 {timeLock.enterMutex();}
1940
1942 {timeLock.leaveMutex();}
1943
1944 public:
1945 static time_t getTime(time_t *tloc = NULL);
1947 { return getTime(tloc); };
1948
1949 static int getTimeOfDay(struct timeval *tp);
1951 { return getTimeOfDay(tp); };
1952
1953 static struct tm *getLocalTime(const time_t *clock, struct tm *result);
1954 static struct tm *
locatime(
const time_t *clock,
struct tm *result)
1955 { return getLocalTime(clock, result); };
1956
1957 static struct tm *getGMTTime(const time_t *clock, struct tm *result);
1958 static struct tm *
gmtime(
const time_t *clock,
struct tm *result)
1959 { return getGMTTime(clock, result);};
1960 };
1961
1962 #ifndef HAVE_LOCALTIME_R
1963
1967 {return ctime(t);};
1968 inline struct tm *
gmtime_r(
const time_t *t,
struct tm *b) \
1971 {return asctime(tm);};
1972
1973 #endif
1974
1975 #ifdef CCXX_NAMESPACES
1976 }
1977 #endif
1978
1979 #endif
1980
static struct tm * getLocalTime(const time_t *clock, struct tm *result)
The SemaphoreLock class is used to protect a section of code through a semaphore so that only x insta...
void lock(void)
In the future we will use lock in place of enterMutex since the conditional composite is not a recurs...
Common C++ generic string class.
void post(void)
Posting to a semaphore increments its current value and releases the first thread waiting for the sem...
MutexLock(Mutex &_mutex)
Acquire the mutex.
struct tm * localtime_r(const time_t *t, struct tm *b)
A semaphore is generally used as a synchronization object between multiple threads or to protect a li...
void signalThread(int signo)
Delivers a Posix signal to the current thread.
The Mutex class is used to protect a section of code so that at any given time only a single thread c...
friend void operator++(Thread &th)
Signal the semaphore that the specified thread is waiting for before beginning execution.
Thread * getParent(void)
Gets the pointer to the Thread class which created the current thread object.
static struct tm * gmtime(const time_t *clock, struct tm *result)
Cancel
How work cancellation.
bool test(void)
Future abi will use enter/leave/test members.
This class allows the creation of a thread context unique "pointer" that can be set and retrieved and...
This is a generic and portable string class.
void clrParent(void)
clear parent thread relationship.
static Thread * get(void)
A conditional variable synchcronization object for one to one and one to many signal and control even...
A class to automatically set the thread cancellation mode of a member function.
The Mutex Counter is a counter variable which can safely be incremented or decremented by multiple th...
ReadLock(ThreadLock &_tl)
Wait for read access.
void signalParent(signo_t signo)
In the Posix version of Common C++, this can be used to send a signal into the parent thread of the c...
void nameMutex(const char *name)
Enable setting of mutex name for deadlock debug.
static int gettimeofday(struct timeval *tp, struct timezone *)
struct tm * gmtime_r(const time_t *t, struct tm *b)
static time_t time(time_t *tloc)
void enter(void)
Future abi will use enter/leave/test members.
~ReadLock()
Post the semaphore automatically.
char * ctime_r(const time_t *t, char *buf)
void signalMain(signo_t signo)
In the Posix version of Common C++, this can be used to send a signal into the main application threa...
~SemaphoreLock()
Post the semaphore automatically.
The ThreadLock class impliments a thread rwlock for optimal reader performance on systems which have ...
static void setDebug(bool mode)
Enable or disable deadlock debugging.
Cancel getCancel(void)
Used to retrieve the cancellation mode in effect for the selected thread.
friend void operator--(Thread &th)
throw object that cause error (throw this)
~MutexLock()
Release the mutex automatically.
The slog class is used to stream messages to the system's logging facility (syslogd).
Every thread of execution in an application is created by instantiating an object of a class derived ...
The Event class implements a feature originally found in the WIN32 API; event notification.
struct timespec * getTimeout(struct timespec *spec, timeout_t timeout)
class __EXPORT Conditional
static void setStack(size_t size=0)
Set base stack limit before manual stack sizes have effect.
static struct tm * getGMTTime(const time_t *clock, struct tm *result)
continue without throwing error
void leave(void)
Future abi will use enter/leave/test members.
bool wait(timeout_t timeout=0)
Wait is used to keep a thread held until the semaphore counter is greater than 0. ...
The WriteLock class is used to protect a section of code through a ThreadLock for "write" access to t...
The ReadLock class is used to protect a section of code through a ThreadLock for "read" access to the...
Timer ports are used to provide synchronized timing events when managed under a "service thread" such...
This class is used to access non-reentrant date and time functions in the standard C library...
char * asctime_r(const struct tm *tm, char *b)
WriteLock(ThreadLock &_tl)
Wait for write access.
~WriteLock()
Post the semaphore automatically.
SemaphoreLock(Semaphore &_sem)
Wait for the semaphore.
const char * getName(void) const
Get the name string for this thread, to use in debug messages.
static struct tm * locatime(const time_t *clock, struct tm *result)
The AtomicCounter class offers thread-safe manipulation of an integer counter.
The MutexLock class is used to protect a section of code so that at any given time only a single thre...
static PosixThread * _timer