| // Copyright (C) 2006-2010 David Sugar, Tycho Softworks. |
| // |
| // This file is part of GNU uCommon C++. |
| // |
| // GNU uCommon C++ is free software: you can redistribute it and/or modify |
| // it under the terms of the GNU Lesser General Public License as published |
| // by the Free Software Foundation, either version 3 of the License, or |
| // (at your option) any later version. |
| // |
| // GNU uCommon C++ 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 Lesser General Public License for more details. |
| // |
| // You should have received a copy of the GNU Lesser General Public License |
| // along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>. |
| |
| /** |
| * Thread classes and sychronization objects. |
| * The theory behind ucommon thread classes is that they would be used |
| * to create derived classes where thread-specific data can be stored as |
| * member data of the derived class. The run method is called when the |
| * context is executed. Since we use a pthread foundation, we support |
| * both detached threads and joinable threads. Objects based on detached |
| * threads should be created with new, and will automatically delete when |
| * the thread context exits. Joinable threads will be joined with deleted. |
| * |
| * The theory behind ucommon sychronization objects is that all upper level |
| * sychronization objects can be formed directly from a mutex and conditional. |
| * This includes semaphores, barriers, rwlock, our own specialized conditional |
| * lock, resource-bound locking, and recurive exclusive locks. Using only |
| * conditionals means we are not dependent on platform specific pthread |
| * implimentations that may not impliment some of these, and hence improves |
| * portability and consistency. Given that our rwlocks are recursive access |
| * locks, one can safely create read/write threading pairs where the read |
| * threads need not worry about deadlocks and the writers need not either if |
| * they only write-lock one instance at a time to change state. |
| * @file ucommon/thread.h |
| */ |
| |
| /** |
| * An example of the thread queue class. This may be relevant to producer- |
| * consumer scenarios and realtime applications where queued messages are |
| * stored on a re-usable object pool. |
| * @example queue.cpp |
| */ |
| |
| /** |
| * A simple example of threading and join operation. |
| * @example thread.cpp |
| */ |
| |
| #ifndef _UCOMMON_THREAD_H_ |
| #define _UCOMMON_THREAD_H_ |
| |
| #ifndef _UCOMMON_CPR_H_ |
| #include <ucommon/cpr.h> |
| #endif |
| |
| #ifndef _UCOMMON_ACCESS_H_ |
| #include <ucommon/access.h> |
| #endif |
| |
| #ifndef _UCOMMON_TIMERS_H_ |
| #include <ucommon/timers.h> |
| #endif |
| |
| #ifndef _UCOMMON_MEMORY_H_ |
| #include <ucommon/memory.h> |
| #endif |
| |
| NAMESPACE_UCOMMON |
| |
| class SharedPointer; |
| |
| /** |
| * The conditional is a common base for other thread synchronizing classes. |
| * Many of the complex sychronization objects, including barriers, semaphores, |
| * and various forms of read/write locks are all built from the conditional. |
| * This assures that the minimum functionality to build higher order thread |
| * synchronizing objects is a pure conditional, and removes dependencies on |
| * what may be optional features or functions that may have different |
| * behaviors on different pthread implimentations and platforms. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT Conditional |
| { |
| private: |
| friend class ConditionalAccess; |
| |
| #if defined(_MSCONDITIONAL_) |
| CRITICAL_SECTION mutex; |
| CONDITION_VARIABLE cond; |
| #elif defined(_MSWINDOWS_) |
| enum {SIGNAL = 0, BROADCAST = 1}; |
| HANDLE events[2]; |
| unsigned waiting; |
| CRITICAL_SECTION mlock; |
| CRITICAL_SECTION mutex; |
| #else |
| #ifndef __PTH__ |
| class __LOCAL attribute |
| { |
| public: |
| pthread_condattr_t attr; |
| attribute(); |
| }; |
| |
| __LOCAL static attribute attr; |
| #endif |
| |
| pthread_cond_t cond; |
| pthread_mutex_t mutex; |
| #endif |
| |
| protected: |
| friend class TimedEvent; |
| |
| /** |
| * Conditional wait for signal on millisecond timeout. |
| * @param timeout in milliseconds. |
| * @return true if signalled, false if timer expired. |
| */ |
| bool wait(timeout_t timeout); |
| |
| /** |
| * Conditional wait for signal on timespec timeout. |
| * @param timeout as a high resolution timespec. |
| * @return true if signalled, false if timer expired. |
| */ |
| bool wait(struct timespec *timeout); |
| |
| #ifdef _MSWINDOWS_ |
| inline void lock(void) |
| {EnterCriticalSection(&mutex);}; |
| |
| inline void unlock(void) |
| {LeaveCriticalSection(&mutex);}; |
| |
| void wait(void); |
| void signal(void); |
| void broadcast(void); |
| |
| #else |
| /** |
| * Lock the conditional's supporting mutex. |
| */ |
| inline void lock(void) |
| {pthread_mutex_lock(&mutex);}; |
| |
| /** |
| * Unlock the conditional's supporting mutex. |
| */ |
| inline void unlock(void) |
| {pthread_mutex_unlock(&mutex);}; |
| |
| /** |
| * Wait (block) until signalled. |
| */ |
| inline void wait(void) |
| {pthread_cond_wait(&cond, &mutex);}; |
| |
| /** |
| * Signal the conditional to release one waiting thread. |
| */ |
| inline void signal(void) |
| {pthread_cond_signal(&cond);}; |
| |
| /** |
| * Signal the conditional to release all waiting threads. |
| */ |
| inline void broadcast(void) |
| {pthread_cond_broadcast(&cond);}; |
| #endif |
| |
| /** |
| * Initialize and construct conditional. |
| */ |
| Conditional(); |
| |
| /** |
| * Destroy conditional, release any blocked threads. |
| */ |
| ~Conditional(); |
| |
| public: |
| #if !defined(_MSWINDOWS_) && !defined(__PTH__) |
| /** |
| * Support function for getting conditional attributes for realtime |
| * scheduling. |
| * @return attributes to use for creating realtime conditionals. |
| */ |
| static inline pthread_condattr_t *initializer(void) |
| {return &attr.attr;}; |
| #endif |
| |
| /** |
| * Convert a millisecond timeout into use for high resolution |
| * conditional timers. |
| * @param hires timespec representation to set. |
| * @param timeout to convert. |
| */ |
| static void set(struct timespec *hires, timeout_t timeout); |
| }; |
| |
| /** |
| * The conditional rw seperates scheduling for optizming behavior or rw locks. |
| * This varient of conditonal seperates scheduling read (broadcast wakeup) and |
| * write (signal wakeup) based threads. This is used to form generic rwlock's |
| * as well as the specialized condlock. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT ConditionalAccess : private Conditional |
| { |
| protected: |
| #if defined _MSCONDITIONAL_ |
| CONDITION_VARIABLE bcast; |
| #elif !defined(_MSWINDOWS_) |
| pthread_cond_t bcast; |
| #endif |
| |
| unsigned pending, waiting, sharing; |
| |
| /** |
| * Conditional wait for signal on millisecond timeout. |
| * @param timeout in milliseconds. |
| * @return true if signalled, false if timer expired. |
| */ |
| bool waitSignal(timeout_t timeout); |
| |
| /** |
| * Conditional wait for broadcast on millisecond timeout. |
| * @param timeout in milliseconds. |
| * @return true if signalled, false if timer expired. |
| */ |
| bool waitBroadcast(timeout_t timeout); |
| |
| |
| /** |
| * Conditional wait for signal on timespec timeout. |
| * @param timeout as a high resolution timespec. |
| * @return true if signalled, false if timer expired. |
| */ |
| bool waitSignal(struct timespec *timeout); |
| |
| /** |
| * Conditional wait for broadcast on timespec timeout. |
| * @param timeout as a high resolution timespec. |
| * @return true if signalled, false if timer expired. |
| */ |
| bool waitBroadcast(struct timespec *timeout); |
| |
| /** |
| * Convert a millisecond timeout into use for high resolution |
| * conditional timers. |
| * @param hires timespec representation to set. |
| * @param timeout to convert. |
| */ |
| inline static void set(struct timespec *hires, timeout_t timeout) |
| {Conditional::set(hires, timeout);}; |
| |
| |
| #ifdef _MSWINDOWS_ |
| inline void lock(void) |
| {EnterCriticalSection(&mutex);}; |
| |
| inline void unlock(void) |
| {LeaveCriticalSection(&mutex);}; |
| |
| void waitSignal(void); |
| void waitBroadcast(void); |
| |
| inline void signal(void) |
| {Conditional::signal();}; |
| |
| inline void broadcast(void) |
| {Conditional::broadcast();}; |
| |
| #else |
| /** |
| * Lock the conditional's supporting mutex. |
| */ |
| inline void lock(void) |
| {pthread_mutex_lock(&mutex);}; |
| |
| /** |
| * Unlock the conditional's supporting mutex. |
| */ |
| inline void unlock(void) |
| {pthread_mutex_unlock(&mutex);}; |
| |
| /** |
| * Wait (block) until signalled. |
| */ |
| inline void waitSignal(void) |
| {pthread_cond_wait(&cond, &mutex);}; |
| |
| /** |
| * Wait (block) until broadcast. |
| */ |
| inline void waitBroadcast(void) |
| {pthread_cond_wait(&bcast, &mutex);}; |
| |
| |
| /** |
| * Signal the conditional to release one signalled thread. |
| */ |
| inline void signal(void) |
| {pthread_cond_signal(&cond);}; |
| |
| /** |
| * Signal the conditional to release all broadcast threads. |
| */ |
| inline void broadcast(void) |
| {pthread_cond_broadcast(&bcast);}; |
| #endif |
| public: |
| /** |
| * Initialize and construct conditional. |
| */ |
| ConditionalAccess(); |
| |
| /** |
| * Destroy conditional, release any blocked threads. |
| */ |
| ~ConditionalAccess(); |
| |
| /** |
| * Access mode shared thread scheduling. |
| */ |
| void access(void); |
| |
| /** |
| * Exclusive mode write thread scheduling. |
| */ |
| void modify(void); |
| |
| /** |
| * Release access mode read scheduling. |
| */ |
| void release(void); |
| |
| /** |
| * Complete exclusive mode write scheduling. |
| */ |
| void commit(void); |
| |
| /** |
| * Specify a maximum sharing (access) limit. This can be used |
| * to detect locking errors, such as when aquiring locks that are |
| * not released. |
| * @param max sharing level. |
| */ |
| void limit_sharing(unsigned max); |
| }; |
| |
| /** |
| * Event notification to manage scheduled realtime threads. The timer |
| * is advanced to sleep threads which then wakeup either when the timer |
| * has expired or they are notified through the signal handler. This can |
| * be used to schedule and signal one-time completion handlers or for time |
| * synchronized events signaled by an asychrononous I/O or event source. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT TimedEvent : public Timer |
| { |
| private: |
| #ifdef _MSWINDOWS_ |
| HANDLE event; |
| #else |
| pthread_cond_t cond; |
| bool signalled; |
| #endif |
| pthread_mutex_t mutex; |
| |
| protected: |
| /** |
| * Lock the object for wait or to manipulate derived data. This is |
| * relevant to manipulations in a derived class. |
| */ |
| void lock(void); |
| |
| /** |
| * Release the object lock after waiting. This is relevent to |
| * manipulations in a derived class. |
| */ |
| void release(void); |
| |
| /** |
| * Wait while locked. This can be used in more complex derived |
| * objects where we are concerned with synchronized access between |
| * the signaling and event thread. This can be used in place of |
| * wait, but lock and release methods must be used around it. |
| * @return true if time expired. |
| */ |
| bool sync(void); |
| |
| public: |
| /** |
| * Create event handler and timer for timing of events. |
| */ |
| TimedEvent(void); |
| |
| /** |
| * Create event handler and timer set to trigger a timeout. |
| * @param timeout in milliseconds. |
| */ |
| TimedEvent(timeout_t timeout); |
| |
| /** |
| * Create event handler and timer set to trigger a timeout. |
| * @param timeout in seconds. |
| */ |
| TimedEvent(time_t timeout); |
| |
| /** |
| * Destroy timer and release pending events. |
| */ |
| ~TimedEvent(); |
| |
| /** |
| * Signal pending event. Object may be locked or unlocked. The |
| * signalling thread may choose to lock and check a condition in |
| * a derived class before signalling. |
| */ |
| void signal(void); |
| |
| /** |
| * Wait to be signalled or until timer expires. This is a wrapper for |
| * expire for simple completion events. |
| * @param timeout to wait from last reset. |
| * @return true if signaled, false if timeout. |
| */ |
| bool wait(timeout_t timeout); |
| |
| /** |
| * A simple wait until triggered. |
| */ |
| void wait(void); |
| |
| /** |
| * Reset triggered conditional. |
| */ |
| void reset(void); |
| }; |
| |
| /** |
| * Portable recursive exclusive lock. This class is built from the |
| * conditional and hence does not require support for non-standard and |
| * platform specific extensions to pthread mutex to support recrusive |
| * style mutex locking. The exclusive protocol is implimented to support |
| * exclusive_lock referencing. |
| */ |
| class __EXPORT RecursiveMutex : private Conditional, public ExclusiveAccess |
| { |
| protected: |
| unsigned waiting; |
| unsigned lockers; |
| pthread_t locker; |
| |
| virtual void _lock(void); |
| virtual void _unlock(void); |
| |
| public: |
| /** |
| * Create rexlock. |
| */ |
| RecursiveMutex(); |
| |
| /** |
| * Acquire or increase locking. |
| */ |
| void lock(void); |
| |
| /** |
| * Timed lock request. |
| */ |
| bool lock(timeout_t timeout); |
| |
| /** |
| * Release or decrease locking. |
| */ |
| void release(void); |
| }; |
| |
| /** |
| * A generic and portable implimentation of Read/Write locking. This |
| * class impliments classical read/write locking, including "timed" locks. |
| * Support for scheduling threads to avoid writer starvation is also provided |
| * for. By building read/write locks from a conditional, we make them |
| * available on pthread implimetations and other platforms which do not |
| * normally include optional pthread rwlock's. We also do not restrict |
| * the number of threads that may use the lock. Finally, both the exclusive |
| * and shared protocols are implimented to support exclusive_lock and |
| * shared_lock referencing. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT ThreadLock : private ConditionalAccess, public ExclusiveAccess, public SharedAccess |
| { |
| protected: |
| unsigned writers; |
| pthread_t writeid; |
| |
| virtual void _lock(void); |
| virtual void _share(void); |
| virtual void _unlock(void); |
| |
| public: |
| /** |
| * Guard class to apply scope based access locking to objects. The rwlock |
| * is located from the rwlock pool rather than contained in the target |
| * object, and the read lock is released when the guard object falls out of |
| * scope. This is essentially an automation mechanism for mutex::reader. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT guard_reader |
| { |
| private: |
| const void *object; |
| |
| public: |
| /** |
| * Create an unitialized instance of guard. Usually used with a |
| * guard = operator. |
| */ |
| guard_reader(); |
| |
| /** |
| * Construct a guard for a specific object. |
| * @param object to guard. |
| */ |
| guard_reader(const void *object); |
| |
| /** |
| * Release mutex when guard falls out of scope. |
| */ |
| ~guard_reader(); |
| |
| /** |
| * Set guard to mutex lock a new object. If a lock is currently |
| * held, it is released. |
| * @param object to guard. |
| */ |
| void set(const void *object); |
| |
| /** |
| * Prematurely release a guard. |
| */ |
| void release(void); |
| |
| /** |
| * Set guard to read lock a new object. If a lock is currently |
| * held, it is released. |
| * @param pointer to object to guard. |
| */ |
| inline void operator=(const void *pointer) |
| {set(pointer);}; |
| }; |
| |
| /** |
| * Guard class to apply scope based exclusive locking to objects. The rwlock |
| * is located from the rwlock pool rather than contained in the target |
| * object, and the write lock is released when the guard object falls out of |
| * scope. This is essentially an automation mechanism for mutex::writer. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT guard_writer |
| { |
| private: |
| const void *object; |
| |
| public: |
| /** |
| * Create an unitialized instance of guard. Usually used with a |
| * guard = operator. |
| */ |
| guard_writer(); |
| |
| /** |
| * Construct a guard for a specific object. |
| * @param object to guard. |
| */ |
| guard_writer(const void *object); |
| |
| /** |
| * Release mutex when guard falls out of scope. |
| */ |
| ~guard_writer(); |
| |
| /** |
| * Set guard to mutex lock a new object. If a lock is currently |
| * held, it is released. |
| * @param object to guard. |
| */ |
| void set(const void *object); |
| |
| /** |
| * Prematurely release a guard. |
| */ |
| void release(void); |
| |
| /** |
| * Set guard to read lock a new object. If a lock is currently |
| * held, it is released. |
| * @param pointer to object to guard. |
| */ |
| inline void operator=(const void *pointer) |
| {set(pointer);}; |
| }; |
| |
| /** |
| * Create an instance of a rwlock. |
| */ |
| ThreadLock(); |
| |
| /** |
| * Request modify (write) access through the lock. |
| * @param timeout in milliseconds to wait for lock. |
| * @return true if locked, false if timeout. |
| */ |
| bool modify(timeout_t timeout = Timer::inf); |
| |
| /** |
| * Request shared (read) access through the lock. |
| * @param timeout in milliseconds to wait for lock. |
| * @return true if locked, false if timeout. |
| */ |
| bool access(timeout_t timeout = Timer::inf); |
| |
| /** |
| * Specify hash table size for guard protection. The default is 1. |
| * This should be called at initialization time from the main thread |
| * of the application before any other threads are created. |
| * @param size of hash table used for guarding. |
| */ |
| static void indexing(unsigned size); |
| |
| /** |
| * Write protect access to an arbitrary object. This is like the |
| * protect function of mutex. |
| * @param object to protect. |
| * @param timeout in milliseconds to wait for lock. |
| * @return true if locked, false if timeout. |
| */ |
| static bool writer(const void *object, timeout_t timeout = Timer::inf); |
| |
| /** |
| * Shared access to an arbitrary object. This is based on the protect |
| * function of mutex. |
| * @param object to share. |
| * @param timeout in milliseconds to wait for lock. |
| * @return true if shared, false if timeout. |
| */ |
| static bool reader(const void *object, timeout_t timeout = Timer::inf); |
| |
| /** |
| * Release an arbitrary object that has been protected by a rwlock. |
| * @param object to release. |
| */ |
| static void release(const void *object); |
| |
| /** |
| * Release the lock. |
| */ |
| void release(void); |
| }; |
| |
| /** |
| * Class for resource bound memory pools between threads. This is used to |
| * support a memory pool allocation scheme where a pool of reusable objects |
| * may be allocated, and the pool renewed by releasing objects or back. |
| * When the pool is used up, a pool consuming thread then must wait for |
| * a resource to be freed by another consumer (or timeout). This class is |
| * not meant to be used directly, but rather to build the synchronizing |
| * control between consumers which might be forced to wait for a resource. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT ReusableAllocator : protected Conditional |
| { |
| protected: |
| ReusableObject *freelist; |
| unsigned waiting; |
| |
| /** |
| * Initialize reusable allocator through a conditional. Zero free list. |
| */ |
| ReusableAllocator(); |
| |
| /** |
| * Get next reusable object in the pool. |
| * @param object from list. |
| * @return next object. |
| */ |
| inline ReusableObject *next(ReusableObject *object) |
| {return object->getNext();}; |
| |
| /** |
| * Release resuable object |
| * @param object being released. |
| */ |
| void release(ReusableObject *object); |
| }; |
| |
| /** |
| * An optimized and convertable shared lock. This is a form of read/write |
| * lock that has been optimized, particularly for shared access. Support |
| * for scheduling access around writer starvation is also included. The |
| * other benefits over traditional read/write locks is that the code is |
| * a little lighter, and read (shared) locks can be converted to exclusive |
| * (write) locks to perform brief modify operations and then returned to read |
| * locks, rather than having to release and re-aquire locks to change mode. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT ConditionalLock : protected ConditionalAccess, public SharedAccess |
| { |
| protected: |
| class Context : public LinkedObject |
| { |
| public: |
| inline Context(LinkedObject **root) : LinkedObject(root) {}; |
| |
| pthread_t thread; |
| unsigned count; |
| }; |
| |
| LinkedObject *contexts; |
| |
| virtual void _share(void); |
| virtual void _unlock(void); |
| |
| Context *getContext(void); |
| |
| public: |
| /** |
| * Construct conditional lock for default concurrency. |
| */ |
| ConditionalLock(); |
| |
| /** |
| * Destroy conditional lock. |
| */ |
| ~ConditionalLock(); |
| |
| /** |
| * Acquire write (exclusive modify) lock. |
| */ |
| void modify(void); |
| |
| /** |
| * Commit changes / release a modify lock. |
| */ |
| void commit(void); |
| |
| /** |
| * Acquire access (shared read) lock. |
| */ |
| void access(void); |
| |
| /** |
| * Release a shared lock. |
| */ |
| void release(void); |
| |
| /** |
| * Convert read lock into exclusive (write/modify) access. Schedule |
| * when other readers sharing. |
| */ |
| virtual void exclusive(void); |
| |
| /** |
| * Return an exclusive access lock back to share mode. |
| */ |
| virtual void share(void); |
| }; |
| |
| /** |
| * A portable implimentation of "barrier" thread sychronization. A barrier |
| * waits until a specified number of threads have all reached the barrier, |
| * and then releases all the threads together. This implimentation works |
| * regardless of whether the thread library supports barriers since it is |
| * built from conditional. It also differs in that the number of threads |
| * required can be changed dynamically at runtime, unlike pthread barriers |
| * which, when supported, have a fixed limit defined at creation time. Since |
| * we use conditionals, another feature we can add is optional support for a |
| * wait with timeout. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT barrier : private Conditional |
| { |
| private: |
| unsigned count; |
| unsigned waits; |
| |
| public: |
| /** |
| * Construct a barrier with an initial size. |
| * @param count of threads required. |
| */ |
| barrier(unsigned count); |
| |
| /** |
| * Destroy barrier and release pending threads. |
| */ |
| ~barrier(); |
| |
| /** |
| * Dynamically alter the number of threads required. If the size is |
| * set below the currently waiting threads, then the barrier releases. |
| * @param count of threads required. |
| */ |
| void set(unsigned count); |
| |
| /** |
| * Dynamically increment the number of threads required. |
| */ |
| void inc(void); |
| |
| /** |
| * Reduce the number of threads required. |
| */ |
| void dec(void); |
| |
| /** |
| * Alternative prefix form of the same increment operation. |
| * @return the current amount of threads. |
| */ |
| unsigned operator++(void); |
| |
| unsigned operator--(void); |
| |
| /** |
| * Wait at the barrier until the count of threads waiting is reached. |
| */ |
| void wait(void); |
| |
| /** |
| * Wait at the barrier until either the count of threads waiting is |
| * reached or a timeout has occurred. |
| * @param timeout to wait in milliseconds. |
| * @return true if barrier reached, false if timer expired. |
| */ |
| bool wait(timeout_t timeout); |
| }; |
| |
| /** |
| * A portable counting semaphore class. A semaphore will allow threads |
| * to pass through it until the count is reached, and blocks further threads. |
| * Unlike pthread semaphore, our semaphore class supports it's count limit |
| * to be altered during runtime and the use of timed waits. This class also |
| * implements the shared_lock protocol. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT Semaphore : public SharedAccess, protected Conditional |
| { |
| protected: |
| unsigned count, waits, used; |
| |
| virtual void _share(void); |
| virtual void _unlock(void); |
| |
| public: |
| /** |
| * Construct a semaphore with an initial count of threads to permit. |
| */ |
| Semaphore(unsigned count = 0); |
| |
| /** |
| * Wait until the semphore usage count is less than the thread limit. |
| * Increase used count for our thread when unblocked. |
| */ |
| void wait(void); |
| |
| /** |
| * Wait until the semphore usage count is less than the thread limit. |
| * Increase used count for our thread when unblocked, or return without |
| * changing if timed out. |
| * @param timeout to wait in millseconds. |
| * @return true if success, false if timeout. |
| */ |
| bool wait(timeout_t timeout); |
| |
| /** |
| * Alter semaphore limit at runtime |
| * @param count of threads to allow. |
| */ |
| void set(unsigned count); |
| |
| /** |
| * Release the semaphore after waiting for it. |
| */ |
| void release(void); |
| |
| /** |
| * Convenience operator to wait on a counting semaphore. |
| */ |
| inline void operator++(void) |
| {wait();}; |
| |
| /** |
| * Convenience operator to release a counting semaphore. |
| */ |
| inline void operator--(void) |
| {release();}; |
| }; |
| |
| /** |
| * Generic non-recursive exclusive lock class. This class also impliments |
| * the exclusive_lock protocol. In addition, an interface is offered to |
| * support dynamically managed mutexes which are internally pooled. These |
| * can be used to protect and serialize arbitrary access to memory and |
| * objects on demand. This offers an advantage over embedding mutexes to |
| * serialize access to individual objects since the maximum number of |
| * mutexes will never be greater than the number of actually running threads |
| * rather than the number of objects being potentially protected. The |
| * ability to hash the pointer address into an indexed table further optimizes |
| * access by reducing the chance for collisions on the primary index mutex. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT Mutex : public ExclusiveAccess |
| { |
| protected: |
| pthread_mutex_t mlock; |
| |
| virtual void _lock(void); |
| virtual void _unlock(void); |
| |
| public: |
| /** |
| * Guard class to apply scope based mutex locking to objects. The mutex |
| * is located from the mutex pool rather than contained in the target |
| * object, and the lock is released when the guard object falls out of |
| * scope. This is essentially an automation mechanism for mutex::protect. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT guard |
| { |
| private: |
| const void *object; |
| |
| public: |
| /** |
| * Create an unitialized instance of guard. Usually used with a |
| * guard = operator. |
| */ |
| guard(); |
| |
| /** |
| * Construct a guard for a specific object. |
| * @param object to guard. |
| */ |
| guard(const void *object); |
| |
| /** |
| * Release mutex when guard falls out of scope. |
| */ |
| ~guard(); |
| |
| /** |
| * Set guard to mutex lock a new object. If a lock is currently |
| * held, it is released. |
| * @param object to guard. |
| */ |
| void set(const void *object); |
| |
| /** |
| * Prematurely release a guard. |
| */ |
| void release(void); |
| |
| /** |
| * Set guard to mutex lock a new object. If a lock is currently |
| * held, it is released. |
| * @param pointer to object to guard. |
| */ |
| inline void operator=(void *pointer) |
| {set(pointer);}; |
| }; |
| |
| |
| /** |
| * Create a mutex lock. |
| */ |
| Mutex(); |
| |
| /** |
| * Destroy mutex lock, release waiting threads. |
| */ |
| ~Mutex(); |
| |
| /** |
| * Acquire mutex lock. This is a blocking operation. |
| */ |
| inline void acquire(void) |
| {pthread_mutex_lock(&mlock);}; |
| |
| /** |
| * Acquire mutex lock. This is a blocking operation. |
| */ |
| inline void lock(void) |
| {pthread_mutex_lock(&mlock);}; |
| |
| /** |
| * Release acquired lock. |
| */ |
| inline void unlock(void) |
| {pthread_mutex_unlock(&mlock);}; |
| |
| /** |
| * Release acquired lock. |
| */ |
| inline void release(void) |
| {pthread_mutex_unlock(&mlock);}; |
| |
| /** |
| * Convenience function to acquire os native mutex lock directly. |
| * @param lock to acquire. |
| */ |
| inline static void acquire(pthread_mutex_t *lock) |
| {pthread_mutex_lock(lock);}; |
| |
| /** |
| * Convenience function to release os native mutex lock directly. |
| * @param lock to release. |
| */ |
| inline static void release(pthread_mutex_t *lock) |
| {pthread_mutex_unlock(lock);}; |
| |
| /** |
| * Specify hash table size for guard protection. The default is 1. |
| * This should be called at initialization time from the main thread |
| * of the application before any other threads are created. |
| * @param size of hash table used for guarding. |
| */ |
| static void indexing(unsigned size); |
| |
| /** |
| * Specify pointer/object/resource to guard protect. This uses a |
| * dynamically managed mutex. |
| * @param pointer to protect. |
| */ |
| static void protect(const void *pointer); |
| |
| /** |
| * Specify a pointer/object/resource to release. |
| * @param pointer to release. |
| */ |
| static void release(const void *pointer); |
| }; |
| |
| /** |
| * A mutex locked object smart pointer helper class. This is particularly |
| * useful in referencing objects which will be protected by the mutex |
| * protect function. When the pointer falls out of scope, the protecting |
| * mutex is also released. This is meant to be used by the typed |
| * mutex_pointer template. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT auto_protect |
| { |
| private: |
| // cannot copy... |
| inline auto_protect(const auto_object &pointer) {}; |
| |
| protected: |
| const void *object; |
| |
| auto_protect(); |
| |
| public: |
| /** |
| * Construct a protected pointer referencing an existing object. |
| * @param object we point to. |
| */ |
| auto_protect(const void *object); |
| |
| /** |
| * Delete protected pointer. When it falls out of scope the associated |
| * mutex is released. |
| */ |
| ~auto_protect(); |
| |
| /** |
| * Manually release the pointer. This releases the mutex. |
| */ |
| void release(void); |
| |
| /** |
| * Test if the pointer is not set. |
| * @return true if the pointer is not referencing anything. |
| */ |
| inline bool operator!() const |
| {return object == NULL;}; |
| |
| /** |
| * Test if the pointer is referencing an object. |
| * @return true if the pointer is currently referencing an object. |
| */ |
| inline operator bool() const |
| {return object != NULL;}; |
| |
| /** |
| * Set our pointer to a specific object. If the pointer currently |
| * references another object, the associated mutex is released. The |
| * pointer references our new object and that new object is locked. |
| * @param object to assign to. |
| */ |
| void operator=(const void *object); |
| }; |
| |
| /** |
| * An object pointer that uses mutex to assure thread-safe singleton use. |
| * This class is used to support a threadsafe replacable pointer to a object. |
| * This class is used to form and support the templated locked_pointer class |
| * and used with the locked_release class. An example of where this might be |
| * used is in config file parsers, where a seperate thread may process and |
| * generate a new config object for new threads to refernce, while the old |
| * configuration continues to be used by a reference counted instance that |
| * goes away when it falls out of scope. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT LockedPointer |
| { |
| private: |
| friend class locked_release; |
| pthread_mutex_t mutex; |
| ObjectProtocol *pointer; |
| |
| protected: |
| /** |
| * Create an instance of a locked pointer. |
| */ |
| LockedPointer(); |
| |
| /** |
| * Replace existing object with a new one for next request. |
| * @param object to register with pointer. |
| */ |
| void replace(ObjectProtocol *object); |
| |
| /** |
| * Create a duplicate reference counted instance of the current object. |
| * @return duplicate reference counted object. |
| */ |
| ObjectProtocol *dup(void); |
| |
| /** |
| * Replace existing object through assignment. |
| * @param object to assign. |
| */ |
| inline void operator=(ObjectProtocol *object) |
| {replace(object);}; |
| }; |
| |
| /** |
| * Shared singleton object. A shared singleton object is a special kind of |
| * object that may be shared by multiple threads but which only one active |
| * instance is allowed to exist. The shared object is managed by the |
| * templated shared pointer class, and is meant to be inherited as a base |
| * class for the derived shared singleton type. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT SharedObject |
| { |
| protected: |
| friend class SharedPointer; |
| |
| /** |
| * Commit is called when a shared singleton is accepted and replaces |
| * a prior instance managed by a shared pointer. Commit occurs |
| * when replace is called on the shared pointer, and is assured to |
| * happen only when no threads are accessing either the current |
| * or the prior instance that was previously protected by the pointer. |
| * @param pointer that now holds the object. |
| */ |
| virtual void commit(SharedPointer *pointer); |
| |
| public: |
| /** |
| * Allows inherited virtual. |
| */ |
| virtual ~SharedObject(); |
| }; |
| |
| /** |
| * The shared pointer is used to manage a singleton instance of shared object. |
| * This class is used to support the templated shared_pointer class and the |
| * shared_release class, and is not meant to be used directly or as a base |
| * for anything else. One or more threads may aquire a shared lock to the |
| * singleton object through this pointer, and it can only be replaced with a |
| * new singleton instance when no threads reference it. The conditional lock |
| * is used to manage shared access for use and exclusive access when modified. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT SharedPointer : protected ConditionalAccess |
| { |
| private: |
| friend class shared_release; |
| SharedObject *pointer; |
| |
| protected: |
| /** |
| * Created shared locking for pointer. Must be assigned by replace. |
| */ |
| SharedPointer(); |
| |
| /** |
| * Destroy lock and release any blocked threads. |
| */ |
| ~SharedPointer(); |
| |
| /** |
| * Replace existing singleton instance with new one. This happens |
| * during exclusive locking, and the commit method of the object |
| * will be called. |
| * @param object being set. |
| */ |
| void replace(SharedObject *object); |
| |
| /** |
| * Acquire a shared reference to the singleton object. This is a |
| * form of shared access lock. Derived classes and templates access |
| * "release" when the shared pointer is no longer needed. |
| * @return shared object. |
| */ |
| SharedObject *share(void); |
| }; |
| |
| /** |
| * An abstract class for defining classes that operate as a thread. A derived |
| * thread class has a run method that is invoked with the newly created |
| * thread context, and can use the derived object to store all member data |
| * that needs to be associated with that context. This means the derived |
| * object can safely hold thread-specific data that is managed with the life |
| * of the object, rather than having to use the clumsy thread-specific data |
| * management and access functions found in thread support libraries. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT Thread |
| { |
| protected: |
| // may be used in future if we need cancelable threads... |
| #ifdef _MSWINDOWS_ |
| HANDLE cancellor; |
| #else |
| void *cancellor; |
| #endif |
| |
| enum {} reserved; // cancel mode? |
| pthread_t tid; |
| size_t stack; |
| int priority; |
| |
| /** |
| * Create a thread object that will have a preset stack size. If 0 |
| * is used, then the stack size is os defined/default. |
| * @param stack size to use or 0 for default. |
| */ |
| Thread(size_t stack = 0); |
| |
| /** |
| * Map thread for get method. This should be called from start of the |
| * run() method of a derived class. |
| */ |
| void map(void); |
| |
| /** |
| * Check if running. |
| */ |
| virtual bool is_active(void); |
| |
| public: |
| /** |
| * Set thread priority without disrupting scheduling if possible. |
| * Based on scheduling policy. It is recommended that the process |
| * is set for realtime scheduling, and this method is actually for |
| * internal use. |
| */ |
| void setPriority(void); |
| |
| /** |
| * Yield execution context of the current thread. This is a static |
| * and may be used anywhere. |
| */ |
| static void yield(void); |
| |
| /** |
| * Sleep current thread for a specified time period. |
| * @param timeout to sleep for in milliseconds. |
| */ |
| static void sleep(timeout_t timeout); |
| |
| /** |
| * Get mapped thread object. This returns the mapped base class of the |
| * thread object of the current executing context. You will need to |
| * cast to the correct derived class to access derived thread-specific |
| * storage. If the current thread context is not mapped NULL is returned. |
| */ |
| static Thread *get(void); |
| |
| /** |
| * Abstract interface for thread context run method. |
| */ |
| virtual void run(void) = 0; |
| |
| /** |
| * Destroy thread object, thread-specific data, and execution context. |
| */ |
| virtual ~Thread(); |
| |
| /** |
| * Exit the thread context. This function should NO LONGER be called |
| * directly to exit a running thread. Instead this method will only be |
| * used to modify the behavior of the thread context at thread exit, |
| * including detached threads which by default delete themselves. This |
| * documented usage was changed to support Mozilla NSPR exit behavior |
| * in case we support NSPR as an alternate thread runtime in the future. |
| */ |
| virtual void exit(void); |
| |
| /** |
| * Used to initialize threading library. May be needed for some platforms. |
| */ |
| static void init(void); |
| |
| /** |
| * Used to specify scheduling policy for threads above priority "0". |
| * Normally we apply static realtime policy SCHED_FIFO (default) or |
| * SCHED_RR. However, we could apply SCHED_OTHER, etc. |
| */ |
| static void policy(int polid); |
| |
| /** |
| * Set concurrency level of process. This is essentially a portable |
| * wrapper for pthread_setconcurrency. |
| */ |
| static void concurrency(int level); |
| |
| /** |
| * Determine if two thread identifiers refer to the same thread. |
| * @param thread1 to test. |
| * @param thread2 to test. |
| * @return true if both are the same context. |
| */ |
| static bool equal(pthread_t thread1, pthread_t thread2); |
| |
| /** |
| * Get current thread id. |
| * @return thread id. |
| */ |
| static pthread_t self(void); |
| |
| inline operator bool() |
| {return is_active();} |
| |
| inline bool operator!() |
| {return !is_active();} |
| |
| inline bool isRunning(void) |
| {return is_active();} |
| }; |
| |
| /** |
| * A child thread object that may be joined by parent. A child thread is |
| * a type of thread in which the parent thread (or process main thread) can |
| * then wait for the child thread to complete and then delete the child object. |
| * The parent thread can wait for the child thread to complete either by |
| * calling join, or performing a "delete" of the derived child object. In |
| * either case the parent thread will suspend execution until the child thread |
| * exits. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT JoinableThread : public Thread |
| { |
| protected: |
| #ifdef _MSWINDOWS_ |
| HANDLE running; |
| #else |
| volatile bool running; |
| #endif |
| volatile bool joining; |
| |
| /** |
| * Create a joinable thread with a known context stack size. |
| * @param size of stack for thread context or 0 for default. |
| */ |
| JoinableThread(size_t size = 0); |
| |
| /** |
| * Delete child thread. Parent thread suspends until child thread |
| * run method completes or child thread calls it's exit method. |
| */ |
| virtual ~JoinableThread(); |
| |
| /** |
| * Join thread with parent. Calling from a child thread to exit is |
| * now depreciated behavior and in the future will not be supported. |
| * Threads should always return through their run() method. |
| */ |
| void join(void); |
| |
| bool is_active(void); |
| |
| virtual void run(void) = 0; |
| |
| public: |
| |
| /** |
| * Start execution of child context. This must be called after the |
| * child object is created (perhaps with "new") and before it can be |
| * joined. This method actually begins the new thread context, which |
| * then calls the object's run method. Optionally raise the priority |
| * of the thread when it starts under realtime priority. |
| * @param priority of child thread. |
| */ |
| void start(int priority = 0); |
| |
| /** |
| * Start execution of child context as background thread. This is |
| * assumed to be off main thread, with a priority lowered by one. |
| */ |
| inline void background(void) |
| {start(-1);}; |
| }; |
| |
| /** |
| * A detached thread object that is stand-alone. This object has no |
| * relationship with any other running thread instance will be automatically |
| * deleted when the running thread instance exits, either by it's run method |
| * exiting, or explicity calling the exit member function. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT DetachedThread : public Thread |
| { |
| protected: |
| bool active; |
| |
| /** |
| * Create a detached thread with a known context stack size. |
| * @param size of stack for thread context or 0 for default. |
| */ |
| DetachedThread(size_t size = 0); |
| |
| /** |
| * Destroys object when thread context exits. Never externally |
| * deleted. Derived object may also have destructor to clean up |
| * thread-specific member data. |
| */ |
| ~DetachedThread(); |
| |
| /** |
| * Exit context of detached thread. Thread object will be deleted. |
| * This function should NO LONGER be called directly to exit a running |
| * thread. Instead, the thread should only "return" through the run() |
| * method to exit. The documented usage was changed so that exit() can |
| * still be used to modify the "delete this" behavior of detached threads |
| * while merging thread exit behavior with Mozilla NSPR. |
| */ |
| void exit(void); |
| |
| bool is_active(void); |
| |
| virtual void run(void) = 0; |
| |
| public: |
| /** |
| * Start execution of detached context. This must be called after the |
| * object is created (perhaps with "new"). This method actually begins |
| * the new thread context, which then calls the object's run method. |
| * @param priority to start thread with. |
| */ |
| void start(int priority = 0); |
| }; |
| |
| /** |
| * Auto-pointer support class for locked objects. This is used as a base |
| * class for the templated locked_instance class that uses the managed |
| * LockedPointer to assign a reference to an object. When the locked |
| * instance falls out of scope, the object is derefenced. Ideally the |
| * pointer typed object should be based on the reference counted object class. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| class __EXPORT locked_release |
| { |
| protected: |
| ObjectProtocol *object; /**< locked object protected by locked_release */ |
| |
| /** |
| * Create an unassigned locked object pointer base. |
| */ |
| locked_release(); |
| |
| /** |
| * Construct a locked object instance base from an existing instance. This |
| * will create a duplicate (retained) reference. |
| * @param object to copy from. |
| */ |
| locked_release(const locked_release &object); |
| |
| public: |
| /** |
| * Construct a locked object instance base from a LockedPointer. References |
| * a retained instance of the underlying object from the LockedPointer. |
| * @param pointer of locked pointer to assign from. |
| */ |
| locked_release(LockedPointer &pointer); |
| |
| /** |
| * Auto-release pointer to locked object instance. This is used to release |
| * a reference when the pointer template falls out of scope. |
| */ |
| ~locked_release(); |
| |
| /** |
| * Manually release the object reference. |
| */ |
| void release(void); |
| |
| /** |
| * Assign a locked object pointer. If an existing object is already |
| * assigned, the existing pointer is released. |
| * @param pointer reference through locked object. |
| */ |
| locked_release &operator=(LockedPointer &pointer); |
| }; |
| |
| /** |
| * Auto-pointer support class for shared singleton objects. This is used as |
| * a base class for the templated shared_instance class that uses shared |
| * access locking through the SharedPointer class. When the shared instance |
| * falls out of scope, the SharedPointer lock is released. The pointer |
| * typed object must be based on the SharedObject class. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| |
| class __EXPORT shared_release |
| { |
| protected: |
| SharedPointer *ptr; /**< Shared lock for protected singleton */ |
| |
| /** |
| * Create an unassigned shared singleton object pointer base. |
| */ |
| shared_release(); |
| |
| /** |
| * Construct a shared object instance base from an existing instance. This |
| * will assign an additional shared lock. |
| * @param object to copy from. |
| */ |
| shared_release(const shared_release &object); |
| |
| public: |
| /** |
| * Access lock a shared singleton instance from a SharedPointer. |
| * @param pointer of shared pointer to assign from. |
| */ |
| shared_release(SharedPointer &pointer); |
| |
| /** |
| * Auto-unlock shared lock for singleton instance protected by shared |
| * pointer. This is used to unlock when the instance template falls out |
| * of scope. |
| */ |
| ~shared_release(); |
| |
| /** |
| * Manually release access to shared singleton object. |
| */ |
| void release(void); |
| |
| /** |
| * Get pointer to singleton object that we have shared lock for. |
| * @return shared object singleton. |
| */ |
| SharedObject *get(void); |
| |
| /** |
| * Assign shared lock access to shared singleton. If an existing |
| * shared lock is held for another pointer, it is released. |
| * @param pointer access for shared object. |
| */ |
| shared_release &operator=(SharedPointer &pointer); |
| }; |
| |
| /** |
| * Templated shared pointer for singleton shared objects of specific type. |
| * This is used as typed template for the SharedPointer object reference |
| * management class. This is used to supply a typed singleton shared |
| * instance to the typed shared_instance template class. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| template<class T> |
| class shared_pointer : public SharedPointer |
| { |
| public: |
| /** |
| * Created shared locking for typed singleton pointer. |
| */ |
| inline shared_pointer() : SharedPointer() {}; |
| |
| /** |
| * Acquire a shared (duplocate) reference to the typed singleton object. |
| * This is a form of shared access lock. Derived classes and templates |
| * access conditionallock "release" when the shared pointer is no longer |
| * needed. |
| * @return typed shared object. |
| */ |
| inline const T *dup(void) |
| {return static_cast<const T*>(SharedPointer::share());}; |
| |
| /** |
| * Replace existing typed singleton instance with new one. This happens |
| * during exclusive locking, and the commit method of the typed object |
| * will be called. |
| * @param object being set. |
| */ |
| inline void replace(T *object) |
| {SharedPointer::replace(object);}; |
| |
| /** |
| * Replace existing typed singleton object through assignment. |
| * @param object to assign. |
| */ |
| inline void operator=(T *object) |
| {replace(object);}; |
| |
| /** |
| * Access shared lock typed singleton object by pointer reference. |
| * @return typed shared object. |
| */ |
| inline T *operator*() |
| {return dup();}; |
| }; |
| |
| /** |
| * Templated locked pointer for referencing locked objects of specific type. |
| * This is used as typed template for the LockedPointer object reference |
| * management class. This is used to supply a typed locked instances |
| * to the typed locked_instance template class. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| template<class T> |
| class locked_pointer : public LockedPointer |
| { |
| public: |
| /** |
| * Create an instance of a typed locked pointer. |
| */ |
| inline locked_pointer() : LockedPointer() {}; |
| |
| /** |
| * Create a duplicate reference counted instance of the current typed |
| * object. |
| * @return duplicate reference counted typed object. |
| */ |
| inline T* dup(void) |
| {return static_cast<T *>(LockedPointer::dup());}; |
| |
| /** |
| * Replace existing typed object with a new one for next request. |
| * @param object to register with pointer. |
| */ |
| inline void replace(T *object) |
| {LockedPointer::replace(object);}; |
| |
| /** |
| * Replace existing object through assignment. |
| * @param object to assign. |
| */ |
| inline void operator=(T *object) |
| {replace(object);}; |
| |
| /** |
| * Create a duplicate reference counted instance of the current typed |
| * object by pointer reference. |
| * @return duplicate reference counted typed object. |
| */ |
| inline T *operator*() |
| {return dup();}; |
| }; |
| |
| /** |
| * A templated smart pointer instance for lock protected objects. |
| * This is used to reference an instance of a typed locked_pointer. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| template<class T> |
| class locked_instance : public locked_release |
| { |
| public: |
| /** |
| * Construct empty locked instance of typed object. |
| */ |
| inline locked_instance() : locked_release() {}; |
| |
| /** |
| * Construct locked instance of typed object from matching locked_pointer. |
| * @param pointer to get instance from. |
| */ |
| inline locked_instance(locked_pointer<T> &pointer) : locked_release(pointer) {}; |
| |
| /** |
| * Extract instance of locked typed object by pointer reference. |
| * @return instance of typed object. |
| */ |
| inline T& operator*() const |
| {return *(static_cast<T&>(object));}; |
| |
| /** |
| * Access member of instance of locked typed object by member reference. |
| * @return instance of typed object. |
| */ |
| inline T* operator->() const |
| {return static_cast<T*>(object);}; |
| |
| /** |
| * Get pointer to instance of locked typed object. |
| * @return instance of typed object. |
| */ |
| inline T* get(void) const |
| {return static_cast<T*>(object);}; |
| }; |
| |
| /** |
| * A templated smart pointer instance for shared singleton typed objects. |
| * This is used to access the shared lock instance of the singleton. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| template<class T> |
| class shared_instance : public shared_release |
| { |
| public: |
| /** |
| * Construct empty instance to reference shared typed singleton. |
| */ |
| inline shared_instance() : shared_release() {}; |
| |
| /** |
| * Construct shared access instance of shared typed singleton from matching |
| * shared_pointer. |
| * @param pointer to get instance from. |
| */ |
| inline shared_instance(shared_pointer<T> &pointer) : shared_release(pointer) {}; |
| |
| /** |
| * Access shared typed singleton object this instance locks and references. |
| */ |
| inline const T& operator*() const |
| {return *(static_cast<const T&>(ptr->pointer));}; |
| |
| /** |
| * Access member of shared typed singleton object this instance locks and |
| * references. |
| */ |
| inline const T* operator->() const |
| {return static_cast<const T*>(ptr->pointer);}; |
| |
| /** |
| * Access pointer to typed singleton object this instance locks and |
| * references. |
| */ |
| inline const T* get(void) const |
| {return static_cast<const T*>(ptr->pointer);}; |
| }; |
| |
| /** |
| * Typed smart locked pointer class. This is used to manage references to |
| * objects which are protected by an auto-generated mutex. The mutex is |
| * released when the pointer falls out of scope. |
| * @author David Sugar <dyfet@gnutelephony.org> |
| */ |
| template <class T> |
| class mutex_pointer : public auto_protect |
| { |
| public: |
| /** |
| * Create a pointer with no reference. |
| */ |
| inline mutex_pointer() : auto_protect() {}; |
| |
| /** |
| * Create a pointer with a reference to a heap object. |
| * @param object we are referencing. |
| */ |
| inline mutex_pointer(T* object) : auto_protect(object) {}; |
| |
| /** |
| * Reference object we are pointing to through pointer indirection. |
| * @return object we are pointing to. |
| */ |
| inline T& operator*() const |
| {return *(static_cast<T&>(auto_protect::object));}; |
| |
| /** |
| * Reference member of object we are pointing to. |
| * @return reference to member of pointed object. |
| */ |
| inline T* operator->() const |
| {return static_cast<T*>(auto_protect::object);}; |
| |
| /** |
| * Get pointer to object. |
| * @return pointer or NULL if we are not referencing an object. |
| */ |
| inline T* get(void) const |
| {return static_cast<T*>(auto_protect::object);}; |
| }; |
| |
| /** |
| * Convenience function to start a joinable thread. |
| * @param thread to start. |
| * @param priority of thread. |
| */ |
| inline void start(JoinableThread *thread, int priority = 0) |
| {thread->start(priority);} |
| |
| /** |
| * Convenience function to start a detached thread. |
| * @param thread to start. |
| * @param priority of thread. |
| */ |
| inline void start(DetachedThread *thread, int priority = 0) |
| {thread->start(priority);} |
| |
| /** |
| * Convenience type for using conditional locks. |
| */ |
| typedef ConditionalLock condlock_t; |
| |
| /** |
| * Convenience type for scheduling access. |
| */ |
| typedef ConditionalAccess accesslock_t; |
| |
| /** |
| * Convenience type for using timed events. |
| */ |
| typedef TimedEvent timedevent_t; |
| |
| /** |
| * Convenience type for using exclusive mutex locks. |
| */ |
| typedef Mutex mutex_t; |
| |
| /** |
| * Convenience type for using read/write locks. |
| */ |
| typedef ThreadLock rwlock_t; |
| |
| /** |
| * Convenience type for using recursive exclusive locks. |
| */ |
| typedef RecursiveMutex rexlock_t; |
| |
| /** |
| * Convenience type for using counting semaphores. |
| */ |
| typedef Semaphore semaphore_t; |
| |
| /** |
| * Convenience type for using thread barriers. |
| */ |
| typedef barrier barrier_t; |
| |
| /** |
| * Convenience function to wait on a barrier. |
| * @param barrier to wait. |
| */ |
| inline void wait(barrier_t &barrier) |
| {barrier.wait();} |
| |
| /** |
| * Convenience function to wait on a semaphore. |
| * @param semaphore to wait on. |
| * @param timeout to wait for. |
| */ |
| inline void wait(semaphore_t &semaphore, timeout_t timeout = Timer::inf) |
| {semaphore.wait(timeout);} |
| |
| /** |
| * Convenience function to release a semaphore. |
| * @param semaphore to release. |
| */ |
| inline void release(semaphore_t &semaphore) |
| {semaphore.release();} |
| |
| /** |
| * Convenience function to acquire a mutex. |
| * @param mutex to acquire. |
| */ |
| inline void acquire(mutex_t &mutex) |
| {mutex.lock();} |
| |
| /** |
| * Convenience function to release a mutex. |
| * @param mutex to release. |
| */ |
| inline void release(mutex_t &mutex) |
| {mutex.release();} |
| |
| /** |
| * Convenience function to exclusively schedule conditional access. |
| * @param lock to make exclusive. |
| */ |
| inline void modify(accesslock_t &lock) |
| {lock.modify();} |
| |
| /** |
| * Convenience function to shared read schedule conditional access. |
| * @param lock to access shared. |
| */ |
| inline void access(accesslock_t &lock) |
| {lock.access();} |
| |
| /** |
| * Convenience function to release an access lock. |
| * @param lock to release. |
| */ |
| inline void release(accesslock_t &lock) |
| {lock.release();} |
| |
| /** |
| * Convenience function to commit an exclusive access lock. |
| * lock. |
| * @param lock to commit. |
| */ |
| inline void commit(accesslock_t &lock) |
| {lock.commit();} |
| |
| /** |
| * Convenience function to exclusively lock shared conditional lock. |
| * @param lock to make exclusive. |
| */ |
| inline void exclusive(condlock_t &lock) |
| {lock.exclusive();} |
| |
| /** |
| * Convenience function to restore shared access on a conditional lock. |
| * @param lock to make shared. |
| */ |
| inline void share(condlock_t &lock) |
| {lock.share();} |
| |
| /** |
| * Convenience function to exclusively aquire a conditional lock. |
| * @param lock to acquire for modify. |
| */ |
| inline void modify(condlock_t &lock) |
| {lock.modify();} |
| |
| /** |
| * Convenience function to commit and release an exclusively locked conditional |
| * lock. |
| * @param lock to commit. |
| */ |
| inline void commit(condlock_t &lock) |
| {lock.commit();} |
| |
| /** |
| * Convenience function for shared access to a conditional lock. |
| * @param lock to access. |
| */ |
| inline void access(condlock_t &lock) |
| {lock.access();} |
| |
| /** |
| * Convenience function to release shared access to a conditional lock. |
| * @param lock to release. |
| */ |
| inline void release(condlock_t &lock) |
| {lock.release();} |
| |
| /** |
| * Convenience function for exclusive write access to a read/write lock. |
| * @param lock to write lock. |
| * @param timeout to wait for exclusive locking. |
| */ |
| inline bool exclusive(rwlock_t &lock, timeout_t timeout = Timer::inf) |
| {return lock.modify(timeout);} |
| |
| /** |
| * Convenience function for shared read access to a read/write lock. |
| * @param lock to share read lock. |
| * @param timeout to wait for shared access. |
| */ |
| inline bool share(rwlock_t &lock, timeout_t timeout = Timer::inf) |
| {return lock.access(timeout);} |
| |
| /** |
| * Convenience function to release a shared lock. |
| * @param lock to release. |
| */ |
| inline void release(rwlock_t &lock) |
| {lock.release();} |
| |
| /** |
| * Convenience function to lock a shared recursive mutex lock. |
| * @param lock to acquire. |
| */ |
| inline void lock(rexlock_t &lock) |
| {lock.lock();} |
| |
| /** |
| * Convenience function to release a shared recursive mutex lock. |
| * @param lock to release. |
| */ |
| inline void release(rexlock_t &lock) |
| {lock.release();} |
| |
| inline bool _sync_protect_(const void *obj) |
| { |
| Mutex::protect(obj); |
| return true; |
| } |
| |
| inline bool _sync_release_(const void *obj) |
| { |
| Mutex::release(obj); |
| return false; |
| } |
| |
| inline bool _rw_reader_(const void *obj) |
| { |
| ThreadLock::reader(obj); |
| return true; |
| } |
| |
| inline bool _rw_writer_(const void *obj) |
| { |
| ThreadLock::writer(obj); |
| return true; |
| } |
| |
| inline bool _rw_release_(const void *obj) |
| { |
| ThreadLock::release(obj); |
| return false; |
| } |
| |
| #define ENTER_EXCLUSIVE \ |
| do { static pthread_mutex_t __sync__ = PTHREAD_MUTEX_INITIALIZER; \ |
| pthread_mutex_lock(&__sync__); |
| |
| #define LEAVE_EXCLUSIVE \ |
| pthread_mutex_unlock(&__sync__);} while(0); |
| |
| #define SYNC(obj) for(bool _sync_flag_ = _sync_protect_(obj); _sync_flag_; _sync_flag_ = _sync_release_(obj)) |
| |
| #define SHARED(obj) for(bool _sync_flag_ = _rw_reader_(obj); _sync_flag_; _sync_flag_ = _rw_release_(obj)) |
| |
| #define EXCLUSIVE(obj) for(bool _sync_flag_ = _rw_writer_(obj); _sync_flag_; _sync_flag_ = _rw_release_(obj)) |
| |
| END_NAMESPACE |
| |
| #endif |