| // Copyright (C) 1999-2005 Open Source Telecom Corporation. |
| // Copyright (C) 2006-2010 David Sugar, Tycho Softworks. |
| // |
| // This program is free software; you can redistribute it and/or modify |
| // it under the terms of the GNU General Public License as published by |
| // the Free Software Foundation; either version 2 of the License, or |
| // (at your option) any later version. |
| // |
| // This program is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| // |
| // You should have received a copy of the GNU General Public License |
| // along with this program; if not, write to the Free Software |
| // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| // |
| // As a special exception, you may use this file as part of a free software |
| // library without restriction. Specifically, if other files instantiate |
| // templates or use macros or inline functions from this file, or you compile |
| // this file and link it with other files to produce an executable, this |
| // file does not by itself cause the resulting executable to be covered by |
| // the GNU General Public License. This exception does not however |
| // invalidate any other reasons why the executable file might be covered by |
| // the GNU General Public License. |
| // |
| // This exception applies only to the code released under the name GNU |
| // Common C++. If you copy code from other releases into a copy of GNU |
| // Common C++, as the General Public License permits, the exception does |
| // not apply to the code that you add in this way. To avoid misleading |
| // anyone as to the status of such modified files, you must delete |
| // this exception notice from them. |
| // |
| // If you write modifications of your own for GNU Common C++, it is your choice |
| // whether to permit this exception to apply to your modifications. |
| // If you do not wish that, delete this exception notice. |
| // |
| |
| /** |
| * @file thread.h |
| * @short Synchronization and threading services. |
| **/ |
| |
| #ifndef CCXX_THREAD_H_ |
| #define CCXX_THREAD_H_ |
| |
| #include <cc++/config.h> |
| |
| #ifndef CCXX_STRING_H_ |
| #include <cc++/string.h> |
| #endif |
| |
| #ifndef WIN32 |
| #define CCXX_POSIX |
| #endif // !WIN32 |
| |
| #include <ctime> |
| |
| #ifndef WIN32 |
| #include <pthread.h> |
| #endif // !WIN32 |
| |
| #undef CCXX_USE_WIN32_ATOMIC |
| #ifndef WIN32 |
| #include <time.h> |
| #include <signal.h> |
| #include <unistd.h> |
| |
| #ifdef _THR_UNIXWARE |
| #undef PTHREAD_MUTEXTYPE_RECURSIVE |
| #endif |
| |
| typedef pthread_t cctid_t; |
| typedef unsigned long timeout_t; |
| |
| /* |
| #if defined(__CYGWIN32__) |
| __declspec(dllimport) long __stdcall InterlockedIncrement(long *); |
| __declspec(dllimport) long __stdcall InterlockedDecrement(long *); |
| __declspec(dllimport) long __stdcall InterlockedExchange(long *, long); |
| #define CCXX_USE_WIN32_ATOMIC 1 |
| #endif |
| */ |
| |
| #else // WIN32 |
| typedef DWORD cctid_t; |
| typedef DWORD timeout_t; |
| |
| #define MAX_SEM_VALUE 1000000 |
| #define CCXX_USE_WIN32_ATOMIC 1 |
| |
| #endif // !WIN32 |
| |
| #ifdef HAVE_GCC_CXX_BITS_ATOMIC |
| #include <ios> |
| #endif |
| |
| #ifdef CCXX_NAMESPACES |
| namespace ost { |
| #ifdef __BORLANDC__ |
| # if __BORLANDC__ >= 0x0560 |
| using std::time_t; |
| using std::tm; |
| # endif |
| #endif |
| #endif |
| |
| #ifdef HAVE_GCC_CXX_BITS_ATOMIC |
| using namespace __gnu_cxx; |
| #endif |
| |
| class __EXPORT Thread; |
| class __EXPORT ThreadKey; |
| |
| #define TIMEOUT_INF ~((timeout_t) 0) |
| |
| #define ENTER_CRITICAL enterMutex(); |
| #define LEAVE_CRITICAL leaveMutex(); |
| #define ENTER_DEFERRED setCancel(cancelDeferred); |
| #define LEAVE_DEFERRED setCancel(cancelImmediate); |
| |
| #ifndef WIN32 |
| // These macros override common functions with thread-safe versions. In |
| // particular the common "libc" sleep() has problems since it normally |
| // uses SIGARLM (as actually defined by "posix"). The pthread_delay and |
| // usleep found in libpthread are gaurenteed not to use SIGALRM and offer |
| // higher resolution. psleep() is defined to call the old process sleep. |
| |
| #undef sleep |
| #define psleep(x) (sleep)(x) |
| |
| #ifdef signal |
| #undef signal |
| #endif |
| |
| #endif // !WIN32 |
| |
| #undef Yield |
| |
| class __EXPORT Conditional; |
| class __EXPORT Event; |
| |
| /** |
| * The Mutex class is used to protect a section of code so that at any |
| * given time only a single thread can perform the protected operation. |
| * |
| * The Mutex can be used as a base class to protect access in a derived |
| * class. When used in this manner, the ENTER_CRITICAL and LEAVE_CRITICAL |
| * macros can be used to specify when code written for the derived class |
| * needs to be protected by the default Mutex of the derived class, and |
| * hence is presumed to be 'thread safe' from multiple instance execution. |
| * One of the most basic Common C++ synchronization object is the Mutex |
| * class. A Mutex only allows one thread to continue execution at a given |
| * time over a specific section of code. Mutex's have a enter and leave |
| * method; only one thread can continue from the Enter until the Leave is |
| * called. The next thread waiting can then get through. Mutex's are also |
| * known as "CRITICAL SECTIONS" in win32-speak. |
| * |
| * The Mutex is always recursive in that if the same thread invokes |
| * the same mutex lock multiple times, it must release it multiple times. |
| * This allows a function to call another function which also happens to |
| * use the same mutex lock when called directly. This was |
| * deemed essential because a mutex might be used to block individual file |
| * requests in say, a database, but the same mutex might be needed to block a |
| * whole series of database updates that compose a "transaction" for one |
| * thread to complete together without having to write alternate non-locking |
| * member functions to invoke for each part of a transaction. |
| * |
| * Strangely enough, the original pthread draft standard does not directly |
| * support recursive mutexes. In fact this is the most common "NP" extension |
| * for most pthread implementations. Common C++ emulates recursive mutex |
| * behavior when the target platform does not directly support it. |
| * |
| * In addition to the Mutex, Common C++ supports a rwlock class. This |
| * implements the X/Open recommended "rwlock". On systems which do not |
| * support rwlock's, the behavior is emulated with a Mutex; however, the |
| * advantage of a rwlock over a mutex is then entirely lost. There has been |
| * some suggested clever hacks for "emulating" the behavior of a rwlock with |
| * a pair of mutexes and a semaphore, and one of these will be adapted for |
| * Common C++ in the future for platforms that do not support rwlock's |
| * directly. |
| * |
| * @author David Sugar <dyfet@ostel.com> |
| * @short Mutex lock for protected access. |
| */ |
| class __EXPORT Mutex |
| { |
| private: |
| static bool _debug; |
| String _name; |
| #ifndef WIN32 |
| #ifndef PTHREAD_MUTEXTYPE_RECURSIVE |
| int volatile _level; |
| Thread *volatile _tid; |
| #endif |
| /* |
| * Pthread mutex object. This is protected rather than private |
| * because some mixed mode pthread operations require a mutex as |
| * well as their primary pthread object. A good example of this |
| * is the Event class, as waiting on a conditional object must be |
| * associated with an accessable mutex. An alternative would be |
| * to make such classes "friend" classes of the Mutex. |
| */ |
| pthread_mutex_t _mutex; |
| #else // WIN32 |
| |
| # if defined(MUTEX_UNDERGROUND_WIN32_MUTEX) && defined(MUTEX_UNDERGROUND_WIN32_CRITICALSECTION) |
| # error "Can't determine underground for Mutex" |
| # endif |
| |
| #ifdef MUTEX_UNDERGROUND_WIN32_MUTEX |
| HANDLE _mutex; |
| #endif |
| #ifdef MUTEX_UNDERGROUND_WIN32_CRITICALSECTION |
| CRITICAL_SECTION _criticalSection; |
| #endif |
| |
| #endif // WIN32 |
| |
| public: |
| /** |
| * The mutex is always initialized as a recursive entity. |
| * |
| * @param name of mutex for optional deadlock detection |
| */ |
| Mutex(const char *name = NULL); |
| |
| /** |
| * Destroying the mutex removes any system resources associated |
| * with it. If a mutex lock is currently in place, it is presumed |
| * to terminate when the Mutex is destroyed. |
| */ |
| virtual ~Mutex(); |
| |
| /** |
| * Enable or disable deadlock debugging. |
| * |
| * @param mode debug mode. |
| */ |
| static void setDebug(bool mode) |
| {_debug = mode;}; |
| |
| /** |
| * Enable setting of mutex name for deadlock debug. |
| * |
| * @param name for mutex. |
| */ |
| inline void nameMutex(const char *name) |
| {_name = name;}; |
| |
| /** |
| * Entering a Mutex locks the mutex for the current thread. This |
| * also can be done using the ENTER_CRITICAL macro or by using the |
| * ++ operator on a mutex. |
| * |
| * @see #leaveMutex |
| */ |
| void enterMutex(void); |
| |
| /** |
| * Future abi will use enter/leave/test members. |
| */ |
| inline void enter(void) |
| {enterMutex();}; |
| |
| /** |
| * Future abi will use enter/leave/test members. |
| */ |
| inline void leave(void) |
| {leaveMutex();}; |
| |
| /** |
| * Future abi will use enter/leave/test members. |
| * |
| * @return true if entered. |
| */ |
| inline bool test(void) |
| {return tryEnterMutex();}; |
| |
| /** |
| * Tries to lock the mutex for the current thread. Behaves like |
| * #enterMutex , except that it doesn't block the calling thread |
| * if the mutex is already locked by another thread. |
| * |
| * @return true if locking the mutex was succesful otherwise false |
| * |
| * @see enterMutex |
| * @see leaveMutex |
| */ |
| bool tryEnterMutex(void); |
| |
| /** |
| * Leaving a mutex frees that mutex for use by another thread. If |
| * the mutex has been entered (invoked) multiple times (recursivily) |
| * by the same thread, then it will need to be exited the same number |
| * of instances before it is free for re-use. This operation can |
| * also be done using the LEAVE_CRITICAL macro or by the -- operator |
| * on a mutex. |
| * |
| * @see #enterMutex |
| */ |
| void leaveMutex(void); |
| }; |
| |
| /** |
| * The MutexLock class is used to protect a section of code so that at any |
| * given time only a single thread can perform the protected operation. |
| * |
| * It use Mutex to protect operation. Using this class is usefull and |
| * exception safe. The mutex that has been locked is automatically |
| * released when the function call stack falls out of scope, so one doesnt |
| * have to remember to unlock the mutex at each function return. |
| * |
| * A common use is |
| * |
| * void func_to_protect() |
| * { |
| * MutexLock lock(mutex); |
| * ... operation ... |
| * } |
| * |
| * NOTE: do not declare variable as "MutexLock (mutex)", the mutex will be |
| * released at statement end. |
| * |
| * @author Frediano Ziglio <freddy77@angelfire.com> |
| * @short Mutex automatic locker for protected access. |
| */ |
| class __EXPORT MutexLock |
| { |
| private: |
| Mutex& mutex; |
| public: |
| /** |
| * Acquire the mutex |
| * |
| * @param _mutex reference to mutex to aquire. |
| */ |
| MutexLock( Mutex& _mutex ) : mutex( _mutex ) |
| { mutex.enterMutex(); } |
| |
| /** |
| * Release the mutex automatically |
| */ |
| // this should be not-virtual |
| ~MutexLock() |
| { mutex.leaveMutex(); } |
| }; |
| |
| /** |
| * The ThreadLock class impliments a thread rwlock for optimal reader performance |
| * on systems which have rwlock support, and reverts to a simple mutex for those |
| * that do not. |
| * |
| * @author David Sugar <dyfet@ostel.com> |
| * @short Posix rwlock extension for protected access. |
| */ |
| class __EXPORT ThreadLock |
| { |
| private: |
| #ifdef HAVE_PTHREAD_RWLOCK |
| pthread_rwlock_t _lock; |
| #else |
| Mutex mutex; |
| #endif |
| |
| public: |
| /** |
| * Create a process shared thread lock object. |
| */ |
| ThreadLock(); |
| |
| /** |
| * Destroy a process shared thread lock object. |
| */ |
| virtual ~ThreadLock(); |
| |
| /** |
| * Aquire a read lock for the current object. |
| */ |
| void readLock(void); |
| |
| /** |
| * Aquire a write lock for the current object. |
| */ |
| void writeLock(void); |
| |
| /** |
| * Attempt read lock for current object. |
| * |
| * @return true on success. |
| */ |
| bool tryReadLock(void); |
| |
| /** |
| * Attempt write lock for current object. |
| * |
| * @return true on success. |
| */ |
| bool tryWriteLock(void); |
| |
| /** |
| * Release any held locks. |
| */ |
| void unlock(void); |
| }; |
| |
| /** |
| * The ReadLock class is used to protect a section of code through |
| * a ThreadLock for "read" access to the member function. The |
| * ThreadLock is automatically released when the object falls out of |
| * scope. |
| * |
| * A common use is |
| * |
| * void func_to_protect() |
| * { |
| * ReadLock lock(threadlock); |
| * ... operation ... |
| * } |
| * |
| * NOTE: do not declare variable as "ReadLock (threadlock)", the |
| * mutex will be released at statement end. |
| * |
| * @author David Sugar <dyfet@gnu.org> |
| * @short Read mode automatic locker for protected access. |
| */ |
| class __EXPORT ReadLock |
| { |
| private: |
| ThreadLock& tl; |
| |
| public: |
| /** |
| * Wait for read access |
| * |
| * @param _tl reference to lock to aquire. |
| */ |
| ReadLock( ThreadLock& _tl ) : tl( _tl ) |
| { tl.readLock(); } |
| /** |
| * Post the semaphore automatically |
| */ |
| // this should be not-virtual |
| ~ReadLock() |
| { tl.unlock(); } |
| }; |
| |
| /** |
| * The WriteLock class is used to protect a section of code through |
| * a ThreadLock for "write" access to the member function. The |
| * ThreadLock is automatically released when the object falls out of |
| * scope. |
| * |
| * A common use is |
| * |
| * void func_to_protect() |
| * { |
| * WriteLock lock(threadlock); |
| * ... operation ... |
| * } |
| * |
| * NOTE: do not declare variable as "WriteLock (threadlock)", the |
| * mutex will be released at statement end. |
| * |
| * @author David Sugar <dyfet@gnu.org> |
| * @short Read mode automatic locker for protected access. |
| */ |
| class __EXPORT WriteLock |
| { |
| private: |
| ThreadLock& tl; |
| |
| public: |
| /** |
| * Wait for write access |
| * |
| * @param _tl reference to threadlock to aquire. |
| */ |
| WriteLock( ThreadLock& _tl ) : tl( _tl ) |
| { tl.writeLock(); } |
| /** |
| * Post the semaphore automatically |
| */ |
| // this should be not-virtual |
| ~WriteLock() |
| { tl.unlock(); } |
| }; |
| |
| |
| /** |
| * The Mutex Counter is a counter variable which can safely be incremented |
| * or decremented by multiple threads. A Mutex is used to protect access |
| * to the counter variable (an integer). An initial value can be specified |
| * for the counter, and it can be manipulated with the ++ and -- operators. |
| * |
| * @author David Sugar <dyfet@ostel.com> |
| * @short Thread protected integer counter. |
| */ |
| class __EXPORT MutexCounter : public Mutex |
| { |
| private: |
| volatile int counter; |
| |
| public: |
| /** |
| * Create and optionally name a mutex protected counter. |
| * |
| * @param id name for mutex counter, optional for deadlock testing. |
| */ |
| MutexCounter(const char *id = NULL); |
| |
| /** |
| * Create and optionally name a mutex protected counter with |
| * an initial value. |
| * |
| * @param initial value of counter. |
| * @param id name of counter, optional for deadlock testing. |
| */ |
| MutexCounter(int initial, const char *id = NULL); |
| |
| friend __EXPORT int operator++(MutexCounter &mc); |
| friend __EXPORT int operator--(MutexCounter &mc); |
| }; |
| |
| /** |
| * The AtomicCounter class offers thread-safe manipulation of an integer |
| * counter. These are commonly used for building thread-safe "reference" |
| * counters for C++ classes. The AtomicCounter depends on the platforms |
| * support for "atomic" integer operations, and can alternately substitute |
| * a "mutex" if no atomic support exists. |
| * |
| * @author Sean Cavanaugh <sean@dimensionalrift.com> |
| * @short atomic counter operation. |
| */ |
| class __EXPORT AtomicCounter |
| { |
| #ifndef CCXX_USE_WIN32_ATOMIC |
| private: |
| #if defined(HAVE_ATOMIC_AIX) |
| volatile int counter; |
| #elif defined(HAVE_GCC_BITS_ATOMIC) |
| volatile _Atomic_word counter; |
| #elif defined(HAVE_GCC_CXX_BITS_ATOMIC) |
| volatile _Atomic_word counter; |
| // __gnu_cxx::_Atomic_word counter; |
| #elif defined(HAVE_ATOMIC) |
| atomic_t atomic; |
| #else |
| volatile int counter; |
| pthread_mutex_t _mutex; |
| #endif |
| |
| public: |
| /** |
| * Initialize an atomic counter to 0. |
| */ |
| AtomicCounter(); |
| |
| /** |
| * Initialize an atomic counter to a known value. |
| * |
| * @param value initial value. |
| */ |
| AtomicCounter(int value); |
| |
| ~AtomicCounter(); |
| |
| int operator++(void); |
| int operator--(void); |
| int operator+=(int change); |
| int operator-=(int change); |
| int operator+(int change); |
| int operator-(int change); |
| int operator=(int value); |
| bool operator!(void); |
| operator int(); |
| #else |
| private: |
| long atomic; |
| |
| public: |
| inline AtomicCounter() |
| {atomic = 0;}; |
| |
| inline AtomicCounter(int value) |
| {atomic = value;}; |
| |
| inline int operator++(void) |
| {return InterlockedIncrement(&atomic);}; |
| |
| inline int operator--(void) |
| {return InterlockedDecrement(&atomic);}; |
| |
| int operator+=(int change); |
| |
| int operator-=(int change); |
| |
| inline int operator+(int change) |
| {return atomic + change;}; |
| |
| inline int operator-(int change) |
| {return atomic - change;}; |
| |
| inline int operator=(int value) |
| {return InterlockedExchange(&atomic, value);}; |
| |
| inline bool operator!(void) |
| {return (atomic == 0) ? true : false;}; |
| |
| inline operator int() |
| {return atomic;}; |
| #endif |
| }; |
| |
| #ifndef WIN32 |
| /** |
| * A conditional variable synchcronization object for one to one and |
| * one to many signal and control events between processes. |
| * Conditional variables may wait for and receive signals to notify |
| * when to resume or perform operations. Multiple waiting threads may |
| * be woken with a broadcast signal. |
| * |
| * @warning While this class inherits from Mutex, the methods of the |
| * class Conditional just handle the system conditional variable, so |
| * the user is responsible for calling enterMutex and leaveMutex so as |
| * to avoid race conditions. Another thing to note is that if you have |
| * several threads waiting on one condition, not uncommon in thread |
| * pools, each thread must take care to manually unlock the mutex if |
| * cancellation occurs. Otherwise the first thread cancelled will |
| * deadlock the rest of the thread. |
| * |
| * @author David Sugar |
| * @short conditional. |
| * @todo implement in win32 |
| */ |
| class __EXPORT Conditional |
| { |
| private: |
| pthread_cond_t _cond; |
| pthread_mutex_t _mutex; |
| |
| public: |
| /** |
| * Create an instance of a conditional. |
| * |
| * @param id name of conditional, optional for deadlock testing. |
| */ |
| Conditional(const char *id = NULL); |
| |
| /** |
| * Destroy the conditional. |
| */ |
| virtual ~Conditional(); |
| |
| /** |
| * Signal a conditional object and a waiting threads. |
| * |
| * @param broadcast this signal to all waiting threads if true. |
| */ |
| void signal(bool broadcast); |
| |
| /** |
| * Wait to be signaled from another thread. |
| * |
| * @param timer time period to wait. |
| * @param locked flag if already locked the mutex. |
| */ |
| bool wait(timeout_t timer = 0, bool locked = false); |
| |
| /** |
| * Locks the conditional's mutex for this thread. Remember |
| * that Conditional's mutex is NOT a recursive mutex! |
| * |
| * @see #leaveMutex |
| */ |
| void enterMutex(void); |
| |
| /** |
| * In the future we will use lock in place of enterMutex since |
| * the conditional composite is not a recursive mutex, and hence |
| * using enterMutex may cause confusion in expectation with the |
| * behavior of the Mutex class. |
| * |
| * @see #enterMutex |
| */ |
| inline void lock(void) |
| {enterMutex();}; |
| |
| /** |
| * Tries to lock the conditional for the current thread. |
| * Behaves like #enterMutex , except that it doesn't block the |
| * calling thread. |
| * |
| * @return true if locking the mutex was succesful otherwise false |
| * |
| * @see enterMutex |
| * @see leaveMutex |
| */ |
| bool tryEnterMutex(void); |
| |
| inline bool test(void) |
| {return tryEnterMutex();}; |
| |
| /** |
| * Leaving a mutex frees that mutex for use by another thread. |
| * |
| * @see #enterMutex |
| */ |
| void leaveMutex(void); |
| |
| inline void unlock(void) |
| {return leaveMutex();}; |
| }; |
| #endif |
| |
| /** |
| * A semaphore is generally used as a synchronization object between multiple |
| * threads or to protect a limited and finite resource such as a memory or |
| * thread pool. The semaphore has a counter which only permits access by |
| * one or more threads when the value of the semaphore is non-zero. Each |
| * access reduces the current value of the semaphore by 1. One or more |
| * threads can wait on a semaphore until it is no longer 0, and hence the |
| * semaphore can be used as a simple thread synchronization object to enable |
| * one thread to pause others until the thread is ready or has provided data |
| * for them. Semaphores are typically used as a |
| * counter for protecting or limiting concurrent access to a given |
| * resource, such as to permitting at most "x" number of threads to use |
| * resource "y", for example. |
| * |
| * @author David Sugar <dyfet@ostel.com> |
| * @short Semaphore counter for thread synchronization. |
| */ |
| class __EXPORT Semaphore |
| { |
| private: |
| #ifndef WIN32 |
| unsigned _count, _waiters; |
| pthread_mutex_t _mutex; |
| pthread_cond_t _cond; |
| #else |
| HANDLE semObject; |
| #endif // !WIN32 |
| |
| public: |
| /** |
| * The initial value of the semaphore can be specified. An initial |
| * value is often used When used to lock a finite resource or to |
| * specify the maximum number of thread instances that can access a |
| * specified resource. |
| * |
| * @param resource specify initial resource count or 0 default. |
| */ |
| Semaphore(unsigned resource = 0); |
| |
| /** |
| * Destroying a semaphore also removes any system resources |
| * associated with it. If a semaphore has threads currently waiting |
| * on it, those threads will all continue when a semaphore is |
| * destroyed. |
| */ |
| virtual ~Semaphore(); |
| |
| /** |
| * Wait is used to keep a thread held until the semaphore counter |
| * is greater than 0. If the current thread is held, then another |
| * thread must increment the semaphore. Once the thread is accepted, |
| * the semaphore is automatically decremented, and the thread |
| * continues execution. |
| * |
| * The pthread semaphore object does not support a timed "wait", and |
| * hence to maintain consistancy, neither the posix nor win32 source |
| * trees support "timed" semaphore objects. |
| * |
| * @return false if timed out |
| * @param timeout period in milliseconds to wait |
| * @see #post |
| */ |
| bool wait(timeout_t timeout = 0); |
| |
| /** |
| * Posting to a semaphore increments its current value and releases |
| * the first thread waiting for the semaphore if it is currently at |
| * 0. Interestingly, there is no support to increment a semaphore by |
| * any value greater than 1 to release multiple waiting threads in |
| * either pthread or the win32 API. Hence, if one wants to release |
| * a semaphore to enable multiple threads to execute, one must perform |
| * multiple post operations. |
| * |
| * @see #wait |
| */ |
| void post(void); |
| |
| #ifndef WIN32 |
| /** |
| * Call it after a deferred cancellation to avoid deadlocks. |
| * From PTHREAD_COND_TIMEDWAIT(3P): A condition wait (whether timed or not) |
| * is a cancellation point. When the cancelability enable state of a thread |
| * is set to PTHREAD_CANCEL_DEFERRED, a side effect of acting upon a |
| * cancellation request while in a condition wait is that the mutex is |
| * (in effect) re-acquired before calling the first cancellation cleanup handler. |
| */ |
| void force_unlock_after_cancellation(); |
| |
| #endif // WIN32 |
| |
| // FIXME: how implement getValue for posix compatibility ? |
| // not portable... |
| #if 0 |
| /** |
| * Get the current value of a semaphore. |
| * |
| * @return current value. |
| */ |
| int getValue(void); |
| #endif |
| }; |
| |
| /** |
| * The SemaphoreLock class is used to protect a section of code through |
| * a semaphore so that only x instances of the member function may |
| * execute concurrently. |
| * |
| * A common use is |
| * |
| * void func_to_protect() |
| * { |
| * SemaphoreLock lock(semaphore); |
| * ... operation ... |
| * } |
| * |
| * NOTE: do not declare variable as "SemaohoreLock (semaphore)", the |
| * mutex will be released at statement end. |
| * |
| * @author David Sugar <dyfet@gnu.org> |
| * @short Semaphore automatic locker for protected access. |
| */ |
| class __EXPORT SemaphoreLock |
| { |
| private: |
| Semaphore& sem; |
| |
| public: |
| /** |
| * Wait for the semaphore |
| */ |
| SemaphoreLock( Semaphore& _sem ) : sem( _sem ) |
| { sem.wait(); } |
| /** |
| * Post the semaphore automatically |
| */ |
| // this should be not-virtual |
| ~SemaphoreLock() |
| { sem.post(); } |
| }; |
| |
| /** |
| * The Event class implements a feature originally found in the WIN32 API; |
| * event notification. A target thread waits on a resetable Event, and one |
| * or more other threads can then signal the waiting thread to resume |
| * execution. A timeout can be used to specify a wait duration in |
| * milliseconds. The Event class must be reset before it can be used again |
| * as a trigger. These event objects |
| * use a trigger/reset mechanism and are related to low level conditional |
| * variables. |
| * |
| * @author: David Sugar <dyfet@ostel.com> |
| * @short Thread synchornization on event notification. |
| */ |
| class __EXPORT Event |
| { |
| private: |
| #ifndef WIN32 |
| pthread_mutex_t _mutex; |
| pthread_cond_t _cond; |
| bool _signaled; |
| int _count; |
| #else |
| HANDLE cond; |
| #endif |
| |
| public: |
| Event(); |
| |
| virtual ~Event(); |
| |
| /** |
| * Once signaled, the Event class must be "reset" before responding |
| * to a new signal. |
| * |
| * @see #signal |
| */ |
| void reset(void); |
| |
| /** |
| * Signal the event for the waiting thread. |
| */ |
| void signal(void); |
| |
| /** |
| * Wait either for the event to be signaled by another thread or |
| * for the specified timeout duration. |
| * |
| * @see #signal |
| * @return true if signaled, false if timed out. |
| * @param timer timeout in milliseconds to wait for a signal. |
| */ |
| bool wait(timeout_t timer); |
| bool wait(void); |
| }; |
| |
| |
| /** |
| * Every thread of execution in an application is created by |
| * instantiating an object of a class derived from the Thread |
| * class. Classes derived from Thread must implement the run() method, |
| * which specifies the code of the thread. The base Thread class |
| * supports encapsulation of the generic threading methods implemented |
| * on various target operating systems. This includes the ability to |
| * start and stop threads in a synchronized and controllable manner, |
| * the ability to specify thread execution priority, and thread |
| * specific "system call" wrappers, such as for sleep and yield. A |
| * thread exception is thrown if the thread cannot be created. |
| * Threading was the first part of Common C++ I wrote, back when it |
| * was still the APE library. My goal for Common C++ threading has |
| * been to make threading as natural and easy to use in C++ |
| * application development as threading is in Java. With this said, |
| * one does not need to use threading at all to take advantage of |
| * Common C++. However, all Common C++ classes are designed at least |
| * to be thread-aware/thread-safe as appropriate and necessary. |
| * |
| * Common C++ threading is currently built either from the Posix "pthread" |
| * library or using the win32 SDK. In that the Posix "pthread" draft |
| * has gone through many revisions, and many system implementations are |
| * only marginally compliant, and even then usually in different ways, I |
| * wrote a large series of autoconf macros found in ost_pthread.m4 which |
| * handle the task of identifying which pthread features and capabilities |
| * your target platform supports. In the process I learned much about what |
| * autoconf can and cannot do for you.. |
| * |
| * Currently the GNU Portable Thread library (GNU pth) is not directly |
| * supported in Common C++. While GNU "Pth" doesn't offer direct |
| * native threading support or benefit from SMP hardware, many of the design |
| * advantages of threading can be gained from it's use, and the Pth pthread |
| * "emulation" library should be usable with Common C++. In the future, |
| * Common C++ will directly support Pth, as well as OS/2 and BeOS native |
| * threading API's. |
| * |
| * Common C++ itself defines a fairly "neutral" threading model that is |
| * not tied to any specific API such as pthread, win32, etc. This neutral |
| * thread model is contained in a series of classes which handle threading |
| * and synchronization and which may be used together to build reliable |
| * threaded applications. |
| * |
| * Common C++ defines application specific threads as objects which are |
| * derived from the Common C++ "Thread" base class. At minimum the "Run" |
| * method must be implemented, and this method essentially is the "thread", |
| * for it is executed within the execution context of the thread, and when |
| * the Run method terminates the thread is assumed to have terminated. |
| * |
| * Common C++ allows one to specify the running priority of a newly created |
| * thread relative to the "parent" thread which is the thread that is |
| * executing when the constructor is called. Since most newer C++ |
| * implementations do not allow one to call virtual constructors or virtual |
| * methods from constructors, the thread must be "started" after the |
| * constructor returns. This is done either by defining a "starting" |
| * semaphore object that one or more newly created thread objects can wait |
| * upon, or by invoking an explicit "start" member function. |
| * |
| * Threads can be "suspended" and "resumed". As this behavior is not defined |
| * in the Posix "pthread" specification, it is often emulated through |
| * signals. Typically SIGUSR1 will be used for this purpose in Common C++ |
| * applications, depending in the target platform. On Linux, since threads |
| * are indeed processes, SIGSTP and SIGCONT can be used. On solaris, the |
| * Solaris thread library supports suspend and resume directly. |
| * |
| * Threads can be canceled. Not all platforms support the concept of |
| * externally cancelable threads. On those platforms and API |
| * implementations that do not, threads are typically canceled through the |
| * action of a signal handler. |
| * |
| * As noted earlier, threads are considered running until the "Run" method |
| * returns, or until a cancellation request is made. Common C++ threads can |
| * control how they respond to cancellation, using setCancellation(). |
| * Cancellation requests can be ignored, set to occur only when a |
| * cancellation "point" has been reached in the code, or occur immediately. |
| * Threads can also exit by returning from Run() or by invoking the Exit() |
| * method. |
| * |
| * Generally it is a good practice to initialize any resources the thread may |
| * require within the constructor of your derived thread class, and to purge |
| * or restore any allocated resources in the destructor. In most cases, the |
| * destructor will be executed after the thread has terminated, and hence |
| * will execute within the context of the thread that requested a join rather |
| * than in the context of the thread that is being terminated. Most |
| * destructors in derived thread classes should first call Terminate() to |
| * make sure the thread has stopped running before releasing resources. |
| * |
| * A Common C++ thread is normally canceled by deleting the thread object. |
| * The process of deletion invokes the thread's destructor, and the |
| * destructor will then perform a "join" against the thread using the |
| * Terminate() function. This behavior is not always desirable since the |
| * thread may block itself from cancellation and block the current "delete" |
| * operation from completing. One can alternately invoke Terminate() |
| * directly before deleting a thread object. |
| * |
| * When a given Common C++ thread exits on it's own through it's Run() |
| * method, a "Final" method will be called. This Final method will be called |
| * while the thread is "detached". If a thread object is constructed through |
| * a "new" operator, it's final method can be used to "self delete" when |
| * done, and allows an independent thread to construct and remove itself |
| * autonomously. |
| * |
| * A special global function, getThread(), is provided to identify the thread |
| * object that represents the current execution context you are running |
| * under. This is sometimes needed to deliver signals to the correct thread. |
| * Since all thread manipulation should be done through the Common C++ (base) |
| * thread class itself, this provides the same functionality as things like |
| * "pthread_self" for Common C++. |
| * |
| * All Common C++ threads have an exception "mode" which determines |
| * their behavior when an exception is thrown by another Common C++ |
| * class. Extensions to Common C++ should respect the current |
| * exception mode and use getException() to determine what to do when |
| * they are about to throw an object. The default exception mode |
| * (defined in the Thread() constructor) is throwObject, which causes |
| * a pointer to an instance of the class where the error occured to be |
| * thrown. Other exception modes are throwException, which causes a |
| * class-specific exception class to be thrown, and throwNothing, |
| * which causes errors to be ignored. |
| * |
| * As an example, you could try to call the Socket class with an |
| * invalid address that the system could not bind to. This would |
| * cause an object of type Socket * to be thrown by default, as the |
| * default exception mode is throwObject. If you call |
| * setException(throwException) before the bad call to the Socket |
| * constructor, an object of type SockException (the exception class |
| * for class Socket) will be thrown instead. |
| * |
| * To determine what exception class is thrown by a given Common C++ |
| * class when the exception mode is set to throwException, search the |
| * source files for the class you are interested in for a class which |
| * inherits directly or indirectly from class Exception. This is the |
| * exception class which would be thrown when the exception mode is |
| * set to throwException. |
| * |
| * The advantage of using throwException versus throwObject is that |
| * more information is available to the programmer from the thrown |
| * object. All class-specific exceptions inherit from class |
| * Exception, which provides a getString() method which can be called |
| * to get a human-readable error string. |
| * |
| * Common C++ threads are often aggregated into other classes to provide |
| * services that are "managed" from or operate within the context of a |
| * thread, even within the Common C++ framework itself. A good example of |
| * this is the TCPSession class, which essentially is a combination of a TCP |
| * client connection and a separate thread the user can define by deriving a |
| * class with a Run() method to handle the connected service. This |
| * aggregation logically connects the successful allocation of a given |
| * resource with the construction of a thread to manage and perform |
| * operations for said resource. |
| * |
| * Threads are also used in "service pools". In Common C++, a service pool |
| * is one or more threads that are used to manage a set of resources. While |
| * Common C++ does not provide a direct "pool" class, it does provide a model |
| * for their implementation, usually by constructing an array of thread |
| * "service" objects, each of which can then be assigned the next new |
| * instance of a given resource in turn or algorithmically. |
| * |
| * Threads have signal handlers associated with them. Several signal types |
| * are "predefined" and have special meaning. All signal handlers are |
| * defined as virtual member functions of the Thread class which are called |
| * when a specific signal is received for a given thread. The "SIGPIPE" |
| * event is defined as a "Disconnect" event since it's normally associated |
| * with a socket disconnecting or broken fifo. The Hangup() method is |
| * associated with the SIGHUP signal. All other signals are handled through |
| * the more generic Signal(). |
| * |
| * Incidently, unlike Posix, the win32 API has no concept of signals, and |
| * certainly no means to define or deliver signals on a per-thread basis. |
| * For this reason, no signal handling is supported or emulated in the win32 |
| * implementation of Common C++ at this time. |
| * |
| * In addition to TCPStream, there is a TCPSession class which combines a |
| * thread with a TCPStream object. The assumption made by TCPSession is that |
| * one will service each TCP connection with a separate thread, and this |
| * makes sense for systems where extended connections may be maintained and |
| * complex protocols are being used over TCP. |
| * |
| * |
| * @author David Sugar <dyfet@ostel.com> |
| * @short base class used to derive all threads of execution. |
| */ |
| class __EXPORT Thread |
| { |
| public: |
| /** |
| * How to raise error |
| */ |
| typedef enum Throw { |
| throwNothing, /**< continue without throwing error */ |
| throwObject, /**< throw object that cause error (throw this) */ |
| throwException /**< throw an object relative to error */ |
| } Throw; |
| |
| /** |
| * How work cancellation |
| */ |
| typedef enum Cancel { |
| cancelInitial=0, /**< used internally, do not use */ |
| cancelDeferred=1, /**< exit thread on cancellation pointsuch as yield */ |
| cancelImmediate, /**< exit befor cancellation */ |
| cancelDisabled, /**< ignore cancellation */ |
| cancelManual, /**< unimplemented (working in progress) |
| @todo implement */ |
| cancelDefault=cancelDeferred |
| /**< default you should use this for compatibility instead of deferred */ |
| } Cancel; |
| |
| /** |
| * How work suspend |
| */ |
| typedef enum Suspend { |
| suspendEnable, /**< suspend enabled */ |
| suspendDisable /**< suspend disabled, Suspend do nothing */ |
| } Suspend; |
| |
| #ifndef WIN32 |
| /** @internal */ |
| friend class PosixThread; |
| #endif |
| /** @internal */ |
| friend class DummyThread; |
| private: |
| friend class Cancellation; |
| friend class postream_type; |
| friend class Slog; |
| |
| Semaphore joinSem; |
| static Thread* _main; |
| |
| Thread *_parent; |
| Cancel _cancel; |
| Semaphore *_start; |
| |
| // private data |
| friend class ThreadImpl; |
| class ThreadImpl* priv; |
| |
| public: |
| static Thread *get(void); |
| |
| private: |
| #ifdef WIN32 |
| static unsigned __stdcall Execute(Thread *th); |
| #endif |
| |
| // close current thread, free all and call Notify |
| void close(); |
| |
| private: |
| char _name[32]; |
| static size_t _autostack; |
| |
| #ifdef WIN32 |
| DWORD waitHandle(HANDLE obj, timeout_t timeout); |
| #endif |
| |
| protected: |
| /** |
| * Set the name of the current thread. If the name is passed |
| * as NULL, then the default name is set (usually object |
| * pointer). |
| * |
| * @param text name to use. |
| */ |
| void setName(const char *text); |
| |
| /** |
| * All threads execute by deriving the Run method of Thread. |
| * This method is called after Initial to begin normal operation |
| * of the thread. If the method terminates, then the thread will |
| * also terminate after notifying it's parent and calling it's |
| * Final() method. |
| * |
| * @see #Initial |
| */ |
| virtual void run(void) = 0; |
| |
| /** |
| * A thread that is self terminating, either by invoking exit() or |
| * leaving it's run(), will have this method called. It can be used |
| * to self delete the current object assuming the object was created |
| * with new on the heap rather than stack local, hence one may often |
| * see final defined as "delete this" in a derived thread class. A |
| * final method, while running, cannot be terminated or cancelled by |
| * another thread. Final is called for all cancellation type (even |
| * immediate). |
| * |
| * You can safe delete thread ("delete this") class on final, but |
| * you should exit ASAP (or do not try to call CommonC++ methods...) |
| * |
| * @note A thread cannot delete its own context or join |
| * itself. To make a thread that is a self running object |
| * that self-deletes, one has to detach the thread by using |
| * detach() instead of start(). |
| * |
| * @see #exit |
| * @see #run |
| */ |
| virtual void final(void); |
| |
| /** |
| * The initial method is called by a newly created thread when it |
| * starts execution. This method is ran with deferred cancellation |
| * disabled by default. The Initial method is given a separate |
| * handler so that it can create temporary objects on it's own |
| * stack frame, rather than having objects created on run() that |
| * are only needed by startup and yet continue to consume stack space. |
| * |
| * @see #run |
| * @see #final |
| */ |
| virtual void initial(void); |
| |
| /** |
| * Since getParent() and getThread() only refer to an object of the |
| * Thread "base" type, this virtual method can be replaced in a |
| * derived class with something that returns data specific to the |
| * derived class that can still be accessed through the pointer |
| * returned by getParent() and getThread(). |
| * |
| * @return pointer to derived class specific data. |
| */ |
| virtual void* getExtended(void); |
| |
| /** |
| * When a thread terminates, it now sends a notification message |
| * to the parent thread which created it. The actual use of this |
| * notification is left to be defined in a derived class. |
| * |
| * @param - the thread that has terminated. |
| */ |
| virtual void notify(Thread*); |
| |
| /** |
| * Used to properly exit from a Thread derived run() or initial() |
| * method. Terminates execution of the current thread and calls |
| * the derived classes final() method. |
| */ |
| void exit(void); |
| |
| /** |
| * Used to wait for a join or cancel, in place of explicit exit. |
| */ |
| void sync(void); |
| |
| /** |
| * test a cancellation point for deferred thread cancellation. |
| */ |
| bool testCancel(void); |
| |
| /** |
| * Sets thread cancellation mode. Threads can either be set immune to |
| * termination (cancelDisabled), can be set to terminate when |
| * reaching specific "thread cancellation points" |
| * (cancelDeferred) |
| * or immediately when Terminate is requested (cancelImmediate). |
| * |
| * @param mode for cancellation of the current thread. |
| */ |
| void setCancel(Cancel mode); |
| |
| /** |
| * Sets the thread's ability to be suspended from execution. The |
| * thread may either have suspend enabled (suspendEnable) or |
| * disabled (suspendDisable). |
| * |
| * @param mode for suspend. |
| */ |
| void setSuspend(Suspend mode); |
| |
| /** |
| * Used by another thread to terminate the current thread. Termination |
| * actually occurs based on the current setCancel() mode. When the |
| * current thread does terminate, control is returned to the requesting |
| * thread. terminate() should always be called at the start of any |
| * destructor of a class derived from Thread to assure the remaining |
| * part of the destructor is called without the thread still executing. |
| */ |
| void terminate(void); |
| |
| /** |
| * clear parent thread relationship. |
| */ |
| inline void clrParent(void) |
| {_parent = NULL;}; |
| |
| public: |
| /** |
| * This is actually a special constructor that is used to create a |
| * thread "object" for the current execution context when that context |
| * is not created via an instance of a derived Thread object itself. |
| * This constructor does not support First. |
| * |
| * @param isMain bool used if the main "thread" of the application. |
| */ |
| Thread(bool isMain); |
| |
| /** |
| * When a thread object is contructed, a new thread of execution |
| * context is created. This constructor allows basic properties |
| * of that context (thread priority, stack space, etc) to be defined. |
| * The starting condition is also specified for whether the thread |
| * is to wait on a semaphore before begining execution or wait until |
| * it's start method is called. |
| * |
| * @param pri thread base priority relative to it's parent. |
| * @param stack space as needed in some implementations. |
| */ |
| Thread(int pri = 0, size_t stack = 0); |
| |
| #ifndef WIN32 |
| /** |
| * A thread of execution can also be specified by cloning an existing |
| * thread. The existing thread's properties (cancel mode, priority, |
| * etc), are also duplicated. |
| * |
| * @param th currently executing thread object to clone. |
| * @todo implement in win32 |
| */ |
| Thread(const Thread &th); |
| #endif |
| |
| /** |
| * The thread destructor should clear up any resources that have |
| * been allocated by the thread. The desctructor of a derived |
| * thread should begin with Terminate() and is presumed to then |
| * execute within the context of the thread causing terminaton. |
| */ |
| virtual ~Thread(); |
| |
| /** |
| * Set base stack limit before manual stack sizes have effect. |
| * |
| * @param size stack size to set, or use 0 to clear autostack. |
| */ |
| static void setStack(size_t size = 0) |
| {_autostack = size;}; |
| |
| /** |
| * A thread-safe sleep call. On most Posix systems, "sleep()" |
| * is implimented with SIGALRM making it unusable from multipe |
| * threads. Pthread libraries often define an alternate "sleep" |
| * handler such as usleep(), nanosleep(), or nap(), that is thread |
| * safe, and also offers a higher timer resolution. |
| * |
| * @param msec timeout in milliseconds. |
| */ |
| static void sleep(timeout_t msec); |
| |
| /** |
| * Yields the current thread's CPU time slice to allow another thread to |
| * begin immediate execution. |
| */ |
| static void yield(void); |
| |
| /** |
| * When a new thread is created, it does not begin immediate |
| * execution. This is because the derived class virtual tables |
| * are not properly loaded at the time the C++ object is created |
| * within the constructor itself, at least in some compiler/system |
| * combinations. The thread can either be told to wait for an |
| * external semaphore, or it can be started directly after the |
| * constructor completes by calling the start() method. |
| * |
| * @return error code if execution fails. |
| * @param start optional starting semaphore to alternately use. |
| */ |
| int start(Semaphore *start = 0); |
| |
| /** |
| * Start a new thread as "detached". This is an alternative |
| * start() method that resolves some issues with later glibc |
| * implimentations which incorrectly impliment self-detach. |
| * |
| * @return error code if execution fails. |
| * @param start optional starting semaphore to alternately use. |
| */ |
| int detach(Semaphore *start = 0); |
| |
| /** |
| * Gets the pointer to the Thread class which created the current |
| * thread object. |
| * |
| * @return a Thread *, or "(Thread *)this" if no parent. |
| */ |
| inline Thread *getParent(void) |
| {return _parent;}; |
| |
| /** |
| * Suspends execution of the selected thread. Pthreads do not |
| * normally support suspendable threads, so the behavior is |
| * simulated with signals. On systems such as Linux that |
| * define threads as processes, SIGSTOP and SIGCONT may be used. |
| */ |
| void suspend(void); |
| |
| /** |
| * Resumes execution of the selected thread. |
| */ |
| void resume(void); |
| |
| /** |
| * Used to retrieve the cancellation mode in effect for the |
| * selected thread. |
| * |
| * @return cancellation mode constant. |
| */ |
| inline Cancel getCancel(void) |
| {return _cancel;}; |
| |
| /** |
| * Verifies if the thread is still running or has already been |
| * terminated but not yet deleted. |
| * |
| * @return true if the thread is still executing. |
| */ |
| bool isRunning(void) const; |
| |
| /** |
| * Check if this thread is detached. |
| * |
| * @return true if the thread is detached. |
| */ |
| bool isDetached(void) const; |
| |
| /** |
| * Blocking call which unlocks when thread terminates. |
| */ |
| void join(void); |
| |
| /** |
| * Tests to see if the current execution context is the same as |
| * the specified thread object. |
| * |
| * @return true if the current context is this object. |
| */ |
| bool isThread(void) const; |
| |
| /** |
| * Get system thread numeric identifier. |
| * |
| * @return numeric identifier of this thread. |
| */ |
| cctid_t getId(void) const; |
| |
| /** |
| * Get the name string for this thread, to use in |
| * debug messages. |
| * |
| * @return debug name. |
| */ |
| const char *getName(void) const |
| {return _name;}; |
| |
| /** |
| * Get exception mode of the current thread. |
| * |
| * @return exception mode. |
| */ |
| static Throw getException(void); |
| |
| /** |
| * Set exception mode of the current thread. |
| * |
| * @return exception mode. |
| */ |
| static void setException(Throw mode); |
| |
| /** |
| * Signal the semaphore that the specified thread is waiting for |
| * before beginning execution. |
| * |
| * @param th specified thread. |
| */ |
| friend inline void operator++(Thread &th) |
| {if (th._start) th._start->post();}; |
| |
| friend inline void operator--(Thread &th) |
| {if (th._start) th._start->wait();}; |
| |
| #ifdef WIN32 |
| bool isCancelled() const; |
| |
| static DWORD waitThread(HANDLE hRef, timeout_t timeout); |
| #endif |
| |
| /** |
| * This is used to help build wrapper functions in libraries |
| * around system calls that should behave as cancellation |
| * points but don't. |
| * |
| * @return saved cancel type. |
| */ |
| static Cancel enterCancel(void); |
| |
| /** |
| * This is used to restore a cancel block. |
| * |
| * @param cancel type that was saved. |
| */ |
| static void exitCancel(Cancel cancel); |
| }; |
| |
| /** |
| * A class to automatically set the thread cancellation mode of a |
| * member function. When the member function returns and the automatic |
| * variable falls out of scope, the previous thread cancellation mode |
| * is restored. |
| * |
| * @author David Sugar <dyfet@gnu.org> |
| * @short Automatic cancellation mode setting. |
| */ |
| class __EXPORT Cancellation |
| { |
| private: |
| Thread::Cancel prior; |
| |
| public: |
| Cancellation(Thread::Cancel cancel); |
| ~Cancellation(); |
| }; |
| |
| #if !defined(WIN32) && !defined(__MINGW32__) |
| typedef int signo_t; |
| |
| class PosixThread: public Thread |
| { |
| private: |
| #ifndef WIN32 |
| /** @internal */ |
| friend class ThreadImpl; |
| friend class Thread; |
| #endif |
| #ifndef CCXX_SIG_THREAD_ALARM |
| static PosixThread *_timer; |
| static Mutex _arm; |
| #endif |
| |
| time_t _alarm; |
| static void signalThread(Thread* th,signo_t signo); |
| protected: |
| |
| /** |
| * In the Posix version of Common C++, this can be used to send a |
| * signal into the parent thread of the current object. |
| * |
| * @param signo a posix signal id. |
| */ |
| inline void signalParent(signo_t signo) |
| { signalThread(_parent,signo); }; |
| |
| /** |
| * In the Posix version of Common C++, this can be used to send a |
| * signal into the main application thread. |
| * |
| * @param signo a posix signal id. |
| */ |
| inline void signalMain(signo_t signo) |
| { signalThread(_main,signo);}; |
| |
| /** |
| * A derivable method to call when a SIGALRM is being delivered |
| * to a specific thread. |
| */ |
| virtual void onTimer(void); |
| |
| /** |
| * A derived method to handle hangup events being delivered |
| * to a specific thread. |
| */ |
| virtual void onHangup(void); |
| |
| /** |
| * A derived method to call when a SIGABRT is being delivered |
| * to a specific thread. |
| */ |
| virtual void onException(void); |
| |
| /** |
| * A derived method to call when a SIGPIPE is being delivered |
| * to a specific thread. |
| */ |
| virtual void onDisconnect(void); |
| |
| /** |
| * A derived method to handle asynchronous I/O requests delivered |
| * to the specified thread. |
| */ |
| virtual void onPolling(void); |
| |
| /** |
| * A derivable method to call for delivering a signal event to |
| * a specified thread. |
| * |
| * @param - posix signal id. |
| */ |
| virtual void onSignal(int); |
| |
| /** |
| * Used to specify a timeout event that can be delivered to the |
| * current thread via SIGALRM. When the timer expires, the onTimer() |
| * method is called for the thread. At present, only one thread |
| * timer can be active at any given time. On some operating |
| * systems (including Linux) a timer can be active on each thread. |
| * |
| * @param timer timeout in milliseconds. |
| * @param periodic should the timer be periodic. |
| * @note currently, periodic timers are only available on |
| * systems with a working setitimer call. |
| */ |
| void setTimer(timeout_t timer, bool periodic = false); |
| |
| /** |
| * Gets the time remaining for the current threads timer before |
| * it expires. |
| * |
| * @return time remaining before timer expires in milliseconds. |
| */ |
| timeout_t getTimer(void) const; |
| |
| /** |
| * Terminates the timer before the timeout period has expired. |
| * This prevents the timer from sending it's SIGALRM and makes |
| * the timer available to other threads. |
| */ |
| void endTimer(void); |
| |
| #if defined(HAVE_SIGWAIT) || defined(HAVE_SIGWAIT2) |
| /** |
| * Used to wait on a Posix signal from another thread. This can be |
| * used as a crude rondevious/synchronization method between threads. |
| * |
| * @param signo a posix signal id. |
| */ |
| void waitSignal(signo_t signo); |
| #endif |
| |
| /** |
| * Used to enable or disable a signal within the current thread. |
| * |
| * @param signo posix signal id. |
| * @param active set to true to enable. |
| */ |
| void setSignal(int signo, bool active); |
| |
| /** |
| * Access to pthread_attr structure |
| * this allows setting/modifying pthread attributes |
| * not covered in the platform independant Thread constructor, |
| * e.g. contention scope or scheduling policy |
| */ |
| pthread_attr_t *getPthreadAttrPtr(void); |
| |
| /** |
| * Get pthread_t of underlying posix thread (useful for |
| * debugging/logging) |
| */ |
| pthread_t getPthreadId(void); |
| |
| public: |
| |
| PosixThread(int pri = 0, size_t stack = 0); |
| |
| /** |
| * Delivers a Posix signal to the current thread. |
| * |
| * @param signo a posix signal id. |
| */ |
| inline void signalThread(int signo) |
| {signalThread(this, signo);}; |
| |
| /** |
| * Install a signal handler for use by threads and |
| * the OnSignal() event notification handler. |
| * |
| * @param signo posix signal id. |
| */ |
| static void sigInstall(int signo); |
| }; |
| #endif |
| |
| /** |
| * This class allows the creation of a thread context unique "pointer" |
| * that can be set and retrieved and can be used to create thread specific |
| * data areas for implementing "thread safe" library routines. |
| * |
| * Finally, Common C++ supports a |
| * thread-safe "AtomicCounter" class. This can often be used for reference |
| * counting without having to protect the counter with a separate Mutex |
| * counter. This lends to lighter-weight code. |
| * |
| * |
| * @author David Sugar <dyfet@ostel.com> |
| * @short container for thread specific data storage. |
| */ |
| class __EXPORT ThreadKey |
| { |
| private: |
| #ifndef WIN32 |
| pthread_key_t key; |
| typedef void (*TDestruct)(void*); |
| friend class ThreadImpl; |
| ThreadKey(TDestruct destruct); |
| #else |
| DWORD key; |
| #endif |
| |
| public: |
| /** |
| * Create a unique thread specific container. |
| */ |
| ThreadKey(); |
| |
| /** |
| * Destroy a thread specific container and any contents reserved. |
| */ |
| virtual ~ThreadKey(); |
| |
| /** |
| * Get the value of the pointer for the thread specific data |
| * container. A unique pointer can be set for each execution |
| * context. |
| * |
| * @return a unique void * for each execution context. |
| */ |
| void *getKey(void); |
| |
| /** |
| * Set the value of the pointer for the current thread specific |
| * execution context. This can be used to store thread context |
| * specific data. |
| * |
| * @param - ptr to thread context specific data. |
| */ |
| void setKey(void *); |
| }; |
| |
| /** |
| * Timer ports are used to provide synchronized timing events when managed |
| * under a "service thread" such as SocketService. This is made into a |
| * stand-alone base class since other derived libraries (such as the |
| * serial handlers) may also use the pooled "service thread" model |
| * and hence also require this code for managing timing. |
| * |
| * @author David Sugar <dyfet@ostel.com> |
| * @short synchronized millisecond timing for service threads. |
| */ |
| class __EXPORT TimerPort |
| { |
| #ifndef WIN32 |
| struct timeval timer; |
| #else |
| DWORD timer; |
| #endif |
| bool active; |
| |
| public: |
| /** |
| * Create a timer, mark it as inactive, and set the initial |
| * "start" time to the creation time of the timer object. This |
| * allows "incTimer" to initially refer to time delays relative |
| * to the original start time of the object. |
| */ |
| TimerPort(); |
| |
| /** |
| * Set a new start time for the object based on when this call is |
| * made and optionally activate the timer for a specified number |
| * of milliseconds. This can be used to set the starting time |
| * of a realtime session. |
| * |
| * @param timeout delay in milliseconds from "now" |
| */ |
| void setTimer(timeout_t timeout = 0); |
| |
| /** |
| * Set a timeout based on the current time reference value either |
| * from object creation or the last setTimer(). This reference |
| * can be used to time synchronize realtime data over specified |
| * intervals and force expiration when a new frame should be |
| * released in a synchronized manner. |
| * |
| * @param timeout delay in milliseconds from reference. |
| */ |
| void incTimer(timeout_t timeout); |
| |
| /** |
| * Adjust a timeout based on the current time reference value either |
| * from object creation or the last setTimer(). This reference |
| * can be used to time synchronize realtime data over specified |
| * intervals and force expiration when a new frame should be |
| * released in a synchronized manner. |
| * |
| * @param timeout delay in milliseconds from reference. |
| */ |
| void decTimer(timeout_t timeout); |
| |
| /** |
| * Sleep until the current timer expires. This is useful in time |
| * syncing realtime periodic tasks. |
| */ |
| void sleepTimer(void); |
| |
| /** |
| * This is used to "disable" the service thread from expiring |
| * the timer object. It does not effect the reference time from |
| * either creation or a setTimer(). |
| */ |
| void endTimer(void); |
| |
| /** |
| * This is used by service threads to determine how much time |
| * remains before the timer expires based on a timeout specified |
| * in setTimer() or incTimer(). It can also be called after |
| * setting a timeout with incTimer() to see if the current timeout |
| * has already expired and hence that the application is already |
| * delayed and should skip frame(s). |
| * |
| * return time remaining in milliseconds, or TIMEOUT_INF if |
| * inactive. |
| */ |
| timeout_t getTimer(void) const; |
| |
| /** |
| * This is used to determine how much time has elapsed since a |
| * timer port setTimer benchmark time was initially set. This |
| * allows one to use setTimer() to set the timer to the current |
| * time and then measure elapsed time from that point forward. |
| * |
| * return time elapsed in milliseconds, or TIMEOUT_INF if |
| * inactive. |
| */ |
| timeout_t getElapsed(void) const; |
| }; |
| |
| |
| |
| // FIXME: not in win32 implementation |
| #if !defined(WIN32) |
| |
| // FIXME: private declaration ??? |
| struct timespec *getTimeout(struct timespec *spec, timeout_t timeout); |
| |
| #if !defined(__CYGWIN32__) && !defined(__MINGW32__) |
| void wait(signo_t signo); |
| #endif |
| |
| #endif // !WIN32 |
| |
| #ifdef USE_POLL |
| |
| /** |
| * The poller class is used to help manage pollfd structs for use in the |
| * updated serial and socket "port" code. |
| * |
| * @author Gianni Mariani <gianni@mariani.ws> |
| * @short pollfd assistance class for port classes. |
| */ |
| class Poller |
| { |
| private: |
| int nufds; |
| pollfd *ufds; |
| |
| public: |
| Poller(); |
| |
| virtual ~Poller(); |
| |
| /** |
| * reserve a specified number of poll descriptors. If additional |
| * descriptors are needed, they are allocated. |
| * |
| * @return new array of descriptors. |
| * @param cnt number of desctiptors to reserve |
| */ |
| pollfd *getList(int cnt); |
| |
| /** |
| * Retreive the current array of poll descriptors. |
| * |
| * @return array of descriptors. |
| */ |
| inline pollfd *getList(void) |
| {return ufds;}; |
| }; |
| #endif |
| |
| inline Thread *getThread(void) |
| {return Thread::get();} |
| |
| /** |
| * This class is used to access non-reentrant date and time functions in the |
| * standard C library. |
| * |
| * The class has two purposes: |
| * - 1 To be used internaly in CommonCpp's date and time classes to make them |
| * thread safe. |
| * - 2 To be used by clients as thread safe replacements to the standard C |
| * functions, much like Thread::sleep() represents a thread safe version |
| * of the standard sleep() function. |
| * |
| * @note The class provides one function with the same name as its equivalent |
| * standard function and one with another, unique name. For new clients, |
| * the version with the unique name is recommended to make it easy to |
| * grep for accidental usage of the standard functions. The version with |
| * the standard name is provided for existing clients to sed replace their |
| * original version. |
| * |
| * @note Also note that some functions that returned pointers have been redone |
| * to take that pointer as an argument instead, making the caller |
| * responsible for memory allocation/deallocation. This is almost |
| * how POSIX specifies *_r functions (reentrant versions of the |
| * standard time functions), except the POSIX functions also return the |
| * given pointer while we do not. We don't use the *_r functions as they |
| * aren't all generally available on all platforms yet. |
| * |
| * @author Idar Tollefsen <idar@cognita.no> |
| * @short Thread safe date and time functions. |
| */ |
| class __EXPORT SysTime |
| { |
| private: |
| static Mutex timeLock; |
| |
| protected: |
| inline static void lock(void) |
| {timeLock.enterMutex();} |
| |
| inline static void unlock(void) |
| {timeLock.leaveMutex();} |
| |
| public: |
| static time_t getTime(time_t *tloc = NULL); |
| static time_t time(time_t *tloc) |
| { return getTime(tloc); }; |
| |
| static int getTimeOfDay(struct timeval *tp); |
| static int gettimeofday(struct timeval *tp, struct timezone *) |
| { return getTimeOfDay(tp); }; |
| |
| static struct tm *getLocalTime(const time_t *clock, struct tm *result); |
| static struct tm *locatime(const time_t *clock, struct tm *result) |
| { return getLocalTime(clock, result); }; |
| |
| static struct tm *getGMTTime(const time_t *clock, struct tm *result); |
| static struct tm *gmtime(const time_t *clock, struct tm *result) |
| { return getGMTTime(clock, result);}; |
| }; |
| |
| #ifndef HAVE_LOCALTIME_R |
| |
| inline struct tm *localtime_r(const time_t *t, struct tm *b) |
| {return SysTime::getLocalTime(t, b);}; |
| inline char *ctime_r(const time_t *t, char *buf) |
| {return ctime(t);}; |
| inline struct tm *gmtime_r(const time_t *t, struct tm *b) \ |
| {return SysTime::getGMTTime(t, b);}; |
| inline char *asctime_r(const struct tm *tm, char *b) \ |
| {return asctime(tm);}; |
| |
| #endif |
| |
| #ifdef CCXX_NAMESPACES |
| } |
| #endif |
| |
| #endif |
| /** EMACS ** |
| * Local variables: |
| * mode: c++ |
| * c-basic-offset: 4 |
| * End: |
| */ |