// Copyright (C) 1999-2005 Open Source Telecom Corporation. // // 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 #ifndef WIN32 #define CCXX_POSIX #endif // !WIN32 #include #ifndef WIN32 #include #endif // !WIN32 #undef CCXX_USE_WIN32_ATOMIC #ifndef WIN32 #include #include #include #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 #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 * @short Mutex lock for protected access. */ class __EXPORT Mutex { private: static bool _debug; const char *_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 * @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 * @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 * @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 * @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 * @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 * @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 * @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); // 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 * @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 * @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 * @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 * @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 * @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 * @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 * @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 * @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: 8 * End: */