Merge commit 'origin/master' into 310

This commit is contained in:
tomrus88 2009-05-11 15:11:02 +04:00
commit c86290fa50
183 changed files with 689 additions and 21043 deletions

View file

@ -29,8 +29,7 @@ EXTRA_DIST = \
win/VC71/realmd.vcproj \
win/VC71/shared.vcproj \
win/VC71/zlib.vcproj \
win/VC71/g3dlite.vcproj \
win/VC71/zthread.vcproj
win/VC71/g3dlite.vcproj
# Win32 project workspace for Visual Studio .NET 2005
EXTRA_DIST += \
@ -41,8 +40,7 @@ EXTRA_DIST += \
win/VC80/realmd.vcproj \
win/VC80/shared.vcproj \
win/VC80/zlib.vcproj \
win/VC80/g3dlite.vcproj \
win/VC80/zthread.vcproj
win/VC80/g3dlite.vcproj
# Win32 project workspace for Visual Studio .NET 2008
EXTRA_DIST += \
@ -53,6 +51,5 @@ EXTRA_DIST += \
win/VC90/realmd.vcproj \
win/VC90/shared.vcproj \
win/VC90/zlib.vcproj \
win/VC90/g3dlite.vcproj \
win/VC90/zthread.vcproj
win/VC90/g3dlite.vcproj

View file

@ -288,7 +288,6 @@ AC_CONFIG_FILES([
dep/src/g3dlite/Makefile
dep/src/sockets/Makefile
dep/src/zlib/Makefile
dep/src/zthread/Makefile
dep/Makefile
doc/Doxyfile
doc/Makefile

View file

@ -197,54 +197,6 @@ EXTRA_DIST += \
zlib/zconf.h \
zlib/zlib.h
# ZThread header files for Win32 builds
EXTRA_DIST += \
zthread/AtomicCount.h \
zthread/Barrier.h \
zthread/BiasedReadWriteLock.h \
zthread/BlockingQueue.h \
zthread/BoundedQueue.h \
zthread/Cancelable.h \
zthread/ClassLockable.h \
zthread/ConcurrentExecutor.h \
zthread/Condition.h \
zthread/Config.h \
zthread/CountedPtr.h \
zthread/CountingSemaphore.h \
zthread/Exceptions.h \
zthread/Executor.h \
zthread/FairReadWriteLock.h \
zthread/FastMutex.h \
zthread/FastRecursiveMutex.h \
zthread/Guard.h \
zthread/GuardedClass.h \
zthread/Lockable.h \
zthread/LockedQueue.h \
zthread/MonitoredQueue.h \
zthread/Mutex.h \
zthread/NonCopyable.h \
zthread/PoolExecutor.h \
zthread/Priority.h \
zthread/PriorityCondition.h \
zthread/PriorityInheritanceMutex.h \
zthread/PriorityMutex.h \
zthread/PrioritySemaphore.h \
zthread/Queue.h \
zthread/ReadWriteLock.h \
zthread/RecursiveMutex.h \
zthread/Runnable.h \
zthread/Semaphore.h \
zthread/Singleton.h \
zthread/SynchronousExecutor.h \
zthread/Task.h \
zthread/Thread.h \
zthread/ThreadLocal.h \
zthread/ThreadLocalImpl.h \
zthread/ThreadedExecutor.h \
zthread/Time.h \
zthread/Waitable.h \
zthread/ZThread.h
# Mersenne Twister random number generator header files
EXTRA_DIST += \
mersennetwister/MersenneTwister.h

View file

@ -1,74 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTATOMICCOUNT_H__
#define __ZTATOMICCOUNT_H__
#include <cstdlib>
#include "zthread/Config.h"
#include "zthread/NonCopyable.h"
namespace ZThread {
/**
* @class AtomicCount
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T09:41:55-0400>
* @version 2.3.0
*
* This class provides an interface to a small integer whose value can be
* incremented or decremented atomically. It's designed to be as simple and
* lightweight as possible so that it can be used cheaply to create reference
* counts.
*/
class ZTHREAD_API AtomicCount : public NonCopyable {
void* _value;
public:
//! Create a new AtomicCount, initialized to a value of 1
AtomicCount();
//! Destroy a new AtomicCount
~AtomicCount();
//! Postfix decrement and return the current value
size_t operator--(int);
//! Postfix increment and return the current value
size_t operator++(int);
//! Prefix decrement and return the current value
size_t operator--();
//! Prefix increment and return the current value
size_t operator++();
}; /* AtomicCount */
} // namespace ZThread
#endif // __ZTATOMICCOUNT_H__

View file

@ -1,328 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTBARRIER_H__
#define __ZTBARRIER_H__
#include "zthread/Condition.h"
#include "zthread/Guard.h"
#include "zthread/Waitable.h"
#include "zthread/Runnable.h"
namespace ZThread {
/**
* @class Barrier
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T09:54:01-0400>
* @version 2.2.1
*
* A Barrier is a Waitable object that serves as synchronization points for
* a set of threads. A Barrier is constructed for a fixed number (<i>N</i>) of threads.
* Threads attempting to wait() on a Barrier (<i> 1 - N</i>) will block until the <i>N</i>th
* thread arrives. The <i>N</i>th thread will awaken all the the others.
*
* An optional Runnable command may be associated with the Barrier. This will be run()
* when the <i>N</i>th thread arrives and Barrier is not broken.
*
* <b>Error Checking</b>
*
* A Barrier uses an all-or-nothing. All threads involved must successfully
* meet at Barrier. If any one of those threads leaves before all the threads
* have (as the result of an error or exception) then all threads present at
* the Barrier will throw BrokenBarrier_Exception.
*
* A broken Barrier will cause all threads attempting to wait() on it to
* throw a BrokenBarrier_Exception.
*
* A Barrier will remain 'broken', until it is manually reset().
*/
template <unsigned int Count, class LockType>
class Barrier : public Waitable, private NonCopyable {
//! Broken flag
bool _broken;
//! Task flag
bool _haveTask;
//! Thread count
unsigned int _count;
//! Wait generation
unsigned int _generation;
//! Serialize access
LockType _lock;
//! Signaled when all thread arrive
Condition _arrived;
//! Command to run when all the thread arrive
Task _task;
public:
//! Create a Barrier
Barrier()
: _broken(false), _haveTask(false), _count(Count), _generation(0), _arrived(_lock), _task(0) { }
/**
* Create a Barrier that executes the given task when all threads arrive
* without error
*
* @param task Task to associate with this Barrier
*/
Barrier(const Task& task)
: _broken(false), _haveTask(true), _count(Count), _generation(0), _arrived(_lock),
_task(task) { }
//! Destroy this Barrier
virtual ~Barrier() {}
/**
* Enter barrier and wait for the other threads to arrive. This can block for an indefinite
* amount of time.
*
* @exception BrokenBarrier_Exception thrown when any thread has left a wait on this
* Barrier as a result of an error.
* @exception Interrupted_Exception thrown when the calling thread is interrupted.
* A thread may be interrupted at any time, prematurely ending a wait
* for one thread and breaking the barrier for all threads
*
* @see Waitable::wait()
*
* @post If no exception was thrown, all threads have successfully arrived
* @post If an exception was thrown, the barrier is broken
*/
virtual void wait() {
Guard<LockType> g(_lock);
if(_broken)
throw BrokenBarrier_Exception();
// Break the barrier if an arriving thread is interrupted
if(Thread::interrupted()) {
// Release the other waiter, propagate the exception
_arrived.broadcast();
_broken = true;
throw Interrupted_Exception();
}
if(--_count == 0) {
// Wake the other threads if this was the last
// arriving thread
_arrived.broadcast();
// Try to run the associated task, if it throws then
// break the barrier and propagate the exception
try {
if(_task)
_task->run();
_generation++;
} catch(Synchronization_Exception&) {
_broken = true;
throw;
} catch(...) { assert(0); }
} else {
int myGeneration = _generation;
try {
// Wait for the other threads to arrive
_arrived.wait();
} catch(Interrupted_Exception&) {
// Its possible for a thread to be interrupted before the
// last thread arrives. If the interrupted thread hasn't
// resumed, then just propagate the interruption
if(myGeneration != _generation)
Thread().interrupt();
else _broken = true;
} catch(Synchronization_Exception&) {
// Break the barrier and propagate the exception
_broken = true;
throw;
}
// If the thread woke because it was notified by the thread
// that broke the barrier, throw.
if(_broken)
throw BrokenBarrier_Exception();
}
}
/**
* Enter barrier and wait for the other threads to arrive. This can block up to the
* amount of time specified with the timeout parameter. The barrier will not break
* if a thread leaves this function due to a timeout.
*
* @param timeout maximum amount of time, in milliseconds, to wait before
*
* @return
* - <em>true</em> if the set of tasks being wait for complete before
* <i>timeout</i> milliseconds elapse.
* - <em>false</em> otherwise.
*
* @exception BrokenBarrier_Exception thrown when any thread has left a wait on this
* Barrier as a result of an error.
* @exception Interrupted_Exception thrown when the calling thread is interrupted.
* A thread may be interrupted at any time, prematurely ending a wait
* for one thread and breaking the barrier for all threads
*
* @see Waitable::wait(unsigned long timeout)
*
* @post If no exception was thrown, all threads have successfully arrived
* @post If an exception was thrown, the barrier is broken
*/
virtual bool wait(unsigned long timeout) {
Guard<LockType> g(_lock);
if(_broken)
throw BrokenBarrier_Exception();
// Break the barrier if an arriving thread is interrupted
if(Thread::interrupted()) {
// Release the other waiter, propagate the exception
_arrived.broadcast();
_broken = true;
throw Interrupted_Exception();
}
if(--_count == 0) {
// Wake the other threads if this was the last
// arriving thread
_arrived.broadcast();
// Try to run the associated task, if it throws then
// break the barrier and propagate the exception
try {
if(_task)
_task->run();
_generation++;
} catch(Synchronization_Exception&) {
_broken = true;
throw;
} catch(...) { assert(0); }
} else {
int myGeneration = _generation;
try {
// Wait for the other threads to arrive
if(!_arrived.wait(timeout))
_broken = true;
} catch(Interrupted_Exception&) {
// Its possible for a thread to be interrupted before the
// last thread arrives. If the interrupted thread hasn't
// resumed, then just propagate the interruption
if(myGeneration != _generation)
Thread().interrupt();
else _broken = true;
} catch(Synchronization_Exception&) {
// Break the barrier and propagate the exception
_broken = true;
throw;
}
// If the thread woke because it was notified by the thread
// that broke the barrier, throw.
if(_broken)
throw BrokenBarrier_Exception();
}
return true;
}
/**
* Break the Barrier ending the wait for any threads that were waiting on
* the barrier.
*
* @post the Barrier is broken, all waiting threads will throw the
* BrokenBarrier_Exception
*/
void shatter() {
Guard<LockType> g(_lock);
_broken = true;
_arrived.broadcast();
}
/**
* Reset the Barrier.
*
* @post the Barrier is no longer Broken and can be used again.
*/
void reset() {
Guard<LockType> g(_lock);
_broken = false;
_generation++;
_count = Count;
}
};
} // namespace ZThread
#endif // __ZTBARRIER_H__

View file

@ -1,319 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTBIASEDREADWRITELOCK_H__
#define __ZTBIASEDREADWRITELOCK_H__
#include "zthread/ReadWriteLock.h"
#include "zthread/Condition.h"
#include "zthread/Guard.h"
#include "zthread/FastMutex.h"
namespace ZThread {
/**
* @class BiasedReadWriteLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T10:22:34-0400>
* @version 2.2.7
*
* A BiasedReadWriteLock has a bias toward writers. It will prefer read-write access over
* read-only access when many threads are contending for access to either Lockable this
* ReadWriteLock provides.
*
* @see ReadWriteLock
*/
class BiasedReadWriteLock : public ReadWriteLock {
FastMutex _lock;
Condition _condRead;
Condition _condWrite;
volatile int _activeWriters;
volatile int _activeReaders;
volatile int _waitingReaders;
volatile int _waitingWriters;
//! @class ReadLock
class ReadLock : public Lockable {
BiasedReadWriteLock& _rwlock;
public:
ReadLock(BiasedReadWriteLock& rwlock) : _rwlock(rwlock) {}
virtual ~ReadLock() {}
virtual void acquire() {
_rwlock.beforeRead();
}
virtual bool tryAcquire(unsigned long timeout) {
return _rwlock.beforeReadAttempt(timeout);
}
virtual void release() {
_rwlock.afterRead();
}
};
//! @class WriteLock
class WriteLock : public Lockable {
BiasedReadWriteLock& _rwlock;
public:
WriteLock(BiasedReadWriteLock& rwlock) : _rwlock(rwlock) {}
virtual ~WriteLock() {}
virtual void acquire() {
_rwlock.beforeWrite();
}
virtual bool tryAcquire(unsigned long timeout) {
return _rwlock.beforeWriteAttempt(timeout);
}
virtual void release() {
_rwlock.afterWrite();
}
};
friend class ReadLock;
friend class WriteLock;
ReadLock _rlock;
WriteLock _wlock;
public:
/**
* Create a BiasedReadWriteLock
*
* @exception Initialization_Exception thrown if resources could not be
* allocated for this object.
*/
BiasedReadWriteLock() : _condRead(_lock), _condWrite(_lock), _rlock(*this), _wlock(*this) {
_activeWriters = 0;
_activeReaders = 0;
_waitingReaders = 0;
_waitingWriters = 0;
}
//! Destroy this ReadWriteLock
virtual ~BiasedReadWriteLock() {}
/**
* @see ReadWriteLock::getReadLock()
*/
virtual Lockable& getReadLock() { return _rlock; }
/**
* @see ReadWriteLock::getWriteLock()
*/
virtual Lockable& getWriteLock() { return _wlock; }
protected:
void beforeRead() {
Guard<FastMutex> guard(_lock);
++_waitingReaders;
while(!allowReader()) {
try {
// wait
_condRead.wait();
} catch(...) {
--_waitingReaders;
throw;
}
}
--_waitingReaders;
++_activeReaders;
}
bool beforeReadAttempt(unsigned long timeout) {
Guard<FastMutex> guard(_lock);
bool result = false;
++_waitingReaders;
while(!allowReader()) {
try {
result = _condRead.wait(timeout);
} catch(...) {
--_waitingReaders;
throw;
}
}
--_waitingReaders;
++_activeReaders;
return result;
}
void afterRead() {
bool wakeReader = false;
bool wakeWriter = false;
{
Guard<FastMutex> guard(_lock);
--_activeReaders;
wakeReader = (_waitingReaders > 0);
wakeWriter = (_waitingWriters > 0);
}
if(wakeWriter)
_condWrite.signal();
else if(wakeReader)
_condRead.signal();
}
void beforeWrite() {
Guard<FastMutex> guard(_lock);
++_waitingWriters;
while(!allowWriter()) {
try {
_condWrite.wait();
} catch(...) {
--_waitingWriters;
throw;
}
}
--_waitingWriters;
++_activeWriters;
}
bool beforeWriteAttempt(unsigned long timeout) {
Guard<FastMutex> guard(_lock);
bool result = false;
++_waitingWriters;
while(!allowWriter()) {
try {
result = _condWrite.wait(timeout);
} catch(...) {
--_waitingWriters;
throw;
}
}
--_waitingWriters;
++_activeWriters;
return result;
}
void afterWrite() {
bool wakeReader = false;
bool wakeWriter = false;
{
Guard<FastMutex> guard(_lock);
--_activeWriters;
wakeReader = (_waitingReaders > 0);
wakeWriter = (_waitingWriters > 0);
}
if(wakeWriter)
_condWrite.signal();
else if(wakeReader)
_condRead.signal();
}
bool allowReader() {
return (_activeWriters == 0);
}
bool allowWriter() {
return (_activeWriters == 0 && _activeReaders == 0);
}
};
}; // __ZTBIASEDREADWRITELOCK_H__
#endif

View file

@ -1,245 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTBLOCKINGQUEUE_H__
#define __ZTBLOCKINGQUEUE_H__
#include "zthread/Guard.h"
#include "zthread/Condition.h"
#include "zthread/Queue.h"
#include <deque>
namespace ZThread {
/**
* @class BlockingQueue
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T12:01:43-0400>
* @version 2.3.0
*
* Like a LockedQueue, a BlockingQueue is a Queue implementation that provides
* serialized access to the items added to it. It differs by causing threads
* accessing the next() methods to block until a value becomes available.
*/
template <class T, class LockType, typename StorageType = std::deque<T> >
class BlockingQueue : public Queue<T>, public Lockable {
//! Serialize access
LockType _lock;
//! Signaled when empty
Condition _notEmpty;
//! Storage backing the queue
StorageType _queue;
//! Cancellation flag
volatile bool _canceled;
public:
//! Create a new BlockingQueue
BlockingQueue() : _notEmpty(_lock), _canceled(false) {}
//! Destroy this BlockingQueue
virtual ~BlockingQueue() { }
/**
* @see Queue::add(const T& item)
*/
virtual void add(const T& item) {
Guard<LockType> g(_lock);
if(_canceled)
throw Cancellation_Exception();
_queue.push_back(item);
_notEmpty.signal();
}
/**
* @see Queue::add(const T& item, unsigned long timeout)
*/
virtual bool add(T item, unsigned long timeout) {
try {
Guard<LockType> g(_lock, timeout);
if(_canceled)
throw Cancellation_Exception();
_queue.push_back(item);
_notEmpty.signal();
} catch(Timeout_Exception&) { return false; }
return true;
}
/**
* Get a value from this Queue. The calling thread may block indefinitely.
*
* @return <em>T</em> next available value
*
* @exception Cancellation_Exception thrown if this Queue has been canceled.
*
* @exception Interrupted_Exception thrown if the calling thread is interrupted
* before a value becomes available.
*
* @pre The Queue should not have been canceled prior to the invocation of this function.
* @post The value returned will have been removed from the Queue.
*
* @see Queue::next()
*/
virtual T next() {
Guard<LockType> g(_lock);
while(_queue.empty() && !_canceled)
_notEmpty.wait();
if( _queue.empty() )
throw Cancellation_Exception();
T item = _queue.front();
_queue.pop_front();
return item;
}
/**
* Get a value from this Queue. The calling thread may block indefinitely.
*
* @param timeout maximum amount of time (milliseconds) this method may block
* the calling thread.
*
* @return <em>T</em> next available value
*
* @exception Cancellation_Exception thrown if this Queue has been canceled.
* @exception Timeout_Exception thrown if the timeout expires before a value
* can be retrieved.
* @exception Interrupted_Exception thrown if the calling thread is interrupted
* before a value becomes available.
*
* @pre The Queue should not have been canceled prior to the invocation of this function.
* @post The value returned will have been removed from the Queue.
*
* @see Queue::next(unsigned long timeout)
*/
virtual T next(unsigned long timeout) {
Guard<LockType> g(_lock, timeout);
while(_queue.empty() && !_canceled) {
if(!_notEmpty.wait(timeout))
throw Timeout_Exception();
}
if(_queue.empty() )
throw Cancellation_Exception();
T item = _queue.front();
_queue.pop_front();
return item;
}
/**
* @see Queue::cancel()
*
* @post If threads are blocked on one of the next() functions then
* they will be awakened with a Cancellation_Exception.
*/
virtual void cancel() {
Guard<LockType> g(_lock);
_notEmpty.broadcast();
_canceled = true;
}
/**
* @see Queue::isCanceled()
*/
virtual bool isCanceled() {
// Faster check since the queue will not become un-canceled
if(_canceled)
return true;
Guard<LockType> g(_lock);
return _canceled;
}
/**
* @see Queue::size()
*/
virtual size_t size() {
Guard<LockType> g(_lock);
return _queue.size();
}
/**
* @see Queue::size(unsigned long timeout)
*/
virtual size_t size(unsigned long timeout) {
Guard<LockType> g(_lock, timeout);
return _queue.size();
}
public:
virtual void acquire() {
_lock.acquire();
}
virtual bool tryAcquire(unsigned long timeout) {
return _lock.tryAcquire(timeout);
}
virtual void release() {
_lock.release();
}
}; /* BlockingQueue */
} // namespace ZThread
#endif // __ZTBLOCKINGQUEUE_H__

View file

@ -1,387 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTBOUNDEDQUEUE_H__
#define __ZTBOUNDEDQUEUE_H__
#include "zthread/Condition.h"
#include "zthread/Guard.h"
#include "zthread/Queue.h"
#include <deque>
namespace ZThread {
/**
* @class BoundedQueue
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T13:54:04-0400>
* @version 2.3.0
*
* A BoundedQueue provides serialized access to a set of values. It differs from other
* Queues by adding a maximum capacity, giving it the following properties:
*
* - Threads calling the empty() methods will be blocked until the BoundedQueue becomes empty.
* - Threads calling the next() methods will be blocked until the BoundedQueue has a value to
* return.
* - Threads calling the add() methods will be blocked until the number of values in the
* Queue drops below the maximum capacity.
*
* @see Queue
*/
template <class T, class LockType, typename StorageType=std::deque<T> >
class BoundedQueue : public Queue<T>, public Lockable {
//! Maximum capacity for the Queue
size_t _capacity;
//! Serialize access
LockType _lock;
//! Signaled if not full
Condition _notFull;
//! Signaled if not empty
Condition _notEmpty;
//! Signaled if empty
Condition _isEmpty;
//! Storage backing the queue
StorageType _queue;
//! Cancellation flag
volatile bool _canceled;
public:
/**
* Create a BoundedQueue with the given capacity.
*
* @param capacity maximum number of values to allow in the Queue at
* at any time
*/
BoundedQueue(size_t capacity)
: _notFull(_lock), _notEmpty(_lock), _isEmpty(_lock),
_capacity(capacity), _canceled(false) {}
//! Destroy this Queue
virtual ~BoundedQueue() { }
/**
* Get the maximum capacity of this Queue.
*
* @return <i>size_t</i> maximum capacity
*/
size_t capacity() {
return _capacity;
}
/**
* Add a value to this Queue.
*
* If the number of values in the queue matches the value returned by <i>capacity</i>()
* then the calling thread will be blocked until at least one value is removed from
* the Queue.
*
* @param item value to be added to the Queue
*
* @exception Cancellation_Exception thrown if this Queue has been canceled.
* @exception Interrupted_Exception thrown if the thread was interrupted while waiting
* to add a value
*
* @pre The Queue should not have been canceled prior to the invocation of this function.
* @post If no exception is thrown, a copy of <i>item</i> will have been added to the Queue.
*
* @see Queue::add(const T& item)
*/
virtual void add(const T& item) {
Guard<LockType> g(_lock);
// Wait for the capacity of the Queue to drop
while ((_queue.size() == _capacity) && !_canceled)
_notFull.wait();
if(_canceled)
throw Cancellation_Exception();
_queue.push_back(item);
_notEmpty.signal(); // Wake any waiters
}
/**
* Add a value to this Queue.
*
* If the number of values in the queue matches the value returned by <i>capacity</i>()
* then the calling thread will be blocked until at least one value is removed from
* the Queue.
*
* @param item value to be added to the Queue
* @param timeout maximum amount of time (milliseconds) this method may block
* the calling thread.
*
* @return
* - <em>true</em> if a copy of <i>item</i> can be added before <i>timeout</i>
* milliseconds elapse.
* - <em>false</em> otherwise.
*
* @exception Cancellation_Exception thrown if this Queue has been canceled.
* @exception Interrupted_Exception thrown if the thread was interrupted while waiting
* to add a value
*
* @pre The Queue should not have been canceled prior to the invocation of this function.
* @post If no exception is thrown, a copy of <i>item</i> will have been added to the Queue.
*
* @see Queue::add(const T& item, unsigned long timeout)
*/
virtual bool add(const T& item, unsigned long timeout) {
try {
Guard<LockType> g(_lock, timeout);
// Wait for the capacity of the Queue to drop
while ((_queue.size() == _capacity) && !_canceled)
if(!_notFull.wait(timeout))
return false;
if(_canceled)
throw Cancellation_Exception();
_queue.push_back(item);
_notEmpty.signal(); // Wake any waiters
} catch(Timeout_Exception&) { return false; }
return true;
}
/**
* Retrieve and remove a value from this Queue.
*
* If invoked when there are no values present to return then the calling thread
* will be blocked until a value arrives in the Queue.
*
* @return <em>T</em> next available value
*
* @exception Cancellation_Exception thrown if this Queue has been canceled.
* @exception Interrupted_Exception thrown if the thread was interrupted while waiting
* to retrieve a value
*
* @pre The Queue should not have been canceled prior to the invocation of this function.
* @post The value returned will have been removed from the Queue.
*/
virtual T next() {
Guard<LockType> g(_lock);
while ( _queue.empty() && !_canceled)
_notEmpty.wait();
if( _queue.empty()) // Queue canceled
throw Cancellation_Exception();
T item = _queue.front();
_queue.pop_front();
_notFull.signal(); // Wake any thread trying to add
if(_queue.empty()) // Wake empty waiters
_isEmpty.broadcast();
return item;
}
/**
* Retrieve and remove a value from this Queue.
*
* If invoked when there are no values present to return then the calling thread
* will be blocked until a value arrives in the Queue.
*
* @param timeout maximum amount of time (milliseconds) this method may block
* the calling thread.
*
* @return <em>T</em> next available value
*
* @exception Cancellation_Exception thrown if this Queue has been canceled.
* @exception Timeout_Exception thrown if the timeout expires before a value
* can be retrieved.
*
* @pre The Queue should not have been canceled prior to the invocation of this function.
* @post The value returned will have been removed from the Queue.
*/
virtual T next(unsigned long timeout) {
Guard<LockType> g(_lock, timeout);
// Wait for items to be added
while (_queue.empty() && !_canceled) {
if(!_notEmpty.wait(timeout))
throw Timeout_Exception();
}
if(_queue.empty()) // Queue canceled
throw Cancellation_Exception();
T item = _queue.front();
_queue.pop_front();
_notFull.signal(); // Wake add() waiters
if(_queue.empty()) // Wake empty() waiters
_isEmpty.broadcast();
return item;
}
/**
* Cancel this queue.
*
* @post Any threads blocked by an add() function will throw a Cancellation_Exception.
* @post Any threads blocked by a next() function will throw a Cancellation_Exception.
*
* @see Queue::cancel()
*/
virtual void cancel() {
Guard<LockType> g(_lock);
_canceled = true;
_notEmpty.broadcast(); // Wake next() waiters
}
/**
* @see Queue::isCanceled()
*/
virtual bool isCanceled() {
// Faster check since the Queue will not become un-canceled
if(_canceled)
return true;
Guard<LockType> g(_lock);
return _canceled;
}
/**
* @see Queue::size()
*/
virtual size_t size() {
Guard<LockType> g(_lock);
return _queue.size();
}
/**
* @see Queue::size(unsigned long timeout)
*/
virtual size_t size(unsigned long timeout) {
Guard<LockType> g(_lock, timeout);
return _queue.size();
}
/**
* Test whether any values are available in this Queue.
*
* The calling thread is blocked until there are no values present
* in the Queue.
*
* @return
* - <em>true</em> if there are no values available.
* - <em>false</em> if there <i>are</i> values available.
*
* @see Queue::empty()
*/
virtual bool empty() {
Guard<LockType> g(_lock);
while(!_queue.empty()) // Wait for an empty signal
_isEmpty.wait();
return true;
}
/**
* Test whether any values are available in this Queue.
*
* The calling thread is blocked until there are no values present
* in the Queue.
*
* @param timeout maximum amount of time (milliseconds) this method may block
* the calling thread.
*
* @return
* - <em>true</em> if there are no values available.
* - <em>false</em> if there <i>are</i> values available.
*
* @exception Timeout_Exception thrown if <i>timeout</i> milliseconds
* expire before a value becomes available
*
* @see Queue::empty()
*/
virtual bool empty(unsigned long timeout) {
Guard<LockType> g(_lock, timeout);
while(!_queue.empty()) // Wait for an empty signal
_isEmpty.wait(timeout);
return true;
}
public:
virtual void acquire() {
_lock.acquire();
}
virtual bool tryAcquire(unsigned long timeout) {
return _lock.tryAcquire(timeout);
}
virtual void release() {
_lock.release();
}
}; /* BoundedQueue */
} // namespace ZThread
#endif // __ZTBOUNDEDQUEUE_H__

View file

@ -1,86 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTCANCELABLE_H__
#define __ZTCANCELABLE_H__
#include "zthread/Exceptions.h"
namespace ZThread {
/**
* @class Cancelable
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T09:28:46-0400>
* @version 2.3.0
*
* The Cancelable interface defines a common method of adding general <i>disable-and-exit</i>
* semantics to some object. By cancel()ing a Cancelable object, a request is
* made to disable that object.
*
* <b>Disabling</b>
*
* A cancel()ed object may not necessarily abort it work immediately. Often, it much more
* elegant for a cancel()ed object to complete handling whatever responsibilities have
* been assigned to it, but it will <i>not</i> take on any new responsibility.
*
* <b>Exiting</b>
*
* A cancel()ed should complete its responsibilities as soon as possible.
* Canceling is not only a request to stop taking on new responsibility, and to
* complete its current responsibility. Its also a request to complete dealing with its
* current responsibilities, quickly when possible.
*/
class Cancelable {
public:
//! Destroy a Cancelable object.
virtual ~Cancelable() {}
/**
* Canceling a Cancelable object makes a request to disable that object.
* This entails refusing to take on any new responsibility, and completing
* its current responsibilities quickly.
*
* Canceling an object more than once has no effect.
*
* @post The Cancelable object will have permanently transitioned to a
* disabled state; it will now refuse to accept new responsibility.
*/
virtual void cancel() = 0;
/**
* Determine if a Cancelable object has been canceled.
*
* @return
* - <em>true</em> if cancel() was called prior to this function.
* - <em>false</em> otherwise.
*/
virtual bool isCanceled() = 0;
}; /* Cancelable */
} // namespace ZThread
#endif // __ZTCANCELABLE_H__

View file

@ -1,74 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTCLASSLOCKABLE_H__
#define __ZTCLASSLOCKABLE_H__
#include "zthread/CountedPtr.h"
#include "zthread/Mutex.h"
namespace ZThread {
/**
* @class ClassLockable
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:37:38-0400>
* @version 2.3.0
*
*
*/
template <typename ClassType, class LockType = Mutex>
class ClassLockable : public Lockable {
static CountedPtr<LockType> _instance;
CountedPtr<LockType> _lock;
public:
//! Create a ClassLockable
ClassLockable()
: _lock(_instance) {}
//! acquire() the ClassLockable
virtual void acquire() {
_lock->acquire();
}
//! tryAcquire() the ClassLockable
virtual bool tryAcquire(unsigned long timeout) {
return _lock->tryAcquire(timeout);
}
//! release() the ClassLockable
virtual void release() {
_lock->release();
}
};
template <typename ClassType, class LockType>
CountedPtr<LockType> ClassLockable<ClassType, LockType>::_instance(new LockType);
} // namespace ZThread
#endif // __ZTCLASSLOCKABLE_H__

View file

@ -1,124 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTCONCURRENTEXECUTOR_H__
#define __ZTCONCURRENTEXECUTOR_H__
#include "zthread/PoolExecutor.h"
namespace ZThread {
/**
* @class ConcurrentExecutor
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T22:36:11-0400>
* @version 2.3.0
*
* A ConcurrentExecutor spawns a single thread to service a series of Tasks.
*
* @see PoolExecutor.
*/
class ConcurrentExecutor : public Executor {
PoolExecutor _executor;
public:
//! Create a ConcurrentExecutor
ConcurrentExecutor();
/**
* Interrupting a ConcurrentExecutor will cause the thread running the tasks to be
* be interrupted once during the execution of each task that has been submitted
* at the time this function is called.
*
* Tasks that are submitted after this function is called will
* not be interrupt()ed; unless this function is invoked again().
*
* @code
*
* void aFunction() {
*
* ConcurrentExecutor executor;
*
* // Submit p Tasks
* for(size_t n = 0; n < p; n++)
* executor.execute(new aRunnable);
*
* // Tasks [m, p) may be interrupted, where m is the first task that has
* // not completed at the time the interrupt() is invoked.
* executor.interrupt();
*
* // Submit (q - p) Tasks
* for(size_t n = p; n < q; n++)
* executor.execute(new Chore);
*
* // Tasks [p, q) are not interrupted
*
* }
*
* @endcode
*/
virtual void interrupt();
/**
* Submit a Task to this Executor. This will not block the current thread
* for very long. The task will be enqueued internally and eventually run
* in the context of the single thread driving all the Tasks submitted to this
* Executor.
*
* @exception Cancellation_Exception thrown if this Executor has been canceled.
* The Task being submitted will not be executed by this Executor.
*
* @exception Synchronization_Exception thrown only in the event of an error
* in the implementation of the library.
*
* @see Executor::execute(const Task&)
*/
virtual void execute(const Task&);
/**
* @see Cancelable::cancel()
*/
virtual void cancel();
/**
* @see Cancelable::isCanceled()
*/
virtual bool isCanceled();
/**
* @see PoolExecutor::wait()
*/
virtual void wait();
/**
* @see PoolExecutor::wait(unsigned long timeout)
*/
virtual bool wait(unsigned long timeout);
}; /* ConcurrentExecutor */
} // namespace ZThread
#endif // __ZTCONCURRENTEXECUTOR_H__

View file

@ -1,154 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTCONDITION_H__
#define __ZTCONDITION_H__
#include "zthread/Lockable.h"
#include "zthread/NonCopyable.h"
#include "zthread/Waitable.h"
namespace ZThread {
class FifoConditionImpl;
/**
* @class Condition
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T14:38:59-0400>
* @version 2.2.1
*
* A Condition is a Waitable object used to block a thread until a particular
* condition is met. A Condition object is always used in conjunction with Lockable
* object. This object should be a FastMutex, Mutex, PriorityMutex or PriorityInheritanceMutex.
*
* Condition objects are reminiscent of POSIX condition variables in several ways but
* are slightly different.
*
* A Condition is <i>not</i> subject to spurious wakeup.
*
* Like all Waitable objects, Conditions are sensitive to Thread::interupt() which can
* be used to prematurely end a wait().
*
* @see Thread::interupt()
*
* Before a wait() is performed on a Condition, the associated Lockable object should
* have been acquire()ed. When the wait() begins, that Lockable object is release()d
* (wait() will atomically begin the wait and unlock the Lockable).
*
* A thread blocked by wait() will remain so until an exception occurs, or until
* the thread awakened by a signal() or broadcast(). When the thread resumes execution,
* the associated Lockable is acquire()d before wait() returns.
*
* <b>Scheduling</b>
*
* Threads blocked on a Condition are resumed in FIFO order.
*/
class ZTHREAD_API Condition : public Waitable, private NonCopyable {
FifoConditionImpl* _impl;
public:
/**
* Create a Condition associated with the given Lockable object.
*
* @param l Lockable object to associate with this Condition object.
*/
Condition(Lockable& l);
//! Destroy Condition object
virtual ~Condition();
/**
* Wake <em>one</em> thread waiting on this Condition.
*
* The associated Lockable need not have been acquire when this function is
* invoked.
*
* @post a waiting thread, if any exists, will be awakened.
*/
void signal();
/**
* Wake <em>all</em> threads wait()ing on this Condition.
*
* The associated Lockable need not have been acquire when this function is
* invoked.
*
* @post all wait()ing threads, if any exist, will be awakened.
*/
void broadcast();
/**
* Wait for this Condition, blocking the calling thread until a signal or broadcast
* is received.
*
* This operation atomically releases the associated Lockable and blocks the calling thread.
*
* @exception Interrupted_Exception thrown when the calling thread is interrupted.
* A thread may be interrupted at any time, prematurely ending any wait.
*
* @pre The thread calling this method must have first acquired the associated
* Lockable object.
*
* @post A thread that has resumed execution without exception (because of a signal(),
* broadcast() or exception) will have acquire()d the associated Lockable object
* before returning from a wait().
*
* @see Waitable::wait()
*/
virtual void wait();
/**
* Wait for this Condition, blocking the calling thread until a signal or broadcast
* is received.
*
* This operation atomically releases the associated Lockable and blocks the calling thread.
*
* @param timeout maximum amount of time (milliseconds) this method could block
*
* @return
* - <em>true</em> if the Condition receives a signal or broadcast before
* <i>timeout</i> milliseconds elapse.
* - <em>false</em> otherwise.
*
* @exception Interrupted_Exception thrown when the calling thread is interrupted.
* A thread may be interrupted at any time, prematurely ending any wait.
*
* @pre The thread calling this method must have first acquired the associated
* Lockable object.
*
* @post A thread that has resumed execution without exception (because of a signal(),
* broadcast() or exception) will have acquire()d the associated Lockable object
* before returning from a wait().
*
* @see Waitable::wait(unsigned long timeout)
*/
virtual bool wait(unsigned long timeout);
};
} // namespace ZThread
#endif // __ZTCONDITION_H__

View file

@ -1,218 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTCONFIG_H__
#define __ZTCONFIG_H__
// =====================================================================================
// The following section describes the symbols the configure program will define.
// If you are not using configure (autoconf), then you make want to set these by
// uncommenting them here, or whatever other means you'd like.
// =====================================================================================
// (configure)
// Uncomment to disable actually changing the operating systems real thread priority
// #define ZTHREAD_DISABLE_PRIORITY 1
// (configure)
// Uncomment to disable compiling the interrupt() hook mechanisms.
// #define ZTHREAD_DISABLE_INTERRUPT 1
// (configure)
// Uncomment to select a Win32 ThreadOps implementation that uses _beginthreadex()
// otherwise, CreateThread() will be used for a Windows compilation
// #define HAVE_BEGINTHREADEX 1
// (configure)
// Uncomment to select a pthreads based implementation
// #define ZT_POSIX 1
// (configure)
// Uncomment to select a Windows based implementation that uses features not
// supported by windows 98 and 95
// #define ZT_WIN32 1
// (configure)
// Uncomment to select a Windows based implementation that does not use features not
// supported by windows 98 and 95, but may not be compatible with 64 bit or alpha systems
// #define ZT_WIN9X 1
// (configure)
// Uncomment to select a MacOS based implementation
// #define ZT_MACOS 1
// (configure)
// Uncomment to prefer vanilla implementations of primatives when possible
// #define ZT_VANILLA 1
// =====================================================================================
// The following section can be customized to select the implementation that is compiled
// Eventually, the configure program will be updated to define these symbols as well.
// =====================================================================================
// Uncomment to select very simple spinlock based implementations
// #define ZTHREAD_USE_SPIN_LOCKS 1
// Uncomment to select the vannila dual mutex implementation of FastRecursiveLock
// #define ZTHREAD_DUAL_LOCKS 1
// Uncomment to select a POSIX implementation of FastRecursiveLock that does not
// spin, but instead sleeps on a condition variable.
// #define ZTHREAD_CONDITION_LOCKS 1
// Uncomment if you want to eliminate inlined code used as a part of some template classes
// #define ZTHREAD_NOINLINE
// Uncomment if you want to compile a DLL version of the library. (Win32)
// #define ZTHREAD_EXPORTS 1
// Uncomment if you want to compile a client using the DLL version of the library. (Win32)
// #define ZTHREAD_IMPORTS 1
// ===================================================================================
// The following section will attempt to guess the best configuration for your system
// ===================================================================================
// Select an implementation by checking out the environment, first looking for
// compilers, then by looking for other definitions that could be present
#if !defined(ZT_POSIX) && !defined(ZT_WIN9X) && !defined(ZT_WIN32) && !defined(ZT_MACOS)
// Check for well known compilers
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__BCPLUSPLUS__) || defined(__MINGW32__)
# define ZT_WIN32
#elif defined(__CYGWIN__)
# define ZT_POSIX
// Check for well known platforms
#elif defined(__linux__) || \
defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
defined(__hpux) || \
defined(__sgi) || \
defined(__sun)
# define ZT_POSIX
// Check for definitions from well known headers
#elif defined(_POSIX_SOURCE) || defined(_XOPEN_SOURCE)
# define ZT_POSIX
#elif defined(WIN32_LEAN_AND_MEAN)
# define ZT_WIN32
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
# define ZT_MACOS
#else
# error "Could not select implementation, define ZT_WIN9X, ZT_WIN32, ZT_POSIX or ZT_MACOS"
#endif
#endif
// Once an implementation has been selected, configure the API decorator
// for shared libraries if its needed.
#if defined(ZTHREAD_SHARED) // Compatibility w/ past releases
# define ZTHREAD_IMPORTS
#elif defined(ZTHREAD_STATIC)
# undef ZTHREAD_EXPORTS
# undef ZTHREAD_IMPORTS
#endif
// Windows users will get a static build by default, unless they
// define either ZTHREAD_IMPORTS or ZTHREAD_EXPORTS. Client code
// of a dll version of this library should define the first flag;
// To build the dll version of this library, define the second.
#if defined(ZTHREAD_IMPORTS) && defined(ZTHREAD_EXPORTS)
# error "Import and export declarations are not valid"
#else
# if defined(ZTHREAD_IMPORTS)
# define ZTHREAD_API __declspec(dllimport)
# elif defined(ZTHREAD_EXPORTS)
# define ZTHREAD_API __declspec(dllexport)
# else
# define ZTHREAD_API
# endif
#endif
// Once the API decorator is configured, create a macro for
// explicit template instantiation (whose need can hopefully
// be removed from the library)
#if defined(ZTHREAD_EXPORTS)
# define EXPLICIT_TEMPLATE(X) template class __declspec( dllexport ) X;
#elif defined(ZTHREAD_IMPORTS)
# define EXPLICIT_TEMPLATE(X) template class __declspec( dllimport ) X;
#else
# define EXPLICIT_TEMPLATE(X)
#endif
// Give libc a hint, should be defined by the user - but people tend
// to forget.
#if !defined(REENTRANT)
# define REENTRANT
#endif
#if !defined(_REENTRANT)
# define _REENTRANT
#endif
#if defined(_MSC_VER)
# pragma warning(disable:4275)
# pragma warning(disable:4290)
# pragma warning(disable:4786)
# pragma warning(disable:4251)
# pragma warning(disable:4355)
#endif
// Ensure that only one implementation is selected
#if \
(defined(ZT_POSIX) && defined(ZT_WIN32)) \
|| (defined(ZT_POSIX) && defined(ZT_WIN9X)) \
|| (defined(ZT_WIN32) && defined(ZT_WIN9X))
# error "Only one implementation should be selected!"
#endif
#if defined(ZTHREAD_NOINLINE)
# define ZTHREAD_INLINE
#else
# define ZTHREAD_INLINE inline
#endif
#endif // __ZTCONFIG_H__

View file

@ -1,289 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTCOUNTEDPTR_H__
#define __ZTCOUNTEDPTR_H__
#include <algorithm>
#include <cassert>
#include "zthread/AtomicCount.h"
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable:4786) // warning: long template symbol name
# pragma warning(push)
# pragma warning(disable:4284) // warning: odd return type for operator->
#endif
namespace ZThread {
/**
* @class CountedPtr
*
* @author Eric Crahen <http://www.code-foo.com/>
* @date <2003-07-29T06:43:48-0400>
* @version 2.3.0
*
*/
template <typename T, typename CountT = AtomicCount>
class CountedPtr {
#if !defined(__MWERKS__)
#if !defined(_MSC_VER) || (_MSC_VER > 1200)
template <typename U, typename V> friend class CountedPtr;
#endif
#endif
CountT* _count;
T* _instance;
public:
CountedPtr() : _count(0), _instance(0) { }
#if !defined(__MWERKS__)
#if !defined(_MSC_VER) || (_MSC_VER > 1200)
explicit CountedPtr(T* raw) : _count(new CountT()), _instance(raw) {
(*_count)++;
}
#endif
#endif
template <typename U>
explicit CountedPtr(U* raw) : _count(new CountT()), _instance(raw) {
(*_count)++;
}
#if !defined(__MWERKS__)
#if !defined(_MSC_VER) || (_MSC_VER > 1200)
CountedPtr(const CountedPtr& ptr) : _count(ptr._count), _instance(ptr._instance) {
if(_count)
(*_count)++;
}
#endif
#endif
template <typename U, typename V>
CountedPtr(const CountedPtr<U, V>& ptr) : _count(ptr._count), _instance(ptr._instance) {
if(_count)
(*_count)++;
}
~CountedPtr() {
if(_count && --(*_count) == 0) {
if(_instance)
delete _instance;
delete _count;
}
}
#if !defined(__MWERKS__)
#if !defined(_MSC_VER) || (_MSC_VER > 1200)
const CountedPtr& operator=(const CountedPtr& ptr) {
typedef CountedPtr<T, CountT> ThisT;
ThisT(ptr).swap(*this);
return *this;
}
#endif
#endif
template <typename U, typename V>
const CountedPtr& operator=(const CountedPtr<U, V>& ptr) {
typedef CountedPtr<T, CountT> ThisT;
ThisT(ptr).swap(*this);
return *this;
}
void reset() {
typedef CountedPtr<T, CountT> ThisT;
ThisT().swap(*this);
}
#if !defined(__MWERKS__)
#if !defined(_MSC_VER) || (_MSC_VER > 1200)
void swap(CountedPtr& ptr) {
std::swap(_count, ptr._count);
std::swap(_instance, ptr._instance);
}
#endif
#endif
template <typename U, typename V>
void swap(CountedPtr<U, V>& ptr) {
std::swap(_count, ptr._count);
std::swap(_instance, ptr._instance);
}
// Convience operators
#if !defined(__MWERKS__)
#if !defined(_MSC_VER) || (_MSC_VER > 1200)
bool less(const CountedPtr& ptr) const {
return _instance < ptr._instance;
}
#endif
#endif
template <typename U, typename V>
bool less(const CountedPtr<U, V>& ptr) const {
return _instance < ptr._instance;
}
#if !defined(__MWERKS__)
#if !defined(_MSC_VER) || (_MSC_VER > 1200)
bool equal(const CountedPtr& ptr) const {
return _count == ptr._count;
}
#endif
#endif
template <typename U, typename V>
bool equal(const CountedPtr<U, V>& ptr) const {
return _count == ptr._count;
}
friend inline bool operator==(const CountedPtr& lhs, const CountedPtr& rhs) {
return lhs.equal(rhs);
}
friend inline bool operator<(const CountedPtr& lhs, const CountedPtr& rhs) {
return lhs.less(rhs);
}
T& operator*() {
assert(_instance != 0);
return *_instance;
}
T* operator->() {
assert(_instance != 0);
return _instance;
}
const T* operator->() const {
assert(_instance != 0);
return _instance;
}
bool operator!() const {
return _instance == 0;
}
operator bool() const {
return _instance != 0;
}
}; /* CountedPtr */
template<typename U, typename V, typename X, typename Y>
inline bool operator<(CountedPtr<U, V> const &lhs, CountedPtr<X, Y> const &rhs) {
return lhs.less(rhs);
}
template<typename U, typename V, typename X, typename Y>
inline bool operator==(CountedPtr<U, V> const &lhs, CountedPtr<X, Y> const &rhs) {
return lhs.equal(rhs.get);
}
template<typename U, typename V, typename X, typename Y>
inline bool operator!=(CountedPtr<U, V> const &lhs, CountedPtr<X, Y> const &rhs) {
return !(lhs.equal(rhs.get));
}
template<typename U, typename V, typename X, typename Y>
inline void swap(CountedPtr<U, V> const &lhs, CountedPtr<X, Y> const &rhs) {
lhs.swap(rhs);
}
#if !defined(__MWERKS__)
#if !defined(_MSC_VER) || (_MSC_VER > 1200)
template<typename U, typename V>
inline bool operator<(CountedPtr<U, V> const &lhs, CountedPtr<U, V> const &rhs) {
return lhs.less(rhs);
}
template<typename U, typename V>
inline bool operator==(CountedPtr<U, V> const &lhs, CountedPtr<U, V> const &rhs) {
return lhs.equal(rhs.get);
}
template<typename U, typename V>
inline bool operator!=(CountedPtr<U, V> const &lhs, CountedPtr<U, V> const &rhs) {
return !(lhs.equal(rhs.get));
}
template<typename U, typename V>
inline void swap(CountedPtr<U, V> const &lhs, CountedPtr<U, V> const &rhs) {
lhs.swap(rhs);
}
#endif
#endif
} // namespace ZThread
#ifdef _MSC_VER
# pragma warning(pop)
# pragma warning(pop)
#endif
#endif // __ZTCOUNTEDPTR_H__

View file

@ -1,138 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTCOUNTINGSEMAPHORE_H__
#define __ZTCOUNTINGSEMAPHORE_H__
#include "zthread/Lockable.h"
#include "zthread/NonCopyable.h"
namespace ZThread {
class FifoSemaphoreImpl;
/**
* @class CountingSemaphore
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T15:26:18-0400>
* @version 2.2.1
*
* A CountingSemaphore is an owner-less Lockable object.
*
* It differs from a normal Semaphore in that there is no upper bound on the count
* and it will not throw an exception because a maximum value has been exceeded.
*
* @see Semaphore
*
* Threads blocked on a CountingSemaphore are resumed in FIFO order.
*/
class ZTHREAD_API CountingSemaphore : public Lockable, private NonCopyable {
FifoSemaphoreImpl* _impl;
public:
/**
* Create a new CountingSemaphore.
*
* @param count - initial count
*/
CountingSemaphore(int initialCount = 0);
//! Destroy the CountingSemaphore
virtual ~CountingSemaphore();
/**
* <i>Provided to reflect the traditional Semaphore semantics</i>
*
* @see acquire()
*/
void wait();
/**
* <i>Provided to reflect the traditional Semaphore semantics</i>
*
* @see tryAcquire(unsigned long timeout)
*/
bool tryWait(unsigned long timeout);
/**
* <i>Provided to reflect the traditional Semaphore semantics</i>
*
* @see release()
*/
void post();
/**
* Get the current count of the semaphore.
*
* This value may change immediately after this function returns to the calling thread.
*
* @return <em>int</em> count
*/
virtual int count();
/**
* Decrement the count, blocking that calling thread if the count becomes 0 or
* less than 0. The calling thread will remain blocked until the count is
* raised above 0, an exception is thrown or the given amount of time expires.
*
* @param timeout maximum amount of time (milliseconds) this method could block
*
* @return
* - <em>true</em> if the Semaphore was acquired before <i>timeout</i> milliseconds elapse.
* - <em>false</em> otherwise.
*
* @exception Interrupted_Exception thrown when the calling thread is interrupted.
* A thread may be interrupted at any time, prematurely ending any wait.
*
* @see Lockable::tryAcquire(unsigned long timeout)
*/
virtual bool tryAcquire(unsigned long timeout);
/**
* Decrement the count, blocking that calling thread if the count becomes 0 or
* less than 0. The calling thread will remain blocked until the count is
* raised above 0 or if an exception is thrown.
*
* @exception Interrupted_Exception thrown when the calling thread is interrupted.
* A thread may be interrupted at any time, prematurely ending any wait.
*
* @see Lockable::acquire()
*/
virtual void acquire();
/**
* Increment the count, unblocking one thread if count is positive.
*
* @see Lockable::release()
*/
virtual void release();
};
} // namespace ZThread
#endif // __ZTCOUNTINGSEMAPHORE_H__

View file

@ -1,244 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTEXCEPTIONS_H__
#define __ZTEXCEPTIONS_H__
#include "zthread/Config.h"
#include <string>
namespace ZThread {
/**
* @class Synchronization_Exception
*
* Serves as a general base class for the Exception hierarchy used within
* this package.
*
*/
class Synchronization_Exception {
// Restrict heap allocation
static void * operator new(size_t size);
static void * operator new[](size_t size);
std::string _msg;
public:
/**
* Create a new exception with a default error message 'Synchronization
* Exception'
*/
Synchronization_Exception() : _msg("Synchronization exception") { }
/**
* Create a new exception with a given error message
*
* @param const char* - error message
*/
Synchronization_Exception(const char* msg) : _msg(msg) { }
/**
* Get additional info about the exception
*
* @return const char* for the error message
*/
const char* what() const {
return _msg.c_str();
}
};
/**
* @class Interrupted_Exception
*
* Used to describe an interrupted operation that would have normally
* blocked the calling thread
*/
class Interrupted_Exception : public Synchronization_Exception {
public:
//! Create a new exception
Interrupted_Exception() : Synchronization_Exception("Thread interrupted") { }
//! Create a new exception
Interrupted_Exception(const char* msg) : Synchronization_Exception(msg) { }
};
/**
* @class Deadlock_Exception
*
* Thrown when deadlock has been detected
*/
class Deadlock_Exception : public Synchronization_Exception {
public:
//! Create a new exception
Deadlock_Exception() : Synchronization_Exception("Deadlock detected") { }
//! Create a new exception
Deadlock_Exception(const char* msg) : Synchronization_Exception(msg) { }
};
/**
* @class InvalidOp_Exception
*
* Thrown when performing an illegal operation this object
*/
class InvalidOp_Exception : public Synchronization_Exception {
public:
//! Create a new exception
InvalidOp_Exception() : Synchronization_Exception("Invalid operation") { }
//! Create a new exception
InvalidOp_Exception(const char* msg) : Synchronization_Exception(msg) { }
};
/**
* @class Initialization_Exception
*
* Thrown when the system has no more resources to create new
* synchronization controls
*/
class Initialization_Exception : public Synchronization_Exception {
public:
//! Create a new exception
Initialization_Exception() : Synchronization_Exception("Initialization error") { }
//! Create a new exception
Initialization_Exception(const char*msg) : Synchronization_Exception(msg) { }
};
/**
* @class Cancellation_Exception
*
* Cancellation_Exceptions are thrown by 'Canceled' objects.
* @see Cancelable
*/
class Cancellation_Exception : public Synchronization_Exception {
public:
//! Create a new Cancelltion_Exception
Cancellation_Exception() : Synchronization_Exception("Canceled") { }
//! Create a new Cancelltion_Exception
Cancellation_Exception(const char*msg) : Synchronization_Exception(msg) { }
};
/**
* @class Timeout_Exception
*
* There is no need for error messaged simply indicates the last
* operation timed out
*/
class Timeout_Exception : public Synchronization_Exception {
public:
//! Create a new Timeout_Exception
Timeout_Exception() : Synchronization_Exception("Timeout") { }
//! Create a new
Timeout_Exception(const char*msg) : Synchronization_Exception(msg) { }
};
/**
* @class NoSuchElement_Exception
*
* The last operation that was attempted on a Queue could not find
* the item that was indicated (during that last Queue method invocation)
*/
class NoSuchElement_Exception {
public:
//! Create a new exception
NoSuchElement_Exception() {}
};
/**
* @class InvalidTask_Exception
*
* Thrown when a task is not valid (e.g. null or start()ing a thread with
* no overriden run() method)
*/
class InvalidTask_Exception : public InvalidOp_Exception {
public:
//! Create a new exception
InvalidTask_Exception() : InvalidOp_Exception("Invalid task") {}
};
/**
* @class BrokenBarrier_Exception
*
* Thrown when a Barrier is broken because one of the participating threads
* has been interrupted.
*/
class BrokenBarrier_Exception : public Synchronization_Exception {
public:
//! Create a new exception
BrokenBarrier_Exception() : Synchronization_Exception("Barrier broken") { }
//! Create a new exception
BrokenBarrier_Exception(const char* msg) : Synchronization_Exception(msg) { }
};
/**
* @class Future_Exception
*
* Thrown when there is an error using a Future.
*/
class Future_Exception : public Synchronization_Exception {
public:
//! Create a new exception
Future_Exception() : Synchronization_Exception() { }
//! Create a new exception
Future_Exception(const char* msg) : Synchronization_Exception(msg) { }
};
};
#endif // __ZTEXCEPTIONS_H__

View file

@ -1,94 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTEXECUTOR_H__
#define __ZTEXECUTOR_H__
#include "zthread/Thread.h"
#include "zthread/Waitable.h"
namespace ZThread {
/**
* @class Executor
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T22:39:39-0400>
* @version 2.3.0
*
* Execeutors are an implementation of the Executor pattern. This is
* a more versatile construct than a thread pool. A paper describing can
* be found in the proceedings of the 2002 VikingPLOP conference.
*
* <b>Executing</b>
*
* - <em>execute</em>()ing task with an Executor will submit the task, scheduling
* it for execution at some future time depending on the Executor being used.
*
* <b>Disabling</b>
*
* - <em>cancel</em>()ing an Executor will cause it to stop accepting
* new tasks.
*
* <b>Interrupting</b>
*
* - <em>interrupt</em>()ing an Executor will cause the any thread running
* a task which was submitted prior to the invocation of this function to
* be interrupted during the execution of that task.
*
* <b>Waiting</b>
*
* - <em>wait</em>()ing on a PoolExecutor will block the calling thread
* until all tasks that were submitted prior to the invocation of this function
* have completed.
*
* @see Cancelable
* @see Waitable
*/
class Executor : public Cancelable, public Waitable, private NonCopyable {
public:
/**
* If supported by the Executor, interrupt all tasks submitted prior to
* the invocation of this function.
*/
virtual void interrupt() = 0;
/**
* Submit a task to this Executor.
*
* @param task Task to be run by a thread managed by this executor
*
* @pre The Executor should have been canceled prior to this invocation.
* @post The submitted task will be run at some point in the future by this Executor.
*
* @exception Cancellation_Exception thrown if the Executor was canceled prior to
* the invocation of this function.
*/
virtual void execute(const Task& task) = 0;
};
} // namespace ZThread
#endif // __ZTEXECUTOR_H__

View file

@ -1,183 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTFAIRREADWRITELOCK_H__
#define __ZTFAIRREADWRITELOCK_H__
#include "zthread/ReadWriteLock.h"
#include "zthread/Condition.h"
#include "zthread/Guard.h"
#include "zthread/Mutex.h"
namespace ZThread {
/**
* @class FairReadWriteLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T10:26:25-0400>
* @version 2.2.7
*
* A FairReadWriteLock maintains a balance between the order read-only access
* and read-write access is allowed. Threads contending for the pair of Lockable
* objects this ReadWriteLock provides will gain access to the locks in FIFO order.
*
* @see ReadWriteLock
*/
class FairReadWriteLock : public ReadWriteLock {
Mutex _lock;
Condition _cond;
volatile int _readers;
//! @class ReadLock
class ReadLock : public Lockable {
FairReadWriteLock& _rwlock;
public:
ReadLock(FairReadWriteLock& rwlock) : _rwlock(rwlock) {}
virtual ~ReadLock() {}
virtual void acquire() {
Guard<Mutex> g(_rwlock._lock);
++_rwlock._readers;
}
virtual bool tryAcquire(unsigned long timeout) {
if(!_rwlock._lock.tryAcquire(timeout))
return false;
++_rwlock._readers;
_rwlock._lock.release();
return true;
}
virtual void release() {
Guard<Mutex> g(_rwlock._lock);
--_rwlock._readers;
if(_rwlock._readers == 0)
_rwlock._cond.signal();
}
};
//! @class WriteLock
class WriteLock : public Lockable {
FairReadWriteLock& _rwlock;
public:
WriteLock(FairReadWriteLock& rwlock) : _rwlock(rwlock) {}
virtual ~WriteLock() {}
virtual void acquire() {
_rwlock._lock.acquire();
try {
while(_rwlock._readers > 0)
_rwlock._cond.wait();
} catch(...) {
_rwlock._lock.release();
throw;
}
}
virtual bool tryAcquire(unsigned long timeout) {
if(!_rwlock._lock.tryAcquire(timeout))
return false;
try {
while(_rwlock._readers > 0)
_rwlock._cond.wait(timeout);
} catch(...) {
_rwlock._lock.release();
throw;
}
return true;
}
virtual void release() {
_rwlock._lock.release();
}
};
friend class ReadLock;
friend class WriteLock;
ReadLock _rlock;
WriteLock _wlock;
public:
/**
* Create a BiasedReadWriteLock
*
* @exception Initialization_Exception thrown if resources could not be
* allocated for this object.
*/
FairReadWriteLock() : _cond(_lock), _readers(0), _rlock(*this), _wlock(*this) {}
//! Destroy this ReadWriteLock
virtual ~FairReadWriteLock() {}
/**
* @see ReadWriteLock::getReadLock()
*/
virtual Lockable& getReadLock() { return _rlock; }
/**
* @see ReadWriteLock::getWriteLock()
*/
virtual Lockable& getWriteLock() { return _wlock; }
};
}; // __ZTFAIRREADWRITELOCK_H__
#endif

View file

@ -1,111 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTFASTMUTEX_H__
#define __ZTFASTMUTEX_H__
#include "zthread/Lockable.h"
#include "zthread/NonCopyable.h"
namespace ZThread {
class FastLock;
/**
* @class FastMutex
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-19T18:45:39-0400>
* @version 2.2.0
*
* A FastMutex is a small fast implementation of a non-recursive, mutually exclusive
* Lockable object. This implementation is a bit faster than the other Mutex classes
* as it involved the least overhead. However, this slight increase in speed is
* gained by sacrificing the robustness provided by the other classes.
*
* A FastMutex has the useful property of not being interruptable; that is to say
* that acquire() and tryAcquire() will not throw Interrupted_Exceptions.
*
* @see Mutex
*
* <b>Scheduling</b>
*
* Scheduling is left to the operating systems and may vary.
*
* <b>Error Checking</b>
*
* No error checking is performed, this means there is the potential for deadlock.
*/
class ZTHREAD_API FastMutex : public Lockable, private NonCopyable {
FastLock* _lock;
public:
//! Create a FastMutex
FastMutex();
//! Destroy a FastMutex
virtual ~FastMutex();
/**
* Acquire exclusive access to the mutex. The calling thread will block until the
* lock can be acquired. No safety or state checks are performed.
*
* @pre The calling thread should <i>not</i> have previously acquired this lock.
* Deadlock will result if the same thread attempts to acquire the mutex more
* than once.
*
* @post The calling thread obtains the lock successfully if no exception is thrown.
* @exception Interrupted_Exception never thrown
*/
virtual void acquire();
/**
* Release exclusive access. No safety or state checks are performed.
*
* @pre the caller should have previously acquired this lock
*/
virtual void release();
/**
* Try to acquire exclusive access to the mutex. The calling thread will block until the
* lock can be acquired. No safety or state checks are performed.
*
* @pre The calling thread should <i>not</i> have previously acquired this lock.
* Deadlock will result if the same thread attempts to acquire the mutex more
* than once.
*
* @param timeout unused
* @return
* - <em>true</em> if the lock was acquired
* - <em>false</em> if the lock was acquired
*
* @post The calling thread obtains the lock successfully if no exception is thrown.
* @exception Interrupted_Exception never thrown
*/
virtual bool tryAcquire(unsigned long timeout);
}; /* FastMutex */
};
#endif // __ZTFASTMUTEX_H__

View file

@ -1,106 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTFASTRECURSIVEMUTEX_H__
#define __ZTFASTRECURSIVEMUTEX_H__
#include "zthread/Lockable.h"
#include "zthread/NonCopyable.h"
namespace ZThread {
class FastRecursiveLock;
/**
* @class FastRecursiveMutex
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-19T19:00:25-0400>
* @version 2.2.0
*
* A FastRecursiveMutex is a small fast implementation of a recursive, mutally exclusive
* Lockable object. This implementation is a bit faster than the other Mutex classes
* as it involved the least overhead. However, this slight increase in speed is
* gained by sacrificing the robustness provided by the other classes.
*
* A FastRecursiveMutex has the useful property of not being interruptable; that is to say
* that acquire() and tryAcquire() will not throw Interrupted_Exceptions.
*
* @see RecursiveMutex
*
* <b>Scheduling</b>
*
* Scheduling is left to the operating systems and may vary.
*
* <b>Error Checking</b>
*
* No error checking is performed, this means there is the potential for deadlock.
*/
class ZTHREAD_API FastRecursiveMutex : public Lockable, private NonCopyable {
FastRecursiveLock* _lock;
public:
//! Create a new FastRecursiveMutex
FastRecursiveMutex();
//! Destroy this FastRecursiveMutex
virtual ~FastRecursiveMutex();
/**
* Acquire exclusive access to the mutex. The calling thread will block until the
* lock can be acquired. No safety or state checks are performed. The calling thread
* may acquire the mutex nore than once.
*
* @post The calling thread obtains the lock successfully if no exception is thrown.
* @exception Interrupted_Exception never thrown
*/
virtual void acquire();
/**
* Release access. No safety or state checks are performed.
*
* @pre the caller should have previously acquired this lock at least once.
*/
virtual void release();
/**
* Try to acquire exclusive access to the mutex. The calling thread will block until the
* lock can be acquired. No safety or state checks are performed. The calling thread
* may acquire the mutex more than once.
*
* @param timeout unused
* @return
* - <em>true</em> if the lock was acquired
* - <em>false</em> if the lock was acquired
*
* @post The calling thread obtains the lock successfully if no exception is thrown.
* @exception Interrupted_Exception never thrown
*/
virtual bool tryAcquire(unsigned long timeout);
};
} // namespace ZThread
#endif // __ZTFASTRECURSIVEMUTEX_H__

View file

@ -1,511 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTGUARD_H__
#define __ZTGUARD_H__
#include "zthread/NonCopyable.h"
#include "zthread/Exceptions.h"
namespace ZThread {
//
// GuardLockingPolicyContract {
//
// createScope(lock_type&)
// bool createScope(lock_type&, unsigned long)
// destroyScope(lock_type&)
//
// }
//
/**
* @class LockHolder
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:55:42-0400>
* @version 2.2.0
*
* This is a simple base class for Guards class. It allows Guards
* that have compatible targets to refer to each others targets
* allowing for the construction of Guards that share the same lock
* but have different locking policies.
*/
template <class LockType>
class LockHolder {
LockType &_lock;
bool _enabled;
public:
template <class T>
LockHolder(T& t) : _lock(extract(t)._lock), _enabled(true) { }
LockHolder(LockHolder& holder) : _lock(holder._lock), _enabled(true) { }
LockHolder(LockType& lock) : _lock(lock), _enabled(true) { }
void disable() {
_enabled = false;
}
bool isDisabled() {
return !_enabled;
}
LockType& getLock() {
return _lock;
}
protected:
template <class T>
static LockHolder& extract(T& t) {
// Design and Evolution of C++, page 328
return (LockHolder&)(t);
}
};
/**
* @class CompoundScope
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:55:42-0400>
* @version 2.2.0
*
* Locking policy that aggregates two policies that share a target.
* It is not appropriate to use with any type of OverlappedScope
*/
template <class Scope1, class Scope2>
class CompoundScope {
public:
template <class LockType>
static void createScope(LockHolder<LockType>& l) {
Scope1::createScope(l);
Scope2::createScope(l);
}
template <class LockType>
static void createScope(LockHolder<LockType>& l, unsigned long ms) {
if(Scope1::createScope(l, ms))
if(!Scope2::createScope(l, ms)) {
Scope1::destroyScope(l);
return false;
}
return true;
}
template <class LockType>
static void destroyScope(LockHolder<LockType>& l) {
Scope1::destroyScope(l);
Scope2::destroyScope(l);
}
};
/**
* @class LockedScope
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:55:42-0400>
* @version 2.2.0
*
* Locking policy for Lockable objects. This policy acquire()s a Lockable
* when the protection scope is created, and it release()s a Lockable
* when the scope is destroyed.
*/
class LockedScope {
public:
/**
* A new protection scope is being created by l2, using an existing scope
* created by l1.
*
* @param lock1 LockType1& is the LockHolder that holds the desired lock
* @param lock2 LockType1& is the LockHolder that wants to share
template <class LockType1, class LockType2>
static void shareScope(LockHolder<LockType1>& l1, LockHolder<LockType2>& l2) {
l2.getLock().acquire();
}
*/
/**
* A new protection scope is being created.
*
* @param lock LockType& is a type of LockHolder.
*/
template <class LockType>
static bool createScope(LockHolder<LockType>& l, unsigned long ms) {
return l.getLock().tryAcquire(ms);
}
/**
* A new protection scope is being created.
*
* @param lock LockType& is a type of LockHolder.
*/
template <class LockType>
static void createScope(LockHolder<LockType>& l) {
l.getLock().acquire();
}
/**
* A protection scope is being destroyed.
*
* @param lock LockType& is a type of LockHolder.
*/
template <class LockType>
static void destroyScope(LockHolder<LockType>& l) {
l.getLock().release();
}
};
/**
* @class UnlockedScope
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:55:42-0400>
* @version 2.2.0
*
* Locking policy for Lockable objects. This policy release()s a Lockable
* when the protection scope is created, and it acquire()s a Lockable
* when the scope is destroyed.
*/
class UnlockedScope {
public:
/**
* A new protection scope is being created by l2, using an existing scope
* created by l1.
*
* @param lock1 LockType1& is the LockHolder that holds the desired lock
* @param lock2 LockType1& is the LockHolder that wants to share
*/
template <class LockType1, class LockType2>
static void shareScope(LockHolder<LockType1>& /*l1*/, LockHolder<LockType2>& l2) {
l2.getLock().release();
}
/**
* A new protection scope is being created.
*
* @param lock LockType& is a type of LockHolder.
template <class LockType>
static void createScope(LockHolder<LockType>& l) {
l.getLock().release();
}
*/
/**
* A protection scope is being destroyed.
*
* @param lock LockType& is a type of LockHolder.
*/
template <class LockType>
static void destroyScope(LockHolder<LockType>& l) {
l.getLock().acquire();
}
};
/**
* @class TimedLockedScope
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:55:42-0400>
* @version 2.2.0
*
* Locking policy that attempts to enterScope some resource
* in a certain amount of time using an tryEnterScope-relase protocol.
*/
template <int TimeOut>
class TimedLockedScope {
public:
/**
* Try to enterScope the given LockHolder.
*
* @param lock LockType& is a type of LockHolder.
*/
template <class LockType1, class LockType2>
static void shareScope(LockHolder<LockType1>& l1, LockHolder<LockType2>& l2) {
if(!l2.getLock().tryAcquire(TimeOut))
throw Timeout_Exception();
}
template <class LockType>
static void createScope(LockHolder<LockType>& l) {
if(!l.getLock().tryAcquire(TimeOut))
throw Timeout_Exception();
}
template <class LockType>
static void destroyScope(LockHolder<LockType>& l) {
l.getLock().release();
}
};
/**
* @class OverlappedScope
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:55:42-0400>
* @version 2.2.0
*
* Locking policy allows the effective scope of two locks to overlap
* by releasing and disabling one lock before its Guard does so.
*/
class OverlappedScope {
public:
template <class LockType1, class LockType2>
static void transferScope(LockHolder<LockType1>& l1, LockHolder<LockType2>& l2) {
l1.getLock().acquire();
l2.getLock().release();
l2.disable();
}
template <class LockType>
static void destroyScope(LockHolder<LockType>& l) {
l.getLock().release();
}
};
/**
* @class Guard
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:55:42-0400>
* @version 2.2.0
*
* Scoped locking utility. This template class can be given a Lockable
* synchronization object and can 'Guard' or serialize access to
* that method.
*
* For instance, consider a case in which a class or program have a
* Mutex object associated with it. Access can be serialized with a
* Guard as shown below.
*
* @code
*
* Mutex _mtx;
* void guarded() {
*
* Guard<Mutex> g(_mtx);
*
* }
*
* @endcode
*
* The Guard will lock the synchronization object when it is created and
* automatically unlock it when it goes out of scope. This eliminates
* common mistakes like forgetting to unlock your mutex.
*
* An alternative to the above example would be
*
* @code
*
* void guarded() {
*
* (Guard<Mutex>)(_mtx);
*
* }
*
* @endcode
*
* HOWEVER; using a Guard in this method is dangerous. Depending on your
* compiler an anonymous variable like this can go out of scope immediately
* which can result in unexpected behavior. - This is the case with MSVC
* and was the reason for introducing assertions into the Win32_MutexImpl
* to track this problem down
*
*/
template <class LockType, class LockingPolicy = LockedScope>
class Guard : private LockHolder<LockType>, private NonCopyable {
friend class LockHolder<LockType>;
public:
/**
* Create a Guard that enforces a the effective protection scope
* throughout the lifetime of the Guard object or until the protection
* scope is modified by another Guard.
*
* @param lock LockType the lock this Guard will use to enforce its
* protection scope.
* @post the protection scope may be ended prematurely
*/
Guard(LockType& lock) : LockHolder<LockType>(lock) {
LockingPolicy::createScope(*this);
};
/**
* Create a Guard that enforces a the effective protection scope
* throughout the lifetime of the Guard object or until the protection
* scope is modified by another Guard.
*
* @param lock LockType the lock this Guard will use to enforce its
* protection scope.
* @post the protection scope may be ended prematurely
*/
Guard(LockType& lock, unsigned long timeout) : LockHolder<LockType>(lock) {
if(!LockingPolicy::createScope(*this, timeout))
throw Timeout_Exception();
};
/**
* Create a Guard that shares the effective protection scope
* from the given Guard to this Guard.
*
* @param g Guard<U, V> guard that is currently enabled
* @param lock LockType the lock this Guard will use to enforce its
* protection scope.
*/
template <class U, class V>
Guard(Guard<U, V>& g) : LockHolder<LockType>(g) {
LockingPolicy::shareScope(*this, extract(g));
}
/**
* Create a Guard that shares the effective protection scope
* from the given Guard to this Guard.
*
* @param g Guard guard that is currently enabled
* @param lock LockType the lock this Guard will use to enforce its
* protection scope.
*/
Guard(Guard& g) : LockHolder<LockType>(g) {
LockingPolicy::shareScope(*this, g);
}
/**
* Create a Guard that transfers the effective protection scope
* from the given Guard to this Guard.
*
* @param g Guard<U, V> guard that is currently enabled
* @param lock LockType the lock this Guard will use to enforce its
* protection scope.
*/
template <class U, class V>
Guard(Guard<U, V>& g, LockType& lock) : LockHolder<LockType>(lock) {
LockingPolicy::transferScope(*this, extract(g));
}
/**
* Create a Guard that transfers the effective protection scope
* from the given Guard to this Guard.
*
* @param g Guard guard that is currently enabled
* @param lock LockType the lock this Guard will use to enforce its
* protection scope.
*/
Guard(Guard& g, LockType& lock) : LockHolder<LockType>(lock) {
LockingPolicy::transferScope(*this, g);
}
/**
* Unlock a given Lockable object with the destruction of this Guard
*/
~Guard() throw();
}; /* Guard */
template <class LockType, class LockingPolicy>
Guard<LockType, LockingPolicy>::~Guard() throw() {
try {
if(!this->isDisabled())
LockingPolicy::destroyScope(*this);
} catch (...) { /* ignore */ }
}
};
#endif // __ZTGUARD_H__

View file

@ -1,103 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __GUARDEDCLASS_H__
#define __GUARDEDCLASS_H__
#include "zthread/Guard.h"
#include "zthread/Mutex.h"
namespace ZThread {
/**
* @class GuardedClass
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-20T20:17:34-0400>
* @version 2.3.0
*
* A simple wrapper template that uses Guard's to provide
* serialized access to an objects member functions.
*/
template <class T, class LockType = Mutex>
class GuardedClass {
LockType _lock;
T* _ptr;
class TransferedScope {
public:
template <class LockType1, class LockType2>
static void shareScope(LockHolder<LockType1>& l1,
LockHolder<LockType2>& l2) {
l1.disable();
l2.getLock().acquire();
}
template <class LockType1>
static void createScope(LockHolder<LockType1>& l) {
// Don't acquire the lock when scope the Guard is created
}
template <class LockType1>
static void destroyScope(LockHolder<LockType1>& l) {
l.getLock().release();
}
};
class Proxy : Guard<LockType, TransferedScope> {
T* _object;
public:
Proxy(LockType& lock, T* object) :
Guard<LockType, TransferedScope>(lock), _object(object) { }
T* operator->() {
return _object;
}
};
GuardedClass();
GuardedClass& operator=(const GuardedClass&);
public:
GuardedClass(T* ptr) : _ptr(ptr) {}
~GuardedClass() {
if(_ptr)
delete _ptr;
}
Proxy operator->() {
Proxy p(_lock, _ptr);
return p;
}
};
} // namespace ZThread
#endif // __ZTGUARDEDCLASS_H__

View file

@ -1,96 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTLOCKABLE_H__
#define __ZTLOCKABLE_H__
#include "zthread/Exceptions.h"
namespace ZThread {
/**
* @class Lockable
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T10:33:32-0400>
* @version 2.3.0
*
* The Lockable interface defines a common method of adding general <i>acquire-release</i>
* semantics to an object. An <i>acquire-release</i> protocol does not necessarily imply
* exclusive access.
*/
class Lockable {
public:
//! Destroy a Lockable object.
virtual ~Lockable() {}
/**
* Acquire the Lockable object.
*
* This method may or may not block the caller for an indefinite amount
* of time. Those details are defined by specializations of this class.
*
* @exception Interrupted_Exception thrown if the calling thread is interrupted before
* the operation completes.
*
* @post The Lockable is acquired only if no exception was thrown.
*/
virtual void acquire() = 0;
/**
* Attempt to acquire the Lockable object.
*
* This method may or may not block the caller for a definite amount
* of time. Those details are defined by specializations of this class;
* however, this method includes a timeout value that can be used to
* limit the maximum amount of time that a specialization <i>could</i> block.
*
* @param timeout - maximum amount of time (milliseconds) this method could block
*
* @return
* - <em>true</em> if the operation completes and the Lockable is acquired before
* the timeout expires.
* - <em>false</em> if the operation times out before the Lockable can be acquired.
*
* @exception Interrupted_Exception thrown if the calling thread is interrupted before
* the operation completes.
*
* @post The Lockable is acquired only if no exception was thrown.
*/
virtual bool tryAcquire(unsigned long timeout) = 0;
/**
* Release the Lockable object.
*
* This method may or may not block the caller for an indefinite amount
* of time. Those details are defined by specializations of this class.
*
* @post The Lockable is released only if no exception was thrown.
*/
virtual void release() = 0;
};
} // namespace ZThread
#endif // __ZTLOCKABLE_H__

View file

@ -1,197 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTLOCKEDQUEUE_H__
#define __ZTLOCKEDQUEUE_H__
#include "zthread/Guard.h"
#include "zthread/Queue.h"
#include <deque>
namespace ZThread {
/**
* @class LockedQueue
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T11:42:33-0400>
* @version 2.3.0
*
* A LockedQueue is the simple Queue implementation that provides
* serialized access to the values added to it.
*/
template <class T, class LockType, typename StorageType=std::deque<T> >
class LockedQueue : public Queue<T> {
//! Serialize access to the Queue
LockType _lock;
//! Storage backing the queue
StorageType _queue;
//! Cancellation flag
volatile bool _canceled;
public:
//! Create a LockedQueue
LockedQueue() : _canceled(false) {}
//! Destroy a LockedQueue
virtual ~LockedQueue() { }
/**
* @see Queue::add(const T& item)
*/
virtual void add(const T& item) {
Guard<LockType> g(_lock);
if(_canceled)
throw Cancellation_Exception();
_queue.push_back(item);
}
/**
* @see Queue::add(const T& item, unsigned long timeout)
*/
virtual bool add(const T& item, unsigned long timeout) {
try {
Guard<LockType> g(_lock, timeout);
if(_canceled)
throw Cancellation_Exception();
_queue.push_back(item);
} catch(Timeout_Exception&) { return false; }
return true;
}
/**
* @see Queue::next()
*/
virtual T next() {
Guard<LockType> g(_lock);
if(_queue.empty() && _canceled)
throw Cancellation_Exception();
if(_queue.empty())
throw NoSuchElement_Exception();
T item = _queue.front();
_queue.pop_front();
return item;
}
/**
* @see Queue::next(unsigned long timeout)
*/
virtual T next(unsigned long timeout) {
Guard<LockType> g(_lock, timeout);
if(_queue.empty() && _canceled)
throw Cancellation_Exception();
if(_queue.empty())
throw NoSuchElement_Exception();
T item = _queue.front();
_queue.pop_front();
return item;
}
virtual T front()
{
Guard<LockType> g(_lock);
if(_queue.empty())
throw NoSuchElement_Exception();
return _queue.front();
}
/**
* @see Queue::cancel()
*/
virtual void cancel() {
Guard<LockType> g(_lock);
_canceled = true;
}
/**
* @see Queue::isCanceled()
*/
virtual bool isCanceled() {
// Faster check since the queue will not become un-canceled
if(_canceled)
return true;
Guard<LockType> g(_lock);
return _canceled;
}
/**
* @see Queue::size()
*/
virtual size_t size() {
Guard<LockType> g(_lock);
return _queue.size();
}
/**
* @see Queue::size(unsigned long timeout)
*/
virtual size_t size(unsigned long timeout) {
Guard<LockType> g(_lock, timeout);
return _queue.size();
}
}; /* LockedQueue */
} // namespace ZThread
#endif // __ZTLOCKEDQUEUE_H__

View file

@ -1,345 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTMONITOREDQUEUE_H__
#define __ZTMONITOREDQUEUE_H__
#include "zthread/Condition.h"
#include "zthread/Guard.h"
#include "zthread/Queue.h"
#include <deque>
namespace ZThread {
/**
* @class MonitoredQueue
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T20:23:28-0400>
* @version 2.3.0
*
* A MonitoredQueue is a Queue implementation that provides serialized access to the
* items added to it.
*
* - Threads calling the empty() methods will be blocked until the BoundedQueue becomes empty.
* - Threads calling the next() methods will be blocked until the BoundedQueue has a value to
* return.
*
* @see Queue
*/
template <class T, class LockType, typename StorageType=std::deque<T> >
class MonitoredQueue : public Queue<T>, public Lockable {
//! Serialize access
LockType _lock;
//! Signaled on not empty
Condition _notEmpty;
//! Signaled on empty
Condition _isEmpty;
//! Storage backing the queue
StorageType _queue;
//! Cancellation flag
volatile bool _canceled;
public:
//! Create a new MonitoredQueue
MonitoredQueue()
: _notEmpty(_lock), _isEmpty(_lock), _canceled(false) {}
//! Destroy a MonitoredQueue, delete remaining items
virtual ~MonitoredQueue() { }
/**
* Add a value to this Queue.
*
* @param item value to be added to the Queue
*
* @exception Cancellation_Exception thrown if this Queue has been canceled.
* @exception Interrupted_Exception thrown if the thread was interrupted while waiting
* to add a value
*
* @pre The Queue should not have been canceled prior to the invocation of this function.
* @post If no exception is thrown, a copy of <i>item</i> will have been added to the Queue.
*
* @see Queue::add(const T& item)
*/
virtual void add(const T& item) {
Guard<LockType> g(_lock);
// Allow no further additions in the canceled state
if(_canceled)
throw Cancellation_Exception();
_queue.push_back( item );
_notEmpty.signal(); // Wake one waiter
}
/**
* Add a value to this Queue.
*
* @param item value to be added to the Queue
* @param timeout maximum amount of time (milliseconds) this method may block
* the calling thread.
*
* @return
* - <em>true</em> if a copy of <i>item</i> can be added before <i>timeout</i>
* milliseconds elapse.
* - <em>false</em> otherwise.
*
* @exception Cancellation_Exception thrown if this Queue has been canceled.
* @exception Interrupted_Exception thrown if the thread was interrupted while waiting
* to add a value
*
* @pre The Queue should not have been canceled prior to the invocation of this function.
* @post If no exception is thrown, a copy of <i>item</i> will have been added to the Queue.
*
* @see Queue::add(const T& item, unsigned long timeout)
*/
virtual bool add(const T& item, unsigned long timeout) {
try {
Guard<LockType> g(_lock, timeout);
if(_canceled)
throw Cancellation_Exception();
_queue.push_back(item);
_notEmpty.signal();
} catch(Timeout_Exception&) { return false; }
return true;
}
/**
* Retrieve and remove a value from this Queue.
*
* If invoked when there are no values present to return then the calling thread
* will be blocked until a value arrives in the Queue.
*
* @return <em>T</em> next available value
*
* @exception Cancellation_Exception thrown if this Queue has been canceled.
* @exception Interrupted_Exception thrown if the thread was interrupted while waiting
* to retrieve a value
*
* @pre The Queue should not have been canceled prior to the invocation of this function.
* @post The value returned will have been removed from the Queue.
*/
virtual T next() {
Guard<LockType> g(_lock);
while (_queue.empty() && !_canceled)
_notEmpty.wait();
if(_queue.empty()) // Queue canceled
throw Cancellation_Exception();
T item = _queue.front();
_queue.pop_front();
if(_queue.empty()) // Wake empty waiters
_isEmpty.broadcast();
return item;
}
/**
* Retrieve and remove a value from this Queue.
*
* If invoked when there are no values present to return then the calling thread
* will be blocked until a value arrives in the Queue.
*
* @param timeout maximum amount of time (milliseconds) this method may block
* the calling thread.
*
* @return <em>T</em> next available value
*
* @exception Cancellation_Exception thrown if this Queue has been canceled.
* @exception Timeout_Exception thrown if the timeout expires before a value
* can be retrieved.
*
* @pre The Queue should not have been canceled prior to the invocation of this function.
* @post The value returned will have been removed from the Queue.
*/
virtual T next(unsigned long timeout) {
Guard<LockType> g(_lock, timeout);
while(_queue.empty() && !_canceled) {
if(!_notEmpty.wait(timeout))
throw Timeout_Exception();
}
if( _queue.empty()) // Queue canceled
throw Cancellation_Exception();
T item = _queue.front();
_queue.pop_front();
if(_queue.empty()) // Wake empty waiters
_isEmpty.broadcast();
return item;
}
/**
* Cancel this queue.
*
* @post Any threads blocked by a next() function will throw a Cancellation_Exception.
*
* @see Queue::cancel()
*/
virtual void cancel() {
Guard<LockType> g(_lock);
_canceled = true;
_notEmpty.broadcast(); // Wake next() waiters
}
/**
* @see Queue::isCanceled()
*/
virtual bool isCanceled() {
// Faster check since the queue will not become un-canceled
if(_canceled)
return true;
Guard<LockType> g(_lock);
return _canceled;
}
/**
* @see Queue::size()
*/
virtual size_t size() {
Guard<LockType> g(_lock);
return _queue.size();
}
/**
* @see Queue::size(unsigned long timeout)
*/
virtual size_t size(unsigned long timeout) {
Guard<LockType> g(_lock, timeout);
return _queue.size();
}
/**
* Test whether any values are available in this Queue.
*
* The calling thread is blocked until there are no values present
* in the Queue.
*
* @return
* - <em>true</em> if there are no values available.
* - <em>false</em> if there <i>are</i> values available.
*
* @see Queue::empty()
*/
virtual bool empty() {
Guard<LockType> g(_lock);
while(!_queue.empty()) // Wait for an empty signal
_isEmpty.wait();
return true;
}
/**
* Test whether any values are available in this Queue.
*
* The calling thread is blocked until there are no values present
* in the Queue.
*
* @param timeout maximum amount of time (milliseconds) this method may block
* the calling thread.
*
* @return
* - <em>true</em> if there are no values available.
* - <em>false</em> if there <i>are</i> values available.
*
* @exception Timeout_Exception thrown if <i>timeout</i> milliseconds
* expire before a value becomes available
*
* @see Queue::empty()
*/
virtual bool empty(unsigned long timeout) {
Guard<LockType> g(_lock, timeout);
while(!_queue.empty()) // Wait for an empty signal
_isEmpty.wait(timeout);
return true;
}
public:
virtual void acquire() {
_lock.acquire();
}
virtual bool tryAcquire(unsigned long timeout) {
return _lock.tryAcquire(timeout);
}
virtual void release() {
_lock.release();
}
}; /* MonitoredQueue */
} // namespace ZThread
#endif // __ZTMONITOREDQUEUE_H__

View file

@ -1,135 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTMUTEX_H__
#define __ZTMUTEX_H__
#include "zthread/Lockable.h"
#include "zthread/NonCopyable.h"
namespace ZThread {
class FifoMutexImpl;
/**
* @class Mutex
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T19:35:28-0400>
* @version 2.2.1
*
* A Mutex is used to provide serialized (one thread at a time) access to some portion
* of code. This is accomplished by attempting to acquire the Mutex before entering that
* piece of code, and by releasing the Mutex when leaving that region. It is a non-reentrant,
* MUTual EXclusion Lockable object.
*
* @see Guard
*
* <b>Scheduling</b>
*
* Threads competing to acquire() a Mutex are granted access in FIFO order.
*
* <b>Error Checking</b>
*
* A Mutex will throw a Deadlock_Exception if an attempt to acquire a Mutex more
* than once is made from the context of the same thread.
*
* A Mutex will throw an InvalidOp_Exception if an attempt to release a Mutex is
* made from the context of a thread that does not currently own that Mutex.
*/
class ZTHREAD_API Mutex : public Lockable, private NonCopyable {
FifoMutexImpl* _impl;
public:
//! Create a new Mutex.
Mutex();
//! Destroy this Mutex.
virtual ~Mutex();
/**
* Acquire a Mutex, possibly blocking until either the current owner of the
* Mutex releases it or until an exception is thrown.
*
* Only one thread may acquire() the Mutex at any given time.
*
* @exception Interrupted_Exception thrown when the calling thread is interrupted.
* A thread may be interrupted at any time, prematurely ending any wait.
* @exception Deadlock_Exception thrown when the same thread attempts to acquire
* a Mutex more than once, without having first release()ed it.
*
* @pre the calling thread must not have already acquired Mutex
*
* @post the calling thread successfully acquired Mutex only if no exception
* was thrown.
*
* @see Lockable::acquire()
*/
virtual void acquire();
/**
* Acquire a Mutex, possibly blocking until the current owner of the
* Mutex releases it, until an exception is thrown or until the given amount
* of time expires.
*
* Only one thread may acquire the Mutex at any given time.
*
* @param timeout maximum amount of time (milliseconds) this method could block
* @return
* - <em>true</em> if the lock was acquired
* - <em>false</em> if the lock was acquired
*
* @exception Interrupted_Exception thrown when the calling thread is interrupted.
* A thread may be interrupted at any time, prematurely ending any wait.
* @exception Deadlock_Exception thrown when the same thread attempts to acquire
* a Mutex more than once, without having first released it.
*
* @pre the calling thread must not have already acquired Mutex
*
* @post the calling thread successfully acquired Mutex only if no exception
* was thrown.
*
* @see Lockable::tryAcquire(unsigned long timeout)
*/
virtual bool tryAcquire(unsigned long timeout);
/**
* Release a Mutex allowing another thread to acquire it.
*
* @exception InvalidOp_Exception - thrown if there is an attempt to release is
* a Mutex that was not owner by the calling thread.
*
* @pre the calling thread must have first acquired the Mutex.
* @post the calling thread successfully released Mutex only if no exception
* was thrown.
*
* @see Lockable::release()
*/
virtual void release();
};
} // namespace ZThread
#endif // __ZTMUTEX_H__

View file

@ -1,60 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTNONCOPYABLE_H__
#define __ZTNONCOPYABLE_H__
namespace ZThread {
/**
* @class NonCopyable
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T19:36:00-0400>
* @version 2.2.11
*
* Some objects kind of objects should not be copied. This is particularly true
* of objects involved in providing mutually exclusive access to something
* (e.g. Mutexes, Queues, Semaphores, etc.)
*
* Based on Dave Abrahams contribution to the Boost library.
*/
class NonCopyable {
//! Restrict the copy constructor
NonCopyable(const NonCopyable&);
//! Restrict the assignment operator
const NonCopyable& operator=(const NonCopyable&);
protected:
//! Create a NonCopyable object
NonCopyable() { }
//! Destroy a NonCopyable object
~NonCopyable() { }
}; /* NonCopyable */
} // namespace ZThread
#endif // __ZTNONCOPYABLE_H__

View file

@ -1,178 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTPOOLEXECUTOR_H__
#define __ZTPOOLEXECUTOR_H__
#include "zthread/Executor.h"
#include "zthread/CountedPtr.h"
#include "zthread/Thread.h"
namespace ZThread {
namespace { class ExecutorImpl; }
/**
* @class PoolExecutor
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T22:41:07-0400>
* @version 2.3.0
*
* A PoolExecutor spawns a set of threads that are used to run tasks
* that are submitted in parallel. A PoolExecutor supports the following
* optional operations,
*
* - <em>cancel</em>()ing a PoolExecutor will cause it to stop accepting
* new tasks.
*
* - <em>interrupt</em>()ing a PoolExecutor will cause the any thread running
* a task which was submitted prior to the invocation of this function to
* be interrupted during the execution of that task.
*
* - <em>wait</em>()ing on a PoolExecutor will block the calling thread
* until all tasks that were submitted prior to the invocation of this function
* have completed.
*
* @see Executor.
*/
class PoolExecutor : public Executor {
//! Reference to the internal implementation
CountedPtr< ExecutorImpl > _impl;
//! Cancellation task
Task _shutdown;
public:
/**
* Create a PoolExecutor
*
* @param n number of threads to service tasks with
*/
PoolExecutor(size_t n);
//! Destroy a PoolExecutor
virtual ~PoolExecutor();
/**
* Invoking this function causes each task that had been submitted prior to
* this function to be interrupted. Tasks submitted after the invocation of
* this function are unaffected.
*
* @post Any task submitted prior to the invocation of this function will be
* run in the context of an interrupted thread.
* @post Any thread already executing a task which was submitted prior to the
* invocation of this function will be interrupted.
*/
virtual void interrupt();
/**
* Alter the number of threads being used to execute submitted tasks.
*
* @param n number of worker threads.
*
* @pre <i>n</i> must be greater than 0.
* @post <i>n</i> threads will be executing tasks submitted to this executor.
*
* @exception InvalidOp_Exception thrown if the new number of threads
* <i>n</i> is less than 1.
*/
void size(size_t n);
/**
* Get the current number of threads being used to execute submitted tasks.
*
* @return n number of worker threads.
*/
size_t size();
/**
* Submit a task to this Executor.
*
* This will not block the calling thread very long. The submitted task will
* be executed at some later point by another thread.
*
* @param task Task to be run by a thread managed by this executor
*
* @pre The Executor should have been canceled prior to this invocation.
* @post The submitted task will be run at some point in the future by this Executor.
*
* @exception Cancellation_Exception thrown if the Executor was canceled prior to
* the invocation of this function.
*
* @see PoolExecutor::cancel()
* @see Executor::execute(const Task& task)
*/
virtual void execute(const Task& task);
/**
* @see Cancelable::cancel()
*/
virtual void cancel();
/**
* @see Cancelable::isCanceled()
*/
virtual bool isCanceled();
/**
* Block the calling thread until all tasks submitted prior to this invocation
* complete.
*
* @exception Interrupted_Exception thrown if the calling thread is interrupted
* before the set of tasks being wait for can complete.
*
* @see Waitable::wait()
*/
virtual void wait();
/**
* Block the calling thread until all tasks submitted prior to this invocation
* complete or until the calling thread is interrupted.
*
* @param timeout maximum amount of time, in milliseconds, to wait for the
* currently submitted set of Tasks to complete.
*
* @exception Interrupted_Exception thrown if the calling thread is interrupted
* before the set of tasks being wait for can complete.
*
* @return
* - <em>true</em> if the set of tasks being wait for complete before
* <i>timeout</i> milliseconds elapse.
* - <em>false</em> otherwise.
*
* @see Waitable::wait(unsigned long timeout)
*/
virtual bool wait(unsigned long timeout);
}; /* PoolExecutor */
} // namespace ZThread
#endif // __ZTPOOLEXECUTOR_H__

View file

@ -1,39 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTPRIORITY_H__
#define __ZTPRIORITY_H__
namespace ZThread {
//! Priorities
typedef enum {
Low,
Medium = Low + 1,
High = Low + 2
} Priority;
}
#endif // __ZTPRIORITY_H__

View file

@ -1,89 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTPRIORITYCONDITION_H__
#define __ZTPRIORITYCONDITION_H__
#include "zthread/Lockable.h"
#include "zthread/NonCopyable.h"
#include "zthread/Waitable.h"
namespace ZThread {
class PriorityConditionImpl;
/**
* @class PriorityCondition
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:35:28-0400>
* @version 2.2.1
*
* A PriorityCondition is a Condition that is sensitive to thread priority.
*
* @see Condition
*
* <b>Scheduling</b>
*
* Threads blocked on a PriorityCondition are resumed in priority order, highest priority
* first
*/
class ZTHREAD_API PriorityCondition : public Waitable, private NonCopyable {
PriorityConditionImpl* _impl;
public:
/**
* @see Condition::Condition(Lockable& l)
*/
PriorityCondition(Lockable& l);
/**
* @see Condition::~Condition()
*/
~PriorityCondition();
/**
* @see Condition::signal()
*/
void signal();
/**
* @see Condition::broadcast()
*/
void broadcast();
/**
* @see Condition::wait()
*/
virtual void wait();
/**
* @see Condition::wait(unsigned long timeout)
*/
virtual bool wait(unsigned long timeout);
};
} // namespace ZThread
#endif // __ZTPRIORITYCONDITION_H__

View file

@ -1,93 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTPRIORITYINHERITANCEMUTEX_H__
#define __ZTPRIORITYINHERITANCEMUTEX_H__
#include "zthread/Lockable.h"
#include "zthread/NonCopyable.h"
namespace ZThread {
class PriorityInheritanceMutexImpl;
/**
* @class PriorityInheritanceMutex
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T19:37:36-0400>
* @version 2.2.1
*
* A PriorityInheritanceMutex is similar to a PriorityMutex, it is a non-reentrant,
* priority sensitive MUTual EXclusion Lockable object. It differs only in its
* scheduling policy.
*
* @see PriorityMutex
*
* <b>Scheduling</b>
*
* Threads competing to acquire() a PriorityInheritanceMutex are granted access in
* order of priority. Threads with a higher priority will be given access first.
*
* When a higher priority thread tries to acquire() a PriorityInheritanceMutex and is
* about to be blocked by a lower priority thread that has already acquire()d it, the
* lower priority thread will temporarily have its effective priority raised to that
* of the higher priority thread until it release()s the mutex; at which point its
* previous priority will be restored.
*/
class ZTHREAD_API PriorityInheritanceMutex : public Lockable, private NonCopyable {
PriorityInheritanceMutexImpl* _impl;
public:
/**
* @see Mutex::Mutex()
*/
PriorityInheritanceMutex();
/**
* @see Mutex::~Mutex()
*/
virtual ~PriorityInheritanceMutex();
/**
* @see Mutex::acquire()
*/
virtual void acquire();
/**
* @see Mutex::tryAcquire(unsigned long timeout)
*/
virtual bool tryAcquire(unsigned long timeout);
/**
* @see Mutex::release()
*/
virtual void release();
};
} // namespace ZThread
#endif // __ZTPRIORITYINHERITANCEMUTEX_H__

View file

@ -1,86 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTPRIORITYMUTEX_H__
#define __ZTPRIORITYMUTEX_H__
#include "zthread/Lockable.h"
#include "zthread/NonCopyable.h"
namespace ZThread {
class PriorityMutexImpl;
/**
* @class PriorityMutex
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:35:46-0400>
* @version 2.2.1
*
* A PriorityMutex is similar to a Mutex, with exception that a PriorityMutex
* has a difference scheduling policy. It is a non-reentrant, priority sensitive
* MUTual EXclusion Lockable object.
*
* @see Mutex
*
* <b>Scheduling</b>
*
* Threads competing to acquire() a Mutex are granted access in order of priority. Threads
* with a higher priority will be given access first.
*/
class ZTHREAD_API PriorityMutex : public Lockable, private NonCopyable {
PriorityMutexImpl* _impl;
public:
/**
* @see Mutex::Mutex()
*/
PriorityMutex();
/**
* @see Mutex::~Mutex()
*/
virtual ~PriorityMutex();
/**
* @see Mutex::acquire()
*/
virtual void acquire();
/**
* @see Mutex::tryAcquire(unsigned long timeout)
*/
virtual bool tryAcquire(unsigned long timeout);
/**
* @see Mutex::release()
*/
virtual void release();
};
} // namespace ZThread
#endif // __ZTPRIORITYMUTEX_H__

View file

@ -1,111 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTPRIORITYSEMAPHORE_H__
#define __ZTPRIORITYSEMAPHORE_H__
#include "zthread/Lockable.h"
#include "zthread/NonCopyable.h"
namespace ZThread {
class PrioritySemaphoreImpl;
/**
* @class PrioritySemaphore
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T15:36:07-0400>
* @version 2.2.1
*
* A PrioritySemaphore operates in the same way as a Semaphore. Its an owner-less
* Lockable object that is sensitive to priority.
*
* <b>Scheduling</b>
*
* Threads blocked on a PrioritySemaphore are resumed in priority order, highest
* priority first.
*
* <b>Error Checking</b>
*
* An attempt to increase a PrioritySemaphore beyond its maximum value will result in
* an InvalidOp_Exception.
*
* @see Semaphore
*/
class ZTHREAD_API PrioritySemaphore : public Lockable, private NonCopyable {
PrioritySemaphoreImpl* _impl;
public:
/**
* @see Semaphore::Semaphore(int count, unsigned int maxCount)
*/
PrioritySemaphore(int count = 1, unsigned int maxCount = 1);
/**
* @see Semaphore::~Semaphore()
*/
virtual ~PrioritySemaphore();
/**
* @see Semaphore::wait()
*/
void wait();
/**
* @see Semaphore::tryWait(unsigned long)
*/
bool tryWait(unsigned long);
/**
* @see Semaphore::post()
*/
void post();
/**
* @see Semaphore::count()
*/
virtual int count();
/**
* @see Semaphore::tryAcquire(unsigned long timeout)
*/
virtual bool tryAcquire(unsigned long timeout);
/**
* @see Semaphore::acquire()
*/
virtual void acquire();
/**
* @see Semaphore::release()
*/
virtual void release();
};
} // namespace ZThread
#endif // __ZTPRIORITYSEMAPHORE_H__

View file

@ -1,189 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTQUEUE_H__
#define __ZTQUEUE_H__
#include "zthread/Cancelable.h"
#include "zthread/NonCopyable.h"
namespace ZThread {
/**
* @class Queue
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T11:32:42-0400>
* @version 2.3.0
*
* A Queue defines an interface for a value-oriented collection objects (similar to
* STL collections).
*/
template <typename T>
class Queue : public Cancelable, private NonCopyable {
public:
//! Destroy a Queue
virtual ~Queue() { }
/**
* Add an object to this Queue.
*
* @param item value to be added to the Queue
*
* @exception Cancellation_Exception thrown if this Queue has been canceled.
*
* @pre The Queue should not have been canceled prior to the invocation of this function.
* @post If no exception is thrown, a copy of <i>item</i> will have been added to the Queue.
*/
virtual void add(const T& item) = 0;
/**
* Add an object to this Queue.
*
* @param item value to be added to the Queue
* @param timeout maximum amount of time (milliseconds) this method may block
* the calling thread.
*
* @return
* - <em>true</em> if a copy of <i>item</i> can be added before <i>timeout</i>
* milliseconds elapse.
* - <em>false</em> otherwise.
*
* @exception Cancellation_Exception thrown if this Queue has been canceled.
*
* @pre The Queue should not have been canceled prior to the invocation of this function.
* @post If this function returns true a copy of <i>item</i> will have been added to the Queue.
*/
virtual bool add(const T& item, unsigned long timeout) = 0;
/**
* Retrieve and remove a value from this Queue.
*
* @return <em>T</em> next available value
*
* @exception Cancellation_Exception thrown if this Queue has been canceled.
*
* @pre The Queue should not have been canceled prior to the invocation of this function.
* @post The value returned will have been removed from the Queue.
*/
virtual T next() = 0;
/**
* Retrieve and remove a value from this Queue.
*
* @param timeout maximum amount of time (milliseconds) this method may block
* the calling thread.
*
* @return <em>T</em> next available value
*
* @exception Cancellation_Exception thrown if this Queue has been canceled.
* @exception Timeout_Exception thrown if the timeout expires before a value
* can be retrieved.
*
* @pre The Queue should not have been canceled prior to the invocation of this function.
* @post The value returned will have been removed from the Queue.
*/
virtual T next(unsigned long timeout) = 0;
/**
* Canceling a Queue disables it, disallowing further additions. Values already
* present in the Queue can still be retrieved and are still available through
* the next() methods.
*
* Canceling a Queue more than once has no effect.
*
* @post The next() methods will continue to return objects until
* the Queue has been emptied.
* @post Once emptied, the next() methods will throw a Cancellation_Exception.
* @post The add() methods will throw a Cancellation_Exceptions from this point on.
*/
virtual void cancel() = 0;
/**
* Count the values present in this Queue.
*
* @return <em>size_t</em> number of elements available in the Queue.
*/
virtual size_t size() = 0;
/**
* Count the values present in this Queue.
*
* @param timeout maximum amount of time (milliseconds) this method may block
* the calling thread.
*
* @return <em>size_t</em> number of elements available in the Queue.
*
* @exception Timeout_Exception thrown if <i>timeout</i> milliseconds
* expire before a value becomes available
*/
virtual size_t size(unsigned long timeout) = 0;
/**
* Test whether any values are available in this Queue.
*
* @return
* - <em>true</em> if there are no values available.
* - <em>false</em> if there <i>are</i> values available.
*/
virtual bool empty() {
try {
return size() == 0;
} catch(Cancellation_Exception&) { }
return true;
}
/**
* Test whether any values are available in this Queue.
*
* @param timeout maximum amount of time (milliseconds) this method may block
* the calling thread.
*
* @return
* - <em>true</em> if there are no values available.
* - <em>false</em> if there <i>are</i> values available.
*
* @exception Timeout_Exception thrown if <i>timeout</i> milliseconds
* expire before a value becomes available
*/
virtual bool empty(unsigned long timeout) {
try {
return size(timeout) == 0;
} catch(Cancellation_Exception&) { }
return true;
}
}; /* Queue */
} // namespace ZThread
#endif // __ZTQUEUE_H__

View file

@ -1,80 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTREADWRITELOCK_H__
#define __ZTREADWRITELOCK_H__
#include "zthread/Lockable.h"
#include "zthread/NonCopyable.h"
namespace ZThread {
/**
* @class ReadWriteLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T10:17:31-0400>
* @version 2.2.7
*
* A ReadWriteLock provides a set of coordinated Lockable objects that can be used to
* guard an object; One for read-only access, and another for read-write access.
*
* @see BiasedReadWriteLock
* @see FairReadWriteLock
*/
class ReadWriteLock : public NonCopyable {
public:
/**
* Create a ReadWriteLock
*
* @exception Initialization_Exception thrown if resources could not be
* allocated for this object.
*/
ReadWriteLock() {}
//! Destroy this ReadWriteLock
virtual ~ReadWriteLock() {}
/**
* Get a reference to the read-only Lockable.
*
* @return <em>Lockable&</em> reference to a Lockable that provides read-only
* access.
*/
virtual Lockable& getReadLock() = 0;
/**
* Get a reference to the read-write Lockable.
*
* @return <em>Lockable&</em> reference to a Lockable that provides read-write
* access.
*/
virtual Lockable& getWriteLock() = 0;
}; /* ReadWriteLock */
}; // __ZTREADWRITELOCK_H__
#endif

View file

@ -1,123 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTRECURSIVEMUTEX_H__
#define __ZTRECURSIVEMUTEX_H__
#include "zthread/Lockable.h"
#include "zthread/NonCopyable.h"
namespace ZThread {
class RecursiveMutexImpl;
/**
* @class RecursiveMutex
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:51:33-0400>
* @version 2.2.1
*
* A RecursiveMutex is a recursive, MUTual EXclusion Lockable object. It is
* recursive because it can be acquire()d and release()d more than once
* by the same thread, instead of causing a Deadlock_Exception.
*
* @see Mutex
* @see Guard
*
* <b>Scheduling</b>
*
* Threads competing to acquire() a Mutex are granted access in FIFO order.
*
* <b>Error Checking</b>
*
* A Mutex will throw an InvalidOp_Exception if an attempt to release() a Mutex is
* made from the context of a thread that does not currently own that Mutex.
*/
class ZTHREAD_API RecursiveMutex : public Lockable, private NonCopyable {
RecursiveMutexImpl* _impl;
public:
//! Create a new RecursiveMutex.
RecursiveMutex();
//! Destroy this RecursiveMutex.
virtual ~RecursiveMutex();
/**
* Acquire a RecursiveMutex, possibly blocking until the the current owner of the
* releases it or until an exception is thrown.
*
* Only one thread may acquire the RecursiveMutex at any given time.
* The same thread may acquire a RecursiveMutex multiple times.
*
* @exception Interrupted_Exception thrown when the calling thread is interrupted.
* A thread may be interrupted at any time, prematurely ending any wait.
*
* @post the calling thread successfully acquire ed RecursiveMutex only if no exception
* was thrown.
*
* @see Lockable::acquire()
*/
virtual void acquire();
/**
* Acquire a RecursiveMutex, possibly blocking until the the current owner
* releases it, until an exception is thrown or until the given amount
* of time expires.
*
* Only one thread may acquire the RecursiveMutex at any given time.
* The same thread may acquire a RecursiveMutex multiple times.
*
* @param timeout maximum amount of time (milliseconds) this method could block
* @return
* - <em>true</em> if the lock was acquired
* - <em>false</em> if the lock was acquired
*
* @exception Interrupted_Exception thrown when the calling thread is interrupted.
* A thread may be interrupted at any time, prematurely ending any wait.
*
* @post the calling thread successfully acquired RecursiveMutex only if no exception
* was thrown.
*
* @see Lockable::tryAcquire(unsigned long timeout)
*/
virtual bool tryAcquire(unsigned long timeout);
/**
* Release exclusive access. No safety or state checks are performed.
*
* @pre This should not be called more times than the acquire() method was
* called.
*
* @see Lockable::release()
*/
virtual void release();
};
} // namespace ZThread
#endif // __ZTRECURSIVEMUTEX_H__

View file

@ -1,58 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTRUNNABLE_H__
#define __ZTRUNNABLE_H__
#include "zthread/Config.h"
namespace ZThread {
/**
* @class Runnable
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:45:35-0400>
* @version 2.2.11
*
* Encapsulates a Runnable task.
*/
class Runnable {
public:
/**
* Runnables should never throw in their destructors
*/
virtual ~Runnable() {}
/**
* Task to be performed in another thread of execution
*/
virtual void run() = 0;
};
}
#endif // __ZTRUNNABLE_H__

View file

@ -1,150 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTSEMAPHORE_H__
#define __ZTSEMAPHORE_H__
#include "zthread/Lockable.h"
#include "zthread/NonCopyable.h"
namespace ZThread {
class FifoSemaphoreImpl;
/**
* @class Semaphore
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T15:28:01-0400>
* @version 2.2.1
*
* A Semaphore is an owner-less Lockable object. Its probably best described as
* a set of 'permits'. A Semaphore is initialized with an initial count and
* a maximum count, these would correspond to the number of 'permits' currently
* available and the number of' permits' in total.
*
* - Acquiring the Semaphore means taking a permit, but if there are none
* (the count is 0) the Semaphore will block the calling thread.
*
* - Releasing the Semaphore means returning a permit, unblocking a thread
* waiting for one.
*
* A Semaphore with an initial value of 1 and maximum value of 1 will act as
* a Mutex.
*
* Threads blocked on a Semaphore are resumed in FIFO order.
*
*/
class ZTHREAD_API Semaphore : public Lockable, private NonCopyable {
FifoSemaphoreImpl* _impl;
public:
/**
* Create a new Semaphore.
*
* @param count initial count
* @param maxCount maximum count
*/
Semaphore(int count = 1, unsigned int maxCount = 1);
//! Destroy the Semaphore
virtual ~Semaphore();
/**
* <i>Provided to reflect the traditional Semaphore semantics</i>
*
* @see acquire()
*/
void wait();
/**
* <i>Provided to reflect the traditional Semaphore semantics</i>
*
* @see tryAcquire(unsigned long timeout)
*/
bool tryWait(unsigned long timeout);
/**
* <i>Provided to reflect the traditional Semaphore semantics</i>
*
* @see release()
*/
void post();
/**
* Get the current count of the semaphore.
*
* This value may change immediately after this function returns to the calling thread.
*
* @return <em>int</em> count
*/
virtual int count();
/**
* Decrement the count, blocking that calling thread if the count becomes 0 or
* less than 0. The calling thread will remain blocked until the count is
* raised above 0, an exception is thrown or the given amount of time expires.
*
* @param timeout maximum amount of time (milliseconds) this method could block
*
* @return
* - <em>true</em> if the Semaphore was acquired before <i>timeout</i> milliseconds elapse.
* - <em>false</em> otherwise.
*
* @exception Interrupted_Exception thrown when the calling thread is interrupted.
* A thread may be interrupted at any time, prematurely ending any wait.
*
* @see Lockable::tryAcquire(unsigned long timeout)
*/
virtual bool tryAcquire(unsigned long timeout);
/**
* Decrement the count, blocking that calling thread if the count becomes 0 or
* less than 0. The calling thread will remain blocked until the count is
* raised above 0 or if an exception is thrown.
*
* @exception Interrupted_Exception thrown when the calling thread is interrupted.
* A thread may be interrupted at any time, prematurely ending any wait.
*
* @see Lockable::acquire()
*/
virtual void acquire();
/**
* Increment the count, unblocking one thread if count is positive.
*
* @exception InvalidOp_Exception thrown if the maximum count would be exceeded.
*
* @see Lockable::release()
*/
virtual void release();
};
} // namespace ZThread
#endif // __ZTSEMAPHORE_H__

View file

@ -1,249 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTSINGLETON_H__
#define __ZTSINGLETON_H__
#include "zthread/Guard.h"
#include "zthread/FastMutex.h"
#include <assert.h>
namespace ZThread {
//
// This policy controls how an object is instantiated
// as well as how and when its destroyed. Phoenix-style
// singletons are not supported easily with type of policy,
// this is intentional since I do not believe that is in
// the true spirit of a singleton.
//
// InstantiationPolicContract {
//
// create(pointer_type&)
//
// }
/**
* @class LocalStaticInstantiation
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:57:45-0400>
* @version 2.2.0
*
* The LocalStaticInstantiation policy allows the creation
* and lifetime of an instance of a particular type
* to be managed using static local values. This will
* abide by the standard C++ rules for static objects
* lifetimes.
*/
class LocalStaticInstantiation {
protected:
/**
* Create an instance of an object, using a local static. The
* object will be destroyed by the system.
*
* @param ptr reference to location to receive the address
* of the allocated object
*/
template <class T>
static void create(T*& ptr) {
static T instance;
ptr = &instance;
}
};
//! Helper class
template <class T>
class StaticInstantiationHelper {
//! Friend class
friend class StaticInstantiation;
//! Holder
static T instance;
};
template <class T>
T StaticInstantiationHelper<T>::instance;
/**
* @class StaticInstantiation
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:57:45-0400>
* @version 2.2.0
*
* The StaticInstantiation policy allows the creation
* and lifetime of an instance of a particular type
* to be managed using static instantiation. This will
* abide by the standard C++ rules for static objects
* lifetimes.
*/
class StaticInstantiation {
protected:
/**
* Create an instance of an object using by simply allocating it statically.
*
* @param ptr reference to location to receive the address
* of the allocated object
*/
template <class T>
static void create(T*& ptr) {
ptr = &StaticInstantiationHelper<T>::instance;
}
};
//! SingletonDestroyer
template <class T>
class Destroyer {
T* doomed;
public:
Destroyer(T* q) : doomed(q) {
assert(doomed);
}
~Destroyer();
};
template <class T>
Destroyer<T>::~Destroyer() {
try {
if(doomed)
delete doomed;
} catch(...) { }
doomed = 0;
}
/**
* @class LazyInstantiation
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:57:45-0400>
* @version 2.2.0
*
* The LazyInstantiation policy allows the creation
* and lifetime of an instance of a particular type
* to be managed using dynamic allocation and a singleton
* destroyer. This will abide by the standard C++ rules
* for static objects lifetimes.
*/
class LazyInstantiation {
protected:
/**
* Create an instance of an object, using new, that will be
* destroyed when an associated Destroyer object (allocated
* statically) goes out of scope.
*
* @param ptr reference to location to receive the address
* of the allocated object
*/
template <class T>
static void create(T*& ptr) {
ptr = new T;
static Destroyer<T> destroyer(ptr);
}
};
/**
* @class Singleton
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:57:45-0400>
* @version 2.2.0
*
* Based on the work of John Vlissidles in his book 'Pattern Hatching'
* an article by Douglas Schmidtt on double-checked locking and policy
* templates described by Andrei Alexandrescu.
*
* This is a thread safe wrapper for creating Singleton classes. The
* synchronization method and instantiation methods can be changed
* easily by specifying different policy implementations as the
* templates parameters.
*
* @code
*
* // Most common Singleton
* Singletion<LonesomeType>
*
* // Singleton that uses static storage
* Singletion<LonesomeType, StaticInstantiation>
*
* // Single-threaded singleton that uses static storage (Meyers-like)
* Singletion<LonesomeType, LocalStaticInstantiation, NotLocked>
*
* @endcode
*/
template <class T, class InstantiationPolicy=LazyInstantiation, class LockType=FastMutex>
class Singleton : private InstantiationPolicy, private NonCopyable {
public:
/**
* Provide access to the single instance through double-checked locking
*
* @return T* single instance
*/
static T* instance();
};
template <class T, class InstantiationPolicy, class LockType>
T* Singleton<T, InstantiationPolicy, LockType>::instance() {
// Uses local static storage to avoid static construction
// sequence issues. (regaring when the lock is created)
static T* ptr = 0;
static LockType lock;
if(!ptr) {
Guard<LockType, LockedScope> g(lock);
if(!ptr)
InstantiationPolicy::create(ptr);
}
return const_cast<T*>(ptr);
}
};
#endif

View file

@ -1,126 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTSYNCHRONOUSEXECUTOR_H__
#define __ZTSYNCHRONOUSEXECUTOR_H__
#include "zthread/Executor.h"
#include "zthread/Guard.h"
#include "zthread/Mutex.h"
#include "zthread/Thread.h"
namespace ZThread {
/**
* @class SynchronousExecutor
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T22:33:51-0400>
* @version 2.3.0
*
* A SynchronousExecutor is an Executor which runs tasks using the thread that
* submits the task. It runs tasks serially, one at a time, in the order they
* were submitted to the executor.
*
* @see Executor.
*/
class SynchronousExecutor : public Executor {
//! Serialize access
Mutex _lock;
//! Cancellation flag
bool _canceled;
public:
//! Create a new SynchronousExecutor
SynchronousExecutor();
//! Destroy a SynchronousExecutor
virtual ~SynchronousExecutor();
/**
* This operation is not supported by this executor.
*/
virtual void interrupt();
/**
* Submit a task to this Executor, blocking the calling thread until the
* task is executed.
*
* @param task Task to be run by a thread managed by this executor
*
* @pre The Executor should have been canceled prior to this invocation.
* @post The submitted task will be run at some point in the future by this Executor.
*
* @exception Cancellation_Exception thrown if the Executor was canceled prior to
* the invocation of this function.
*
* @see Executor::execute(const Task& task)
*/
virtual void execute(const Task& task);
/**
* @see Cancelable::cancel()
*/
virtual void cancel();
/**
* @see Cancelable::cancel()
*/
virtual bool isCanceled();
/**
* Block the calling thread until all tasks submitted prior to this invocation
* complete.
*
* @exception Interrupted_Exception thrown if the calling thread is interrupted
* before the set of tasks being wait for can complete.
*
* @see Executor::wait()
*/
virtual void wait();
/**
* Block the calling thread until all tasks submitted prior to this invocation
* complete or until the calling thread is interrupted.
*
* @param timeout - maximum amount of time, in milliseconds, to wait for the
* currently submitted set of Tasks to complete.
*
* @exception Interrupted_Exception thrown if the calling thread is interrupted
* before the set of tasks being wait for can complete.
*
* @return
* - <em>true</em> if the set of tasks being wait for complete before
* <i>timeout</i> milliseconds elapse.
* - <em>false</em> othewise.
*/
virtual bool wait(unsigned long timeout);
}; /* SynchronousExecutor */
} // namespace ZThread
#endif // __ZTSYNCHRONOUSEXECUTOR_H__

View file

@ -1,78 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTTASK_H__
#define __ZTTASK_H__
#include "zthread/CountedPtr.h"
#include "zthread/Runnable.h"
namespace ZThread {
class ThreadImpl;
/**
* @class Task
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-20T05:22:38-0400>
* @version 2.3.0
*
* A Task provides a CountedPtr wrapper for Runnable objects.
* This wrapper enables an implicit conversion from a
* <i>Runnable*</i> to a <i>Task</i> adding some syntactic sugar
* to the interface.
*/
class ZTHREAD_API Task : public CountedPtr<Runnable, AtomicCount> {
public:
#if !defined(_MSC_VER) || (_MSC_VER > 1200)
Task(Runnable* raw)
: CountedPtr<Runnable, AtomicCount>(raw) { }
#endif
template <typename U>
Task(U* raw)
: CountedPtr<Runnable, AtomicCount>(raw) { }
Task(const CountedPtr<Runnable, AtomicCount>& ptr)
: CountedPtr<Runnable, AtomicCount>(ptr) { }
template <typename U, typename V>
Task(const CountedPtr<U, V>& ptr)
: CountedPtr<Runnable, AtomicCount>(ptr) { }
void operator()() {
(*this)->run();
}
}; /* Task */
} // namespace ZThread
#endif // __ZTTASK_H__

View file

@ -1,381 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTTHREAD_H__
#define __ZTTHREAD_H__
#include "zthread/Cancelable.h"
#include "zthread/Priority.h"
#include "zthread/NonCopyable.h"
#include "zthread/Task.h"
#include "zthread/Waitable.h"
namespace ZThread {
class ThreadImpl;
/**
* @class Thread
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-27T11:17:59-0400>
* @version 2.3.0
*
*
* @see Task
* @see Executor
*
* <h2>Examples</h2>
* - <a href="#ex1">Launching a task</a>
* - <a href="#ex2">Waiting for a task</a>
* - <a href="#ex3">Sharing a task</a>
*
* <h2><a name="ex1">Launching a task</a></h2>
*
* A thread is started simply by constructing a thread object and giving
* it a task to perform. The thread will continue to run its task, even
* after the Thread object used to launch the thread has gone out of scope.
*
* @code
* #include "zthread/Thread.h"
* #include <iostream>
*
* using namespace ZThread;
*
* class aRunnable : public Runnable {
*
* void run() {
*
* Thread::sleep(1000);
* std::cout << "Hello from another thread" << std::endl;
*
* }
*
* };
*
* int main() {
*
* try {
*
* // Implictly constructs a Task
* Thread t(new aRunnable);
*
* } catch(Synchronization_Exception& e) {
* std::cerr << e.what() << std::endl;
* }
*
* std::cout << "Hello from the main thread" << std::endl;
*
* // Output:
*
* // Hello from the main thread
* // Hello from another thread
*
* return 0;
*
* }
*
* @endcode
*
* <h2><a name="ex2">Waiting for a task</a></h2>
*
* A user can exercise some simple synchronization by waiting for a thread
* to complete running its task.
*
* @code
* #include "zthread/Thread.h"
* #include <iostream>
*
* using namespace ZThread;
*
* class aRunnable : public Runnable {
* public:
*
* void run() {
*
* Thread::sleep(1000);
* std::cout << "Hello from another thread" << std::endl;
*
* }
*
* };
*
* int main() {
*
* try {
*
* // Implictly constructs a Task
* Thread t(new aRunnable);
* t.wait();
*
* } catch(Synchronization_Exception& e) {
* std::cerr << e.what() << std::endl;
* }
*
* std::cout << "Hello from the main thread" << std::endl;
*
* // Output:
*
* // Hello from another thread
* // Hello from the main thread
*
* return 0;
*
* }
*
* @endcode
*
* <h2><a name="ex3">Sharing a task</a></h2>
*
* The same task can be shared by more than one thread. A Task is constructed
* from a Runnable, and that Task object is copied by value and handed off to
* each thread.
*
* @code
* #include "zthread/Thread.h"
* #include <iostream>
*
* using namespace ZThread;
*
* class aRunnable : public Runnable {
*
* void run() {
*
* Thread::sleep(1000);
* std::cout << "Hello from another thread" << std::endl;
*
* }
*
* };
*
* int main() {
*
* try {
*
* // Explictly constructs a Task
* Task task(new aRunnable);
*
* // Two threads created to run the same Task
* Thread t1(task);
* Thread t2(task);
*
* } catch(Synchronization_Exception& e) {
* std::cerr << e.what() << std::endl;
* }
*
* std::cout << "Hello from the main thread" << std::endl;
*
* // Output:
*
* // Hello from the main thread
* // Hello from another thread
* // Hello from another thread
*
* return 0;
*
* }
*
* @endcode
*/
class ZTHREAD_API Thread
: public Cancelable, public Waitable, public NonCopyable {
//! Delegate
ThreadImpl* _impl;
public:
/**
* Create a Thread that represents the current thread.
* <em>Using the static members of Thread should be preferred over using this constructor</em>
*/
Thread();
/**
* Create a Thread that spawns a new thread to run the given task.
*
* @param task Task to be run by a thread managed by this executor
* @param autoCancel flag to requestion automatic cancellation
*
* @post if the <i>autoCancel</i> flag was true, this thread will
* automatically be canceled when main() goes out of scope.
*/
Thread(const Task&, bool autoCancel = false);
//! Destroy the Thread
~Thread();
//! Comparison operator
bool operator==(const Thread& t) const;
//! Comparison operator
inline bool operator!=(const Thread& t) const {
return !(*this == t);
}
/**
* Wait for the thread represented by this object to complete its task.
* The calling thread is blocked until the thread represented by this
* object exits.
*
* @exception Deadlock_Exception thrown if thread attempts to join itself
* @exception InvalidOp_Exception thrown if the thread cannot be joined
* @exception Interrupted_Exception thrown if the joining thread has been interrupt()ed
*/
void wait();
/**
* Wait for the thread represented by this object to complete its task.
* The calling thread is blocked until the thread represented by this
* object exits, or until the timeout expires.
*
* @param timeout maximum amount of time (milliseconds) this method
* could block the calling thread.
*
* @return
* - <em>true</em> if the thread task complete before <i>timeout</i>
* milliseconds elapse.
* - <em>false</em> othewise.
*
* @exception Deadlock_Exception thrown if thread attempts to join itself
* @exception InvalidOp_Exception thrown if the thread cannot be joined
* @exception Interrupted_Exception thrown if the joining thread has been interrupt()ed
*/
bool wait(unsigned long timeout);
/**
* Change the priority of this Thread. This will change the actual
* priority of the thread when the OS supports it.
*
* If there is no real priority support, it's simulated.
*
* @param p - new Priority
*/
void setPriority(Priority p);
/**
* Get the priority of this Thread.
*
* @return Priority
*/
Priority getPriority();
/**
* Interrupts this thread, setting the <i>interrupted</i> status of the thread.
* This status is cleared by one of three methods.
*
* If this thread is blocked when this method is called, the thread will
* abort that blocking operation with an Interrupted_Exception.
*
* - The first is by attempting an operation on a synchronization object that
* would normally block the calling thread; Instead of blocking the calling
* the calling thread, the function that would normally block will thrown an
* Interrupted_Exception and clear the <i>interrupted</i> status of the thread.
*
* - The second is by calling Thread::interrupted().
*
* - The third is by calling Thread::canceled().
*
* Threads already blocked by an operation on a synchronization object will abort
* that operation with an Interrupted_Exception, clearing the threads <i>interrupted</i>
* status as in the first case described above.
*
* Interrupting a thread that is no longer running will have no effect.
*
* @return
* - <em>true</em> if the thread was interrupted while not blocked by a wait
* on a synchronization object.
* - <em>false</em> othewise.
*/
bool interrupt();
/**
* Tests whether the current Thread has been interrupt()ed, clearing
* its interruption status.
*
* @return
* - <em>true</em> if the Thread was interrupted.
* - <em>false</em> otherwise.
*
* @post The <i>interrupted</i> status of the current thread will be cleared,
* allowing it to perform a blocking operation on a synchronization
* object without throwing an exception.
*/
static bool interrupted();
/**
* Tests whether the current Thread has been canceled, and clears the
* interrupted status.
*
* @return bool true only if the Thread::cancel() has been invoked.
*/
static bool canceled();
/**
* Tests whether this thread has been canceled. If called from the context
* of this thread, the interrupted status is cleared.
*
* @return
* - <em>true</em> if the Thread was canceled.
* - <em>false</em> otherwise.
*
* @see Cancelable::isCanceled()
*/
virtual bool isCanceled();
/**
* Interrupt and cancel this thread in a single operation. The thread will
* return <em>true</em> whenever its cancelation status is tested in the future.
*
* @exception InvalidOp_Exception thrown if a thread attempts to cancel itself
*
* @see Thread::interrupt()
* @see Cancelable::cancel()
*/
virtual void cancel();
/**
* Put the currently executing thread to sleep for a given amount of
* time.
*
* @param timeout maximum amount of time (milliseconds) this method could block
*
* @exception Interrupted_Exception thrown if the threads sleep is interrupted
* before <i>timeout</i> milliseconds expire.
*/
static void sleep(unsigned long timeout);
/**
* Cause the currently executing thread to yield, allowing the scheduler
* to assign some execution time to another thread.
*/
static void yield();
}; /* Thread */
} // namespace ZThread
#endif // __ZTTHREAD_H__

View file

@ -1,382 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTTHREADLOCAL_H__
#define __ZTTHREADLOCAL_H__
#include "zthread/ThreadLocalImpl.h"
namespace ZThread {
/**
* @class ThreadLocal
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-27T11:18:21-0400>
* @version 2.3.0
*
* Provides access to store and retrieve value types to and from a thread local
* storage context. A thread local storage context consists of the calling thread
* a specific ThreadLocal object. Since this context is specific to each thread
* whenever a value is stored in a ThreadLocal that is accessible from multiple
* threads, it can only be retrieved by the thread that stored it.
*
* The first time a thread accesses the value associated with a thread local storage
* context, a value is created. That value is either an initial value (determined by
* InitialValueT) or an inherited value (determined by ChildValueT).
*
* - If a threads parent had no value associated with a ThreadLocal when the thread was created,
* then the InitialValueT functor is used to create an initial value.
*
* - If a threads parent did have a value associated with a ThreadLocal when the thread was
* created, then the childValueT functor is used to create an initial value.
*
* Not all ThreadLocal's support the inheritance of values from parent threads. The default
* behavoir is to create values through the InitialValueT functor for all thread when
* they first access a thread local storage context.
*
* - Inheritance is enabled automatically when a user supplies a ChildValueT functor other
* than the default one supplied.
*
* - Inheritance can be controlled explicitly by the user through a third functor,
* InheritableValueT.
*
* <h2>Examples</h2>
*
* - <a href="#ex1">Default initial value</a>
* - <a href="#ex2">User-specified initial value</a>
* - <a href="#ex3">User-specified inherited value</a>
*
* <h2><a name="ex1">Default initial value</a></h2>
* A ThreadLocal that does not inherit, and uses the default value
* for an int as its initial value.
*
* @code
*
* #include "zthread/ThreadLocal.h"
* #include "zthread/Thread.h"
* #include <iostream>
*
* using namespace ZThread;
*
* class aRunnable : public Runnable {
* ThreadLocal<int> localValue;
* public:
* void run() {
* std::cout << localValue.get() << std::endl;
* }
* };
*
* int main() {
*
* // Create a shared task to display ThreadLocal values
* Task task(new aRunnable);
*
* Thread t0(task); t0.wait();
* Thread t1(task); t1.wait();
* Thread t2(task); t2.wait();
*
* // Output:
*
* // 0
* // 0
* // 0
*
* return 0;
*
* }
*
* @endcode
*
* <h2><a name="ex2">User-specified initial value</a></h2>
* A ThreadLocal that does not inherit, and uses a custom initial value.
*
* @code
*
* #include "zthread/ThreadLocal.h"
* #include "zthread/Thread.h"
* #include <iostream>
*
* using namespace ZThread;
*
* struct anInitialValueFn {
* int operator()() {
* static int next = 100;
* int val = next; next += 100;
* return val;
* }
* };
*
* class aRunnable : public Runnable {
* ThreadLocal<int, anInitialValueFn> localValue;
* public:
* void run() {
* std::cout << localValue.get() << std::endl;
* }
* };
*
* int main() {
*
* // Create a shared task to display ThreadLocal values
* Task task(new aRunnable);
*
* Thread t0(task); t0.wait();
* Thread t1(task); t1.wait();
* Thread t2(task); t2.wait();
*
* // Output:
*
* // 100
* // 200
* // 300
*
* return 0;
*
* }
*
* @endcode
*
* <h2><a name="ex3">User-specified inherited value</a></h2>
* A ThreadLocal that does inherit and modify child values.
* (The default initial value functor is used)
*
* @code
*
* #include "zthread/ThreadLocal.h"
* #include "zthread/Thread.h"
* #include <iostream>
*
* using namespace ZThread;
*
* struct anInheritedValueFn {
* int operator()(int val) {
* return val + 100;
* }
* };
*
* // This Runnable associates no ThreadLocal value in the main thread; so
* // none of the child threads have anything to inherit.
* class aRunnable : public Runnable {
* ThreadLocal<int, ThreadLocalImpl::InitialValueFn<int>, anInheritedValueFn> localValue;
* public:
* void run() {
* std::cout << localValue.get() << std::endl;
* }
* };
*
* // This Runnable associates a ThreadLocal value in the main thread which
* // is inherited when the child threads are created.
* class anotherRunnable : public Runnable {
* ThreadLocal<int, ThreadLocalImpl::InitialValueFn<int>, anInheritedValueFn> localValue;
* public:
* anotherRunnable() {
* localValue.set(100);
* }
* void run() {
* std::cout << localValue.get() << std::endl;
* }
* };
*
* int main() {
*
* // Create a shared task to display ThreadLocal values
* Task task(new aRunnable);
*
* Thread t0(task); t0.wait();
* Thread t1(task); t1.wait();
* Thread t2(task); t2.wait();
*
* // Output:
*
* // 0
* // 0
* // 0
*
* task = Task(new anotherRunnable);
*
* Thread t10(task); t10.wait();
* Thread t11(task); t11.wait();
* Thread t12(task); t12.wait();
*
* // Output:
*
* // 200
* // 200
* // 200
*
* return 0;
*
* }
*
* @endcode
*
* <h2>Parameters</h2>
*
* <em>InitialValueT</em>
*
* This template parameter should indicate the functor used to set
* the initial value. It should support the following operator:
*
* <code>
* // required operator
* T operator()
*
* // supported expression
* InitialValueT()()
* </code>
*
*
* <em>ChildValueT</em>
*
* This template parameter should indicate the functor used to set
* the value that will be inherited by thread whose parent have associated
* a value with the ThreadLocal's context at the time they are created.
* It should support the following operator:
*
* <code>
* // required operator
* T operator(const T& parentValue)
*
* // supported expression
* ChildValueT()(parentValue)
* </code>
*
*
* <em>InheritableValueT</em>
*
* This template parameter should indicate the functor, used to determine
* wheather or not this ThreadLocal will allow values from a parent threads
* context to be inherited by child threads when they are created.
* It should support the following operator:
*
* <code>
* // required operator
* bool operator(const T& childValueFunctor)
*
* // supported expression
* InheritableValueT()( ChildValueT() )
* </code>
*
*/
template <
typename T,
typename InitialValueT = ThreadLocalImpl::InitialValueFn<T>,
typename ChildValueT = ThreadLocalImpl::UniqueChildValueFn,
typename InheritableValueT = ThreadLocalImpl::InheritableValueFn
>
class ThreadLocal : private ThreadLocalImpl {
typedef ThreadLocalImpl::ValuePtr ValuePtr;
class Value : public ThreadLocalImpl::Value {
T value;
public:
Value() : value( InitialValueT()() ) { }
Value(const Value& v) : value( ChildValueT()(v.value) ) { }
virtual ~Value() { }
operator T() { return value; }
const Value& operator=(const T& v) { value = v; }
virtual bool isInheritable() const {
return InheritableValueT()( ChildValueT() );
}
virtual ValuePtr clone() const {
return ValuePtr( new Value(*this) );
}
};
static ValuePtr createValue() {
return ValuePtr( new Value );
}
public:
/**
* Get the value associated with the context (this ThreadLocal and
* the calling thread) of the invoker. If no value is currently
* associated, then an intial value is created and associated; that value
* is returned.
*
* @return <em>T</em> associated value.
*
* @post If no value has been associated with the invoking context
* then an inital value will be associated. That value is
* created by the <em>InitialValueT</em> functor.
*/
T get() const {
return (T)reinterpret_cast<Value&>( *value(&createValue) );
}
/**
* Replace the value associated with the context (this ThreadLocal and
* the calling thread) of the invoker. If no value is currently
* associated, then an intial value is first created and subsequently
* replaced by the new value.
*
* @param v value of type <em>T</em> to associate.
*
* @post If no value has been associated with the invoking context
* then an inital value will first be associated. That value is
* created by the <em>InitialValueT</em> functor and then
* replaced with the new value.
*/
void set(T v) const {
reinterpret_cast<Value&>( *value(&createValue) ) = v;
}
/**
* Remove any value current associated with this ThreadLocal.
*
* @post Upon thier next invocation the get() and set() functions will behave as
* if no value has been associated with this ThreadLocal and an
* initial value will be generated.
*/
void clear() const {
ThreadLocalImpl::clear();
}
/**
* Remove any value current associated with <em>any</em> ThreadLocal.
*
* @post Upon thier next invocation the get() and set() functions will behave as
* if no value has been associated with <em>any</em> ThreadLocal and new
* initial values will be generated.
*/
static void clearAll() {
ThreadLocalImpl::clearAll();
}
};
} // namespace ZThread
#endif // __ZTTHREADLOCAL_H__

View file

@ -1,108 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTTHREADLOCALIMPL_H__
#define __ZTTHREADLOCALIMPL_H__
#include "zthread/CountedPtr.h"
namespace ZThread {
/**
* @class ThreadLocalImpl
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-27T10:23:19-0400>
* @version 2.3.0
*
* @see ThreadLocal
*/
class ZTHREAD_API ThreadLocalImpl : private NonCopyable {
public:
class Value;
typedef CountedPtr<Value, size_t> ValuePtr;
//!
class Value {
Value& operator=(const Value&);
public:
virtual ~Value() {}
virtual bool isInheritable() const = 0;
virtual ValuePtr clone() const = 0;
};
//! Create a ThreadLocalImpl
ThreadLocalImpl();
//! Destroy a ThreadLocalImpl
~ThreadLocalImpl();
/**
* @class InitialValueFn
*/
template <typename T>
struct InitialValueFn {
T operator()() { return T(); }
};
/**
* @class ChildValueFn
*/
struct ChildValueFn {
template <typename T>
T operator()(const T& value) { return T(value); }
};
/**
* @class UniqueChildValueFn
*/
struct UniqueChildValueFn : public ChildValueFn { };
/**
* @class InheritableValueFn
*/
struct InheritableValueFn {
template <typename T>
bool operator()(const T&) { return true; }
bool operator()(const UniqueChildValueFn&) { return false; }
};
protected:
//! Get the Value for the current thread
ValuePtr value( ValuePtr (*pfn)() ) const;
//! Clear any value set for this thread
void clear() const;
//! Clear any value set with any ThreadLocal for this thread
static void clearAll();
};
} // __ZTTHREADLOCALIMPL_H__
#endif

View file

@ -1,136 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTTHREADEDEXECUTOR_H__
#define __ZTTHREADEDEXECUTOR_H__
#include "zthread/Executor.h"
#include "zthread/CountedPtr.h"
namespace ZThread {
namespace { class ExecutorImpl; }
/**
* @class ThreadedExecutor
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T22:39:13-0400>
* @version 2.3.0
*
* A ThreadedExecutor spawns a new thread to execute each task submitted.
* A ThreadedExecutor supports the following optional operations,
*
* - <em>cancel</em>()ing a ThreadedExecutor will cause it to stop accepting
* new tasks.
*
* - <em>interrupt</em>()ing a ThreadedExecutor will cause the any thread running
* a task which was submitted prior to the invocation of this function to
* be interrupted during the execution of that task.
*
* - <em>wait</em>()ing on a ThreadedExecutor will block the calling thread
* until all tasks that were submitted prior to the invocation of this function
* have completed.
*
* @see Executor.
*/
class ThreadedExecutor : public Executor {
CountedPtr< ExecutorImpl > _impl;
public:
//! Create a new ThreadedExecutor
ThreadedExecutor();
//! Destroy a ThreadedExecutor
virtual ~ThreadedExecutor();
/**
* Interrupting a ThreadedExecutor will cause an interrupt() to be sent
* to every Task that has been submitted at the time this function is
* called. Tasks that are submitted after this function is called will
* not be interrupt()ed; unless this function is invoked again().
*/
virtual void interrupt();
/**
* Submit a task to this Executor. This will not block the current thread
* for very long. A new thread will be created and the task will be run()
* within the context of that new thread.
*
* @exception Cancellation_Exception thrown if this Executor has been canceled.
* The Task being submitted will not be executed by this Executor.
*
* @see Executor::execute(const Task&)
*/
virtual void execute(const Task&);
/**
* @see Cancelable::cancel()
*/
virtual void cancel();
/**
* @see Cancelable::isCanceled()
*/
virtual bool isCanceled();
/**
* Waiting on a ThreadedExecutor will block the current thread until all
* tasks submitted to the Executor up until the time this function was called
* have completed.
*
* Tasks submitted after this function is called will not delay a thread that
* was already waiting on the Executor any longer. In order to wait for
* those tasks to complete as well, another wait() would be needed.
*
* @exception Interrupted_Exception thrown if the calling thread is interrupted
* before the set of tasks for which it was waiting complete.
*
* @see Waitable::wait()
*/
virtual void wait();
/**
* Operates the same as ThreadedExecutor::wait() but with a timeout.
*
* @param timeout maximum amount of time, in milliseconds, to wait for the
* currently submitted set of Tasks to complete.
*
* @exception Interrupted_Exception thrown if the calling thread is interrupt()ed
* while waiting for the current set of Tasks to complete.
*
* @return
* - <em>true</em> if the set of tasks running at the time this function is invoked complete
* before <i>timeout</i> milliseconds elapse.
* - <em>false</em> othewise.
*
* @see Waitable::wait(unsigned long timeout)
*/
virtual bool wait(unsigned long timeout);
}; /* ThreadedExecutor */
} // namespace ZThread
#endif // __ZTTHREADEDEXECUTOR_H__

View file

@ -1,225 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTTIME_H__
#define __ZTTIME_H__
#include "zthread/Config.h"
namespace ZThread {
/**
* @class Time
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:52:46-0400>
* @version 2.2.11
*
* The Time class provides access to time values relative to when the program
* was started. In other words, this class might be thought of as a timer that
* starts at 0 and counts upwards. This class offers millisecond resolution.
*/
class ZTHREAD_API Time {
unsigned long _seconds;
unsigned long _milliseconds;
//! Create a new Time object
Time(unsigned long secs, unsigned long millis)
: _seconds(secs), _milliseconds(millis) { }
/**
* Set the number of milliseconds in this Time object.
*
* @param millis - new milliseconds value
* @return unsigned long old milliseconds value
*/
unsigned long milliseconds(unsigned long millis) {
unsigned long n = _milliseconds;
_milliseconds = millis;
return n;
}
/**
* Set the number of seconds in this Time object.
*
* @param secs - new seconds value
* @return unsigned long old seconds value
*/
unsigned long seconds(unsigned long secs) {
unsigned long n = _seconds;
_seconds = secs;
return n;
}
public:
/**
* Create a Time object with the current time relative to the
* beginning of the program.
*/
Time();
/**
* Create a Time object by copying another.
*
* @param t - Time object to copy.
*/
Time(const Time& t)
: _seconds(t._seconds), _milliseconds(t._milliseconds) { }
/**
* Get the number of milliseconds in this Time object.
*
* @return unsigned long milliseconds value
*/
unsigned long milliseconds() const {
return _milliseconds;
}
/**
* Get the number of seconds in this Time object.
*
* @return unsigned long seconds value
*/
unsigned long seconds() const {
return _seconds;
}
/**
* Add some number of milliseconds to this Time object.
*
* @param millis - number of milliseconds to add to this Time object
* @return const Time& this object
*/
const Time& operator+=(unsigned long millis) {
_milliseconds += millis;
_seconds += (_milliseconds / 1000);
_milliseconds %= 1000;
return *this;
}
/**
* Subtract some number of milliseconds to this Time object.
*
* @param millis - number of milliseconds to subtract from this Time object
* @return const Time& this object
*/
const Time& operator-=(unsigned long millis) {
if(_milliseconds > millis)
_milliseconds -= millis;
else {
while(_seconds > 0 && _milliseconds < millis) {
_milliseconds += 1000;
_seconds -= 1;
}
_milliseconds = (_milliseconds < millis) ? 0 : (_milliseconds - millis);
}
return *this;
}
/**
* Add the value of another Time object to this one.
*
* @param t - Time object whose value should be added to this object
* @return const Time& this object
*/
const Time& operator+=(const Time& t) {
_milliseconds += t.milliseconds();
_seconds += (_milliseconds / 1000) + t.seconds();
_milliseconds %= 1000;
return *this;
}
/**
* Subtract the value of another Time object from this one.
* This function has a floor of 0.
*
* @param t - Time object whose value should be subtracted from this object
* @return const Time& this object
*/
const Time& operator-=(const Time& t) {
unsigned long millis = t.milliseconds();
unsigned long secs = t.seconds();
if(_seconds >= secs) {
if(_milliseconds > millis) {
_milliseconds -= millis;
_seconds -= secs;
} else {
while(_seconds > 0 && _milliseconds < millis) {
_milliseconds += 1000;
_seconds -= 1;
}
_milliseconds = (_milliseconds < millis) ? 0 : (_milliseconds - millis);
_seconds = (_seconds < secs) ? 0 : (_seconds - secs);
}
} else {
_milliseconds = 0;
_seconds = 0;
}
return *this;
}
};
} // namespace ZThread
#endif // __ZTTIME_H__

View file

@ -1,94 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTWAITABLE_H__
#define __ZTWAITABLE_H__
#include "zthread/Exceptions.h"
namespace ZThread {
/**
* @class Waitable
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T22:16:41-0400>
* @version 2.3.0
*
* The Waitable interface defines a common method of adding generic <i>wait</i> semantics
* to a class.
*
* <b>Waiting</b>
*
* An object implementing the Waitable interface externalizes a mechanism for testing
* some internal condition. Another object may <i>wait()</i>s for a Waitable object;
* in doing so, it wait()s for that condition to become true by blocking the caller
* while the condition is false.
*
* For example, a Condition is Waitable object that extends <i>wait</i> semantics
* so that wait()ing means a thread is blocked until some external stimulus
* specifically performs an operation on the Condition to make its internal condition true.
* (serialization aside)
*
* A Barrier extends <i>wait</i> semantics so that wait()ing mean waiting for other
* waiters, and may include automatically resetting the condition once a wait is complete.
*
* @see Condition
* @see Barrier
* @see Executor
*/
class Waitable {
public:
//! Destroy a Waitable object.
virtual ~Waitable() {}
/**
* Waiting on an object will generally cause the calling thread to be blocked
* for some indefinite period of time. The thread executing will not proceed
* any further until the Waitable object releases it unless or an exception
* is thrown.
*/
virtual void wait() = 0;
/**
* Waiting on an object will generally cause the calling thread to be blocked
* for some indefinite period of time. The thread executing will not proceed
* any further until the Waitable object releases it unless or an exception
* is thrown.
*
* @param timeout maximum amount of time, in milliseconds, to spend waiting.
*
* @return
* - <em>true</em> if the set of tasks being wait for complete before
* <i>timeout</i> milliseconds elapse.
* - <em>false</em> othewise.
*/
virtual bool wait(unsigned long timeout) = 0;
}; /* Waitable */
} // namespace ZThread
#endif // __ZTWAITABLE_H__

View file

@ -1,67 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTLIBRARY_H__
#define __ZTLIBRARY_H__
#include "zthread/Barrier.h"
#include "zthread/BiasedReadWriteLock.h"
#include "zthread/BlockingQueue.h"
#include "zthread/BoundedQueue.h"
#include "zthread/Cancelable.h"
#include "zthread/ClassLockable.h"
#include "zthread/ConcurrentExecutor.h"
#include "zthread/Condition.h"
#include "zthread/Config.h"
#include "zthread/CountedPtr.h"
#include "zthread/CountingSemaphore.h"
#include "zthread/Exceptions.h"
#include "zthread/Executor.h"
#include "zthread/FairReadWriteLock.h"
#include "zthread/FastMutex.h"
#include "zthread/FastRecursiveMutex.h"
#include "zthread/Guard.h"
#include "zthread/Lockable.h"
#include "zthread/LockedQueue.h"
#include "zthread/MonitoredQueue.h"
#include "zthread/Mutex.h"
#include "zthread/NonCopyable.h"
#include "zthread/PoolExecutor.h"
#include "zthread/Priority.h"
#include "zthread/PriorityCondition.h"
#include "zthread/PriorityInheritanceMutex.h"
#include "zthread/PriorityMutex.h"
#include "zthread/PrioritySemaphore.h"
#include "zthread/Queue.h"
#include "zthread/ReadWriteLock.h"
#include "zthread/RecursiveMutex.h"
#include "zthread/Runnable.h"
#include "zthread/Semaphore.h"
#include "zthread/Singleton.h"
#include "zthread/SynchronousExecutor.h"
#include "zthread/Thread.h"
#include "zthread/ThreadLocal.h"
#include "zthread/Time.h"
#include "zthread/Waitable.h"
#endif

View file

@ -17,7 +17,7 @@
## Process this file with automake to produce Makefile.in
## Sub-directories to parse
SUBDIRS = g3dlite sockets zlib zthread
SUBDIRS = g3dlite sockets zlib
## Additional files to include when running 'make dist'
# Nothing yet.

View file

@ -1,57 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTATOMICCOUNTSELECT_H__
#define __ZTATOMICCOUNTSELECT_H__
#include "zthread/AtomicCount.h"
#include "zthread/Config.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/*
// Select the correct AtomicCount implementation based on
// what the compilation environment has defined
#ifndef ZT_VANILLA
#if defined(HAVE_ATOMIC_LINUX)
# include "linux/AtomicCount.cxx"
#elif defined(ZT_WIN32)
# include "win32/AtomicCount.cxx"
#elif defined(ZT_WIN9X)
# include "win9x/AtomicCount.cxx"
#endif
#endif
// Default to an AtomicCount that just uses a FastLock
#ifndef __ZTATOMICCOUNTIMPL_H__
# include "vanilla/SimpleAtomicCount.cxx"
#endif
*/
# include "vanilla/SimpleAtomicCount.cxx"
#endif // __ZTATOMICCOUNTSELECT_H__

View file

@ -1,54 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/ConcurrentExecutor.h"
namespace ZThread {
ConcurrentExecutor::ConcurrentExecutor()
: _executor(1) {}
void ConcurrentExecutor::interrupt() {
_executor.interrupt();
}
void ConcurrentExecutor::execute(const Task& task) {
_executor.execute(task);
}
void ConcurrentExecutor::cancel() {
_executor.cancel();
}
bool ConcurrentExecutor::isCanceled() {
return _executor.isCanceled();
}
void ConcurrentExecutor::wait() {
_executor.wait();
}
bool ConcurrentExecutor::wait(unsigned long timeout) {
return _executor.wait(timeout);
}
}

View file

@ -1,80 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/Condition.h"
#include "ConditionImpl.h"
namespace ZThread {
class FifoConditionImpl : public ConditionImpl<fifo_list> {
public:
FifoConditionImpl(Lockable& l) : ConditionImpl<fifo_list>(l) {}
};
Condition::Condition(Lockable& lock) {
_impl = new FifoConditionImpl(lock);
}
Condition::~Condition() {
if(_impl != 0)
delete _impl;
}
void Condition::wait() {
_impl->wait();
}
bool Condition::wait(unsigned long ms) {
return _impl->wait(ms);
}
void Condition::signal() {
_impl->signal();
}
void Condition::broadcast() {
_impl->broadcast();
}
} // namespace ZThread

View file

@ -1,377 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTCONDITIONIMPL_H__
#define __ZTCONDITIONIMPL_H__
#include "zthread/Guard.h"
#include "Debug.h"
#include "Scheduling.h"
#include "DeferredInterruptionScope.h"
namespace ZThread {
/**
* @class ConditionImpl
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-18T08:15:37-0400>
* @version 2.2.11
*
* The ConditionImpl template allows how waiter lists are sorted
* to be parameteized
*/
template <typename List>
class ConditionImpl {
//! Waiters currently blocked
List _waiters;
//! Serialize access to this object
FastLock _lock;
//! External lock
Lockable& _predicateLock;
public:
/**
* Create a new ConditionImpl.
*
* @exception Initialization_Exception thrown if resources could not be
* allocated
*/
ConditionImpl(Lockable& predicateLock) : _predicateLock(predicateLock) {
}
/**
* Destroy this ConditionImpl, release its resources
*/
~ConditionImpl();
void signal();
void broadcast();
void wait();
bool wait(unsigned long timeout);
};
template <typename List>
ConditionImpl<List>::~ConditionImpl() {
#ifndef NDEBUG
// It is an error to destroy a condition with threads waiting on it.
if(!_waiters.empty()) {
ZTDEBUG("** You are destroying a condition variable which still has waiting threads. **\n");
assert(0);
}
#endif
}
/**
* Signal the condition variable, waking one thread if any.
*/
template <typename List>
void ConditionImpl<List>::signal() {
Guard<FastLock> g1(_lock);
// Try to find a waiter with a backoff & retry scheme
for(;;) {
// Go through the list, attempt to notify() a waiter.
for(typename List::iterator i = _waiters.begin(); i != _waiters.end();) {
// Try the monitor lock, if it cant be locked skip to the next waiter
ThreadImpl* impl = *i;
Monitor& m = impl->getMonitor();
if(m.tryAcquire()) {
// Notify the monitor & remove from the waiter list so time isn't
// wasted checking it again.
i = _waiters.erase(i);
// If notify() is not sucessful, it is because the wait() has already
// been ended (killed/interrupted/notify'd)
bool woke = m.notify();
m.release();
// Once notify() succeeds, return
if(woke)
return;
} else ++i;
}
if(_waiters.empty())
return;
{ // Backoff and try again
Guard<FastLock, UnlockedScope> g2(g1);
ThreadImpl::yield();
}
}
}
/**
* Broadcast to the condition variable, waking all threads waiting at the time of
* the broadcast.
*/
template <typename List>
void ConditionImpl<List>::broadcast() {
Guard<FastLock> g1(_lock);
// Try to find a waiter with a backoff & retry scheme
for(;;) {
// Go through the list, attempt to notify() a waiter.
for(typename List::iterator i = _waiters.begin(); i != _waiters.end();) {
// Try the monitor lock, if it cant be locked skip to the next waiter
ThreadImpl* impl = *i;
Monitor& m = impl->getMonitor();
if(m.tryAcquire()) {
// Notify the monitor & remove from the waiter list so time isn't
// wasted checking it again.
i = _waiters.erase(i);
// Try to wake the waiter, it doesn't matter if this is successful
// or not (only fails when the monitor is already going to stop waiting).
m.notify();
m.release();
} else ++i;
}
if(_waiters.empty())
return;
{ // Backoff and try again
Guard<FastLock, UnlockedScope> g2(g1);
ThreadImpl::yield();
}
}
}
/**
* Cause the currently executing thread to block until this ConditionImpl has
* been signaled, the threads state changes.
*
* @param predicate Lockable&
*
* @exception Interrupted_Exception thrown when the caller status is interrupted
* @exception Synchronization_Exception thrown if there is some other error.
*/
template <typename List>
void ConditionImpl<List>::wait() {
// Get the monitor for the current thread
ThreadImpl* self = ThreadImpl::current();
Monitor& m = self->getMonitor();
Monitor::STATE state;
{
Guard<FastLock> g1(_lock);
// Release the _predicateLock
_predicateLock.release();
// Stuff the waiter into the list
_waiters.insert(self);
// Move to the monitor's lock
m.acquire();
{
Guard<FastLock, UnlockedScope> g2(g1);
state = m.wait();
}
// Move back to the Condition's lock
m.release();
// Remove from waiter list, regarless of weather release() is called or
// not. The monitor is sticky, so its possible a state 'stuck' from a
// previous operation and will leave the wait() w/o release() having
// been called.
typename List::iterator i = std::find(_waiters.begin(), _waiters.end(), self);
if(i != _waiters.end())
_waiters.erase(i);
}
// Defer interruption until the external lock is acquire()d
Guard<Monitor, DeferredInterruptionScope> g3(m);
{
#if !defined(NDEBUG)
try {
#endif
_predicateLock.acquire(); // Should not throw
#if !defined(NDEBUG)
} catch(...) { assert(0); }
#endif
}
switch(state) {
case Monitor::SIGNALED:
break;
case Monitor::INTERRUPTED:
throw Interrupted_Exception();
default:
throw Synchronization_Exception();
}
}
/**
* Cause the currently executing thread to block until this ConditionImpl has
* been signaled, or the timeout expires or the threads state changes.
*
* @param _predicateLock Lockable&
* @param timeout maximum milliseconds to block.
*
* @return bool
*
* @exception Interrupted_Exception thrown when the caller status is interrupted
* @exception Synchronization_Exception thrown if there is some other error.
*/
template <typename List>
bool ConditionImpl<List>::wait(unsigned long timeout) {
// Get the monitor for the current thread
ThreadImpl* self = ThreadImpl::current();
Monitor& m = self->getMonitor();
Monitor::STATE state;
{
Guard<FastLock> g1(_lock);
// Release the _predicateLock
_predicateLock.release();
// Stuff the waiter into the list
_waiters.insert(self);
state = Monitor::TIMEDOUT;
// Don't bother waiting if the timeout is 0
if(timeout) {
m.acquire();
{
Guard<FastLock, UnlockedScope> g2(g1);
state = m.wait(timeout);
}
m.release();
}
// Remove from waiter list, regarless of weather release() is called or
// not. The monitor is sticky, so its possible a state 'stuck' from a
// previous operation and will leave the wait() w/o release() having
// been called.
typename List::iterator i = std::find(_waiters.begin(), _waiters.end(), self);
if(i != _waiters.end())
_waiters.erase(i);
}
// Defer interruption until the external lock is acquire()d
Guard<Monitor, DeferredInterruptionScope> g3(m);
{
#if !defined(NDEBUG)
try {
#endif
_predicateLock.acquire(); // Should not throw
#if !defined(NDEBUG)
} catch(...) { assert(0); }
#endif
}
switch(state) {
case Monitor::SIGNALED:
break;
case Monitor::INTERRUPTED:
throw Interrupted_Exception();
case Monitor::TIMEDOUT:
return false;
default:
throw Synchronization_Exception();
}
return true;
}
} // namespace ZThread
#endif // __ZTCONDITIONIMPL_H__

View file

@ -1,92 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/CountingSemaphore.h"
#include "SemaphoreImpl.h"
using namespace ZThread;
namespace ZThread {
CountingSemaphore::CountingSemaphore(int initialCount) {
_impl = new FifoSemaphoreImpl(initialCount, 0 , false);
}
CountingSemaphore::~CountingSemaphore() {
try {
if(_impl != 0)
delete _impl;
} catch(...) { }
}
void CountingSemaphore::wait() {
_impl->acquire();
}
bool CountingSemaphore::tryWait(unsigned long ms) {
return _impl->tryAcquire(ms);
}
void CountingSemaphore::post() {
_impl->release();
}
int CountingSemaphore::count() {
return _impl->count();
}
void CountingSemaphore::acquire() {
_impl->acquire();
}
bool CountingSemaphore::tryAcquire(unsigned long ms) {
return _impl->tryAcquire(ms);
}
void CountingSemaphore::release() {
_impl->release();
}
} // namespace ZThread

View file

@ -1,32 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef ZTDEBUG
#ifndef NDEBUG
# include <stdio.h>
# define ZTDEBUG printf
#else
# define ZTDEBUG(x)
#endif
#endif

View file

@ -1,63 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTDEFERREDINTERRUPTIONSCOPE_H__
#define __ZTDEFERREDINTERRUPTIONSCOPE_H__
#include "ThreadImpl.h"
#include <cassert>
namespace ZThread {
/**
* @class DeferredInterruptionScope
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T19:45:18-0400>
* @version 2.3.0
*
* Locking policy for a Guard that will defer any state reported
* for the reported Status of a thread except SIGNALED until the
* scope has ended. This allows a Guard to be used to create an
* uninterruptible region in code.
*/
class DeferredInterruptionScope {
public:
template <class LockType>
static void createScope(LockHolder<LockType>& l) {
l.getLock().interest(Monitor::SIGNALED);
}
template <class LockType>
static void destroyScope(LockHolder<LockType>& l) {
l.getLock().interest(Monitor::ANYTHING);
}
};
}
#endif // __ZTDEFERREDINTERRUPTIONSCOPE_H__

View file

@ -1,71 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTFASTLOCKSELECT_H__
#define __ZTFASTLOCKSELECT_H__
#include "zthread/Config.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// Select the correct FastLock implementation based on
// what the compilation environment has defined
#if defined(ZT_POSIX)
# if defined(HAVE_ATOMIC_LINUX)
# if defined(ZTHREAD_USE_SPIN_LOCKS)
# include "linux/AtomicFastLock.h"
# endif
# endif
# include "posix/FastLock.h"
// Use spin locks
#elif defined(ZTHREAD_USE_SPIN_LOCKS)
# if defined(ZT_WIN9X)
# include "win9x/AtomicFastLock.h"
# elif defined(ZT_WIN32)
# include "win32/AtomicFastLock.h"
# endif
// Use normal Mutex objects
#elif defined(ZT_WIN9X) || defined(ZT_WIN32)
# include "win32/FastLock.h"
#elif defined(ZT_MACOS)
# include "macos/FastLock.h"
#endif
#ifndef __ZTFASTLOCK_H__
#error "No FastLock implementation could be selected"
#endif
#endif // __ZTFASTLOCKSELECT_H__

View file

@ -1,53 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/FastMutex.h"
#include "FastLock.h"
namespace ZThread {
FastMutex::FastMutex() : _lock(new FastLock) { }
FastMutex::~FastMutex() {
delete _lock;
}
void FastMutex::acquire() {
_lock->acquire();
}
bool FastMutex::tryAcquire(unsigned long timeout) {
return _lock->tryAcquire(timeout);
}
void FastMutex::release() {
_lock->release();
}
} // namespace ZThread

View file

@ -1,74 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTFASTRECURSIVELOCKSELECT_H__
#define __ZTFASTRECURSIVELOCKSELECT_H__
#include "zthread/Config.h"
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
// Select the correct FastRecusriveLock implementation based on
// what the compilation environment has defined
#if defined(ZTHREAD_DUAL_LOCKS)
# include "vanilla/DualMutexRecursiveLock.h"
#else
# ifndef ZT_VANILLA
# if defined(ZT_POSIX)
// Linux and Solaris have working pthreads recursive locks. These
// are created differently, and there are some system don't seem to
// include recursive locks at all. Several recursive implementations
// are provided
# if defined(__linux__)
# include "linux/FastRecursiveLock.h"
# elif defined(HAVE_MUTEXATTR_SETTYPE)
# include "solaris/FastRecursiveLock.h"
# elif defined(ZTHREAD_CONDITION_LOCKS)
# include "posix/ConditionRecursiveLock.h"
# endif
// Use spin locks
# elif defined(ZT_WIN32) && defined(ZTHREAD_USE_SPIN_LOCKS)
# include "win32/AtomicFastRecursiveLock.h"
// Use normal Mutex objects
# elif defined(ZT_WIN32) || defined(ZT_WIN9X)
# include "win32/FastRecursiveLock.h"
# endif
# endif
#endif
#ifndef __ZTFASTRECURSIVELOCK_H__
#include "vanilla/SimpleRecursiveLock.h"
#endif
#endif // __ZTFASTRECURSIVELOCKSELECT_H__

View file

@ -1,53 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/FastRecursiveMutex.h"
#include "FastRecursiveLock.h"
namespace ZThread {
FastRecursiveMutex::FastRecursiveMutex()
: _lock(new FastRecursiveLock) { }
FastRecursiveMutex::~FastRecursiveMutex()
{ delete _lock; }
void FastRecursiveMutex::acquire() {
_lock->acquire();
}
bool FastRecursiveMutex::tryAcquire(unsigned long timeout) {
return _lock->tryAcquire(timeout);
}
void FastRecursiveMutex::release() {
_lock->release();
}
} // namespace ZThread

View file

@ -1,99 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTINTRUSIVEPTR_H__
#define __ZTINTRUSIVEPTR_H__
#include "zthread/Guard.h"
#include <cstdlib>
namespace ZThread {
/**
* @class IntrusivePtr
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T17:54:23-0400>
* @version 2.2.0
*
* This template creates an intrusively reference counted object
* an IntrusivePtr starts out with a 1 count, which is updated as references are
* added and removed. When the reference count drops to 0, the
* IntrusivePtr will delete itself.
*/
template <typename T, class LockType>
class IntrusivePtr : NonCopyable {
//! Intrusive reference count
size_t _count;
//! Synchornization object
LockType _lock;
public:
/**
* Create an IntrusivePtr with a count.
*/
IntrusivePtr(size_t InitialCount=1) : _count(InitialCount) { }
/**
* Destroy an IntrusivePtr
*/
virtual ~IntrusivePtr() {}
/**
* Add a reference to this object, it will take one more
* call to delReference() for it to be deleted.
*/
void addReference() {
Guard<LockType, LockedScope> g(_lock);
_count++;
}
/**
* Remove a reference from this object, if the reference count
* drops to 0 as a result, the object deletes itself.
*/
void delReference() {
bool result = false;
{
Guard<LockType, LockedScope> g(_lock);
result = (--_count == 0);
}
if(result)
delete this;
}
};
};
#endif

View file

@ -1,132 +0,0 @@
## Copyright (c) 2005, Eric Crahen
## Modified for MaNGOS project <http://getmangos.com>
##
## Permission is hereby granted, free of charge, to any person obtaining a copy
## of this software and associated documentation files (the "Software"), to deal
## in the Software without restriction, including without limitation the rights
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## copies of the Software, and to permit persons to whom the Software is furnished
## to do so, subject to the following conditions:
##
## The above copyright notice and this permission notice shall be included in all
## copies or substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
## WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## Process this file with automake to produce Makefile.in
## CPP flags for includes, defines, etc.
AM_CPPFLAGS = -I$(srcdir)/../../include -I$(srcdir)/../../include/zthread
## Build ZThread as shared library.
# libZThread shared library will later be reused by realm list daemon
# and world server daemon.
lib_LTLIBRARIES = libZThread.la
libZThread_la_SOURCES = \
AtomicCount.cxx \
Condition.cxx \
ConcurrentExecutor.cxx \
CountingSemaphore.cxx \
FastMutex.cxx \
FastRecursiveMutex.cxx \
Mutex.cxx \
RecursiveMutexImpl.cxx \
RecursiveMutex.cxx \
Monitor.cxx \
PoolExecutor.cxx \
PriorityCondition.cxx \
PriorityInheritanceMutex.cxx \
PriorityMutex.cxx \
PrioritySemaphore.cxx \
Semaphore.cxx \
SynchronousExecutor.cxx \
Thread.cxx \
ThreadedExecutor.cxx \
ThreadImpl.cxx \
ThreadLocalImpl.cxx \
ThreadQueue.cxx \
Time.cxx \
ThreadOps.cxx
## libtool settings
# API versioning
# Link against dependencies
# How to increase version info:
# - only bug fixes implemented:
# bump the version to LTZTHREAD_CURRENT:LTZTHREAD_REVISION+1:LTZTHREAD_AGE
# - augmented the interface:
# bump the version to LTZTHREAD_CURRENT+1:0:LTZTHREAD_AGE+1
# - broken old interface:
# bump the version to LTZTHREAD_CURRENT+1:0:0
LTZTHREAD_CURRENT = 2
LTZTHREAD_REVISION = 3
LTZTHREAD_AGE = 2
libZThread_la_LDFLAGS = -version-info $(LTZTHREAD_CURRENT):$(LTZTHREAD_REVISION):$(LTZTHREAD_AGE)
## Additional files to include when running 'make dist'
# Header files.
EXTRA_DIST = \
ConditionImpl.h \
Debug.h \
DeferredInterruptionScope.h \
FastLock.h \
FastRecursiveLock.h \
IntrusivePtr.h \
Monitor.h \
MutexImpl.h \
RecursiveMutexImpl.h \
Scheduling.h \
SemaphoreImpl.h \
State.h \
Status.h \
TSS.h \
ThreadImpl.h \
ThreadOps.h \
ThreadQueue.h \
TimeStrategy.h \
config.h
# Implementation specific files.
EXTRA_DIST += \
linux/AtomicCount.cxx \
linux/AtomicFastLock.h \
linux/FastRecursiveLock.h \
macos/FastLock.h \
macos/Monitor.cxx \
macos/Monitor.h \
macos/TSS.h \
macos/ThreadOps.cxx \
macos/ThreadOps.h \
macos/UpTimeStrategy.h \
posix/ConditionRecursiveLock.h \
posix/FastLock.h \
posix/FtimeStrategy.h \
posix/GetTimeOfDayStrategy.h \
posix/Monitor.cxx \
posix/Monitor.h \
posix/PriorityOps.h \
posix/TSS.h \
posix/ThreadOps.cxx \
posix/ThreadOps.h \
solaris/FastRecursiveLock.h \
vanilla/DualMutexRecursiveLock.h \
vanilla/SimpleAtomicCount.cxx \
vanilla/SimpleRecursiveLock.h \
win32/AtomicCount.cxx \
win32/AtomicFastLock.h \
win32/AtomicFastRecursiveLock.h \
win32/FastLock.h \
win32/FastRecursiveLock.h \
win32/Monitor.cxx \
win32/Monitor.h \
win32/PerformanceCounterStrategy.h \
win32/TSS.h \
win32/ThreadOps.cxx \
win32/ThreadOps.h \
win9x/AtomicCount.cxx \
win9x/AtomicFastLock.h

View file

@ -1,39 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTMONITORIMPLSELECT_CXX__
#define __ZTMONITORIMPLSELECT_CXX__
#include "Monitor.h"
// This file will select an implementation for a Monitor based on
// what Monitor.h selects. This method is for selecting the
// source files, to improve portability. Currently, the project is
// based on the autoconf tool-set, which doesn't support conditional
// compilation well. Additionally, this should make the library
// easier to port since its working around conditional compilation
// by using C++ features and people won't have to fiddle around with
// their make tool as much to compile the source
#include ZT_MONITOR_IMPLEMENTATION
#endif

View file

@ -1,60 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTMONITORSELECT_H__
#define __ZTMONITORSELECT_H__
#include "zthread/Config.h"
#if defined(ZT_MONITOR_IMPLEMENTATION)
# error "Reserved symbol defined"
#endif
// Include the dependencies for a Montior
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
// Select the correct Monitor implementation based on
// what the compilation environment has defined
#if defined(ZT_POSIX)
# include "posix/Monitor.h"
# define ZT_MONITOR_IMPLEMENTATION "posix/Monitor.cxx"
#elif defined(ZT_WIN32) || defined(ZT_WIN9X)
# include "win32/Monitor.h"
# define ZT_MONITOR_IMPLEMENTATION "win32/Monitor.cxx"
#elif defined(ZT_MACOS)
# include "macos/Monitor.h"
# define ZT_MONITOR_IMPLEMENTATION "macos/Monitor.cxx"
#endif
#ifndef __ZTMONITOR_H__
#error "No Monitor implementation could be selected"
#endif
#endif // __ZTMONITORSELECT_H__

View file

@ -1,68 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/Mutex.h"
#include "MutexImpl.h"
namespace ZThread {
class FifoMutexImpl : public MutexImpl<fifo_list, NullBehavior> { };
Mutex::Mutex() {
_impl = new FifoMutexImpl();
}
Mutex::~Mutex() {
if(_impl != 0)
delete _impl;
}
// P
void Mutex::acquire() {
_impl->acquire();
}
// P
bool Mutex::tryAcquire(unsigned long ms) {
return _impl->tryAcquire(ms);
}
// V
void Mutex::release() {
_impl->release();
}
} // namespace ZThread

View file

@ -1,377 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/Exceptions.h"
#include "zthread/Guard.h"
#include "Debug.h"
#include "FastLock.h"
#include "Scheduling.h"
#include <assert.h>
#include <errno.h>
namespace ZThread {
/**
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T19:52:12-0400>
* @version 2.2.11
* @class NullBehavior
*/
class NullBehavior {
protected:
inline void waiterArrived(ThreadImpl*) { }
inline void waiterDeparted(ThreadImpl*) { }
inline void ownerAcquired(ThreadImpl*) { }
inline void ownerReleased(ThreadImpl*) { }
};
/**
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T19:52:12-0400>
* @version 2.2.11
* @class MutexImpl
*
* The MutexImpl template allows how waiter lists are sorted, and
* what actions are taken when a thread interacts with the mutex
* to be parametized.
*/
template <typename List, typename Behavior>
class MutexImpl : Behavior {
//! List of Events that are waiting for notification
List _waiters;
//! Serialize access to this Mutex
FastLock _lock;
//! Current owner
volatile ThreadImpl* _owner;
public:
/**
* Create a new MutexImpl
*
* @exception Initialization_Exception thrown if resources could not be
* properly allocated
*/
MutexImpl() : _owner(0) { }
~MutexImpl();
void acquire();
void release();
bool tryAcquire(unsigned long timeout);
};
/**
* Destroy this MutexImpl and release its resources
*/
template<typename List, typename Behavior>
MutexImpl<List, Behavior>::~MutexImpl() {
#ifndef NDEBUG
// It is an error to destroy a mutex that has not been released
if(_owner != 0) {
ZTDEBUG("** You are destroying a mutex which was never released. **\n");
assert(0); // Destroyed mutex while in use
}
if(!_waiters.empty()) {
ZTDEBUG("** You are destroying a mutex which is blocking %d threads. **\n", _waiters.size());
assert(0); // Destroyed mutex while in use
}
#endif
}
/**
* Acquire a lock on the mutex. If this operation succeeds the calling
* thread holds an exclusive lock on this mutex, otherwise it is blocked
* until the lock can be acquired.
*
* @exception Deadlock_Exception thrown when the caller attempts to acquire() more
* than once, If the checking flag is set.
* @exception Interrupted_Exception thrown when the caller status is interrupted
* @exception Synchronization_Exception thrown if there is some other error.
*/
template<typename List, typename Behavior>
void MutexImpl<List, Behavior>::acquire() {
ThreadImpl* self = ThreadImpl::current();
Monitor& m = self->getMonitor();
Monitor::STATE state;
Guard<FastLock> g1(_lock);
// Deadlock will occur if the current thread is the owner
// and there is no entry count.
if(_owner == self)
throw Deadlock_Exception();
// Acquire the lock if it is free and there are no waiting threads
if(_owner == 0 && _waiters.empty()) {
_owner = self;
this->ownerAcquired(self);
}
// Otherwise, wait for a signal from a thread releasing its
// ownership of the lock
else {
_waiters.insert(self);
m.acquire();
this->waiterArrived(self);
{
Guard<FastLock, UnlockedScope> g2(g1);
state = m.wait();
}
this->waiterDeparted(self);
m.release();
// Remove from waiter list, regardless of wether release() is called or
// not. The monitor is sticky, so its possible a state 'stuck' from a
// previous operation and will leave the wait() w/o release() having
// been called (e.g. interrupted)
typename List::iterator i = std::find(_waiters.begin(), _waiters.end(), self);
if(i != _waiters.end())
_waiters.erase(i);
// If awoke due to a notify(), take ownership.
switch(state) {
case Monitor::SIGNALED:
assert(_owner == 0);
_owner = self;
this->ownerAcquired(self);
break;
case Monitor::INTERRUPTED:
throw Interrupted_Exception();
default:
throw Synchronization_Exception();
}
}
}
/**
* Acquire a lock on the mutex. If this operation succeeds the calling
* thread holds an exclusive lock on this mutex. If the lock cannot be
* obtained before the timeout expires, the caller returns false.
*
* @exception Deadlock_Exception thrown when the caller attempts to acquire() more
* than once, If the checking flag is set.
* @exception Interrupted_Exception thrown when the caller status is interrupted
* @exception Synchronization_Exception thrown if there is some other error.
*/
template<typename List, typename Behavior>
bool MutexImpl<List, Behavior>::tryAcquire(unsigned long timeout) {
ThreadImpl* self = ThreadImpl::current();
Monitor& m = self->getMonitor();
Guard<FastLock> g1(_lock);
// Deadlock will occur if the current thread is the owner
// and there is no entry count.
if(_owner == self)
throw Deadlock_Exception();
// Acquire the lock if it is free and there are no waiting threads
if(_owner == 0 && _waiters.empty()) {
_owner = self;
this->ownerAcquired(self);
}
// Otherwise, wait for a signal from a thread releasing its
// ownership of the lock
else {
_waiters.insert(self);
Monitor::STATE state = Monitor::TIMEDOUT;
// Don't bother waiting if the timeout is 0
if(timeout) {
m.acquire();
this->waiterArrived(self);
{
Guard<FastLock, UnlockedScope> g2(g1);
state = m.wait(timeout);
}
this->waiterDeparted(self);
m.release();
}
// Remove from waiter list, regarless of weather release() is called or
// not. The monitor is sticky, so its possible a state 'stuck' from a
// previous operation and will leave the wait() w/o release() having
// been called.
typename List::iterator i = std::find(_waiters.begin(), _waiters.end(), self);
if(i != _waiters.end())
_waiters.erase(i);
// If awoke due to a notify(), take ownership.
switch(state) {
case Monitor::SIGNALED:
assert(0 == _owner);
_owner = self;
this->ownerAcquired(self);
break;
case Monitor::INTERRUPTED:
throw Interrupted_Exception();
case Monitor::TIMEDOUT:
return false;
default:
throw Synchronization_Exception();
}
}
return true;
}
/**
* Release a lock on the mutex. If this operation succeeds the calling
* thread no longer holds an exclusive lock on this mutex. If there are
* waiting threads, one will be selected, assigned ownership and specifically
* awakened.
*
* @exception InvalidOp_Exception - thrown if an attempt is made to
* release a mutex not owned by the calling thread.
*/
template<typename List, typename Behavior>
void MutexImpl<List, Behavior>::release() {
ThreadImpl* impl = ThreadImpl::current();
Guard<FastLock> g1(_lock);
// Make sure the operation is valid
if(_owner != impl)
throw InvalidOp_Exception();
_owner = 0;
this->ownerReleased(impl);
// Try to find a waiter with a backoff & retry scheme
for(;;) {
// Go through the list, attempt to notify() a waiter.
for(typename List::iterator i = _waiters.begin(); i != _waiters.end();) {
// Try the monitor lock, if it cant be locked skip to the next waiter
impl = *i;
Monitor& m = impl->getMonitor();
if(m.tryAcquire()) {
// If notify() is not sucessful, it is because the wait() has already
// been ended (killed/interrupted/notify'd)
bool woke = m.notify();
m.release();
// Once notify() succeeds, return
if(woke)
return;
} else ++i;
}
if(_waiters.empty())
return;
{ // Backoff and try again
Guard<FastLock, UnlockedScope> g2(g1);
ThreadImpl::yield();
}
}
}
} // namespace ZThread

View file

@ -1,629 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "ThreadImpl.h"
#include "zthread/PoolExecutor.h"
#include "zthread/MonitoredQueue.h"
#include "zthread/FastMutex.h"
#include "ThreadImpl.h"
#include "ThreadQueue.h"
#include <algorithm>
#include <deque>
#include <utility>
using namespace ZThread;
namespace ZThread {
namespace {
/**
*/
class WaiterQueue {
typedef std::deque<ThreadImpl*> ThreadList;
typedef struct group_t {
size_t id;
size_t count;
ThreadList waiters;
group_t(size_t n) : id(n), count(0) {}
} Group;
typedef std::deque<Group> GroupList;
//! Predicate to find a specific group
struct by_id : public std::unary_function<bool, Group> {
size_t id;
by_id(size_t n) : id(n) {}
bool operator()(const Group& grp) {
return grp.id == id;
}
};
//! Functor to count groups
struct counter : public std::unary_function<void, Group> {
size_t count;
counter() : count(0) {}
void operator()(const Group& grp) { count += grp.count; }
operator size_t() { return count; }
};
FastMutex _lock;
GroupList _list;
size_t _id;
size_t _generation;
public:
WaiterQueue() : _id(0), _generation(0) {
// At least one empty-group exists
_list.push_back( Group(_id++) );
}
/**
* Insert the current thread into the current waiter list
*
* @pre At least one empty group exists
* @post At least one empty group exists
*/
bool wait(unsigned long timeout) {
ThreadImpl* current = ThreadImpl::current();
Monitor& m = current->getMonitor();
Monitor::STATE state;
Guard<FastMutex> g1(_lock);
// At least one empty-group exists
assert(!_list.empty());
// Return w/o waiting if there are no executing tasks
if((size_t)std::for_each(_list.begin(), _list.end(), counter()) < 1)
return true;
// Update the waiter list for the active group
_list.back().waiters.push_back(current);
size_t n = _list.back().id;
m.acquire();
{
Guard<FastMutex, UnlockedScope> g2(g1);
state = timeout == 0 ? m.wait() : m.wait(timeout);
}
m.release();
// If awoke due to a reason other than the last task in the group 'n' completing,
// then then find the group 'current' is waiting in
GroupList::iterator i = std::find_if(_list.begin(), _list.end(), by_id(n));
if(i != _list.end()) {
// Remove 'current' from that list if it is still a member
ThreadList::iterator j = std::find(i->waiters.begin(), i->waiters.end(), current);
if(j != i->waiters.end())
i->waiters.erase(j);
}
// At least one empty-group exists
assert(!_list.empty());
switch(state) {
case Monitor::SIGNALED:
break;
case Monitor::TIMEDOUT:
return false;
case Monitor::INTERRUPTED:
throw Interrupted_Exception();
default:
throw Synchronization_Exception();
}
return true;
}
/**
* Increment the active group count
*
* @pre at least 1 empty group exists
* @post at least 1 non-empty group exists
*/
std::pair<size_t, size_t> increment() {
Guard<FastMutex> g(_lock);
// At least one empty-group exists
assert(!_list.empty());
GroupList::iterator i = --_list.end();
size_t n = i->id;
if(i == _list.end()) {
// A group should never have been removed until
// the final task in that group completed
assert(0);
}
i->count++;
// When the active group is being incremented, insert a new active group
// to replace it if there were waiting threads
if(i == --_list.end() && !i->waiters.empty())
_list.push_back(Group(_id++));
// At least 1 non-empty group exists
assert((size_t)std::for_each(_list.begin(), _list.end(), counter()) > 0);
return std::make_pair(n, _generation);
}
/**
* Decrease the count for the group with the given id.
*
* @param n group id
*
* @pre At least 1 non-empty group exists
* @post At least 1 empty group exists
*/
void decrement(size_t n) {
Guard<FastMutex> g1(_lock);
// At least 1 non-empty group exists
assert((size_t)std::for_each(_list.begin(), _list.end(), counter()) > 0);
// Find the requested group
GroupList::iterator i = std::find_if(_list.begin(), _list.end(), by_id(n));
if(i == _list.end()) {
// A group should never have been removed until
// the final task in that group completed
assert(0);
}
// Decrease the count for tasks in this group,
if(--i->count == 0 && i == _list.begin()) {
do {
// When the first group completes, wake all waiters for every
// group, starting from the first until a group that is not
// complete is reached
/*
// Don't remove the empty active group
if(i == --_list.end() && i->waiters.empty())
break;
*/
if( awaken(*i) ) {
// If all waiters were awakened, remove the group
i = _list.erase(i);
} else {
{
// Otherwise, unlock and yield allowing the waiter
// lists to be updated if other threads are busy
Guard<FastLock, UnlockedScope> g2(g1);
ThreadImpl::yield();
}
i = _list.begin();
}
} while(i != _list.end() && i->count == 0);
// Ensure that an active group exists
if(_list.empty())
_list.push_back( Group(++_id) );
}
// At least one group exists
assert(!_list.empty());
}
/**
*/
size_t generation(bool next = false) {
Guard<FastMutex> g(_lock);
return next ? _generation++ : _generation;
}
private:
/**
* Awaken all the waiters remaining in the given group
*
* @return
* - true if all the waiting threads were successfully awakened.
* - false if there were one or more threads that could not be awakened.
*/
bool awaken(Group& grp) {
// Go through the waiter list in the given group;
for(ThreadList::iterator i = grp.waiters.begin(); i != grp.waiters.end();) {
ThreadImpl* impl = *i;
Monitor& m = impl->getMonitor();
// Try the monitor lock, if it cant be locked skip to the next waiter
if(m.tryAcquire()) {
// Notify the monitor & remove from the waiter list so time isn't
// wasted checking it again.
i = grp.waiters.erase(i);
// Try to wake the waiter, it doesn't matter if this is successful
// or not (only fails when the monitor is already going to stop waiting).
m.notify();
m.release();
} else ++i;
}
return grp.waiters.empty();
}
};
/**
* @class GroupedRunnable
*
* Wrap a task with group and generation information.
*
* - 'group' allows tasks to be grouped together so that lists of waiting
* threads can be managed.
*
* - 'generation' allows tasks to be interrupted
*/
class GroupedRunnable : public Runnable {
Task _task;
WaiterQueue& _queue;
size_t _group;
size_t _generation;
public:
GroupedRunnable(const Task& task, WaiterQueue& queue)
: _task(task), _queue(queue) {
std::pair<size_t, size_t> pr( _queue.increment() );
_group = pr.first;
_generation = pr.second;
}
size_t group() const {
return _group;
}
size_t generation() const {
return _generation;
}
void run() {
try {
_task->run();
} catch(...) {
}
_queue.decrement( group() );
}
};
typedef CountedPtr<GroupedRunnable, size_t> ExecutorTask;
/**
*
*/
class ExecutorImpl {
typedef MonitoredQueue<ExecutorTask, FastMutex> TaskQueue;
typedef std::deque<ThreadImpl*> ThreadList;
TaskQueue _taskQueue;
WaiterQueue _waitingQueue;
ThreadList _threads;
volatile size_t _size;
public:
ExecutorImpl() : _size(0) {}
void registerThread() {
Guard<TaskQueue> g(_taskQueue);
ThreadImpl* impl = ThreadImpl::current();
_threads.push_back(impl);
// current cancel if too many threads are being created
if(_threads.size() > _size)
impl->cancel();
}
void unregisterThread() {
Guard<TaskQueue> g(_taskQueue);
std::remove(_threads.begin(), _threads.end(), ThreadImpl::current());
}
void execute(const Task& task) {
// Wrap the task with a grouped task
GroupedRunnable* runnable = new GroupedRunnable(task, _waitingQueue);
try {
_taskQueue.add( ExecutorTask(runnable) );
} catch(...) {
// Incase the queue is canceled between the time the WaiterQueue is
// updated and the task is added to the TaskQueue
_waitingQueue.decrement( runnable->group() );
throw;
}
}
void interrupt() {
// Bump the generation number
_waitingQueue.generation(true);
Guard<TaskQueue> g(_taskQueue);
// Interrupt all threads currently running, thier tasks would be
// from an older generation
for(ThreadList::iterator i = _threads.begin(); i != _threads.end(); ++i)
(*i)->interrupt();
}
//! Adjust the number of desired workers and return the number of Threads needed
size_t workers(size_t n) {
Guard<TaskQueue> g(_taskQueue);
size_t m = (_size < n) ? (n - _size) : 0;
_size = n;
return m;
}
size_t workers() {
Guard<TaskQueue> g(_taskQueue);
return _size;
}
ExecutorTask next() {
ExecutorTask task;
// Draw the task from the queue
for(;;) {
try {
task = _taskQueue.next();
break;
} catch(Interrupted_Exception&) {
// Ignore interruption here, it can only come from
// another thread interrupt()ing the executor. The
// thread was interrupted in the hopes it was busy
// with a task
}
}
// Interrupt the thread running the tasks when the generation
// does not match the current generation
if( task->generation() != _waitingQueue.generation() )
ThreadImpl::current()->interrupt();
// Otherwise, clear the interrupted status for the thread and
// give it a clean slate to start with
else
ThreadImpl::current()->isInterrupted();
return task;
}
bool isCanceled() {
return _taskQueue.isCanceled();
}
void cancel() {
_taskQueue.cancel();
}
bool wait(unsigned long timeout) {
return _waitingQueue.wait(timeout);
}
};
//! Executor job
class Worker : public Runnable {
CountedPtr< ExecutorImpl > _impl;
public:
//! Create a Worker that draws upon the given Queue
Worker(const CountedPtr< ExecutorImpl >& impl)
: _impl(impl) { }
//! Run until Thread or Queue are canceled
void run() {
_impl->registerThread();
// Run until the Queue is canceled
while(!Thread::canceled()) {
// Draw tasks from the queue
ExecutorTask task( _impl->next() );
task->run();
}
_impl->unregisterThread();
}
}; /* Worker */
//! Helper
class Shutdown : public Runnable {
CountedPtr< ExecutorImpl > _impl;
public:
Shutdown(const CountedPtr< ExecutorImpl >& impl)
: _impl(impl) { }
void run() {
_impl->cancel();
}
}; /* Shutdown */
}
PoolExecutor::PoolExecutor(size_t n)
: _impl( new ExecutorImpl() ), _shutdown( new Shutdown(_impl) ) {
size(n);
// Request cancelation when main() exits
ThreadQueue::instance()->insertShutdownTask(_shutdown);
}
PoolExecutor::~PoolExecutor() {
try {
/**
* If the shutdown task for this executor has not already been
* selected to run, then run it locally
*/
if(ThreadQueue::instance()->removeShutdownTask(_shutdown))
_shutdown->run();
} catch(...) { }
}
void PoolExecutor::interrupt() {
_impl->interrupt();
}
void PoolExecutor::size(size_t n) {
if(n < 1)
throw InvalidOp_Exception();
for(size_t m = _impl->workers(n); m > 0; --m)
Thread t(new Worker(_impl));
}
size_t PoolExecutor::size() {
return _impl->workers();
}
void PoolExecutor::execute(const Task& task) {
// Enqueue the task, the Queue will reject it with a
// Cancelation_Exception if the Executor has been canceled
_impl->execute(task);
}
void PoolExecutor::cancel() {
_impl->cancel();
}
bool PoolExecutor::isCanceled() {
return _impl->isCanceled();
}
void PoolExecutor::wait() {
_impl->wait(0);
}
bool PoolExecutor::wait(unsigned long timeout) {
return _impl->wait(timeout == 0 ? 1 : timeout);
}
}

View file

@ -1,80 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/PriorityCondition.h"
#include "ConditionImpl.h"
namespace ZThread {
class PriorityConditionImpl : public ConditionImpl<priority_list> {
public:
PriorityConditionImpl(Lockable& l) : ConditionImpl<priority_list>(l) {}
};
PriorityCondition::PriorityCondition(Lockable& lock) {
_impl = new PriorityConditionImpl(lock);
}
PriorityCondition::~PriorityCondition() {
if(_impl != 0)
delete _impl;
}
void PriorityCondition::wait() {
_impl->wait();
}
bool PriorityCondition::wait(unsigned long ms) {
return _impl->wait(ms);
}
void PriorityCondition::signal() {
_impl->signal();
}
void PriorityCondition::broadcast() {
_impl->broadcast();
}
} // namespace ZThread

View file

@ -1,109 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/PriorityInheritanceMutex.h"
#include "MutexImpl.h"
#include "ThreadOps.h"
namespace ZThread {
class InheritPriorityBehavior : public NullBehavior {
ThreadImpl* owner;
Priority p;
protected:
// Temporarily raise the effective priority of the owner
inline void waiterArrived(ThreadImpl* impl) {
Priority q = impl->getPriority();
if((int)q > (int)p) {
ThreadOps::setPriority(impl, p);
p = q;
}
}
// Note the owners priority
inline void ownerAcquired(ThreadImpl* impl) {
p = impl->getPriority();
owner = impl;
}
// Restore its original priority
inline void ownerReleased(ThreadImpl* impl) {
if(p > owner->getPriority())
ThreadOps::setPriority(impl, impl->getPriority());
}
};
class PriorityInheritanceMutexImpl :
public MutexImpl<priority_list, InheritPriorityBehavior> { };
PriorityInheritanceMutex::PriorityInheritanceMutex() {
_impl = new PriorityInheritanceMutexImpl();
}
PriorityInheritanceMutex::~PriorityInheritanceMutex() {
if(_impl != 0)
delete _impl;
}
// P
void PriorityInheritanceMutex::acquire() {
_impl->acquire();
}
// P
bool PriorityInheritanceMutex::tryAcquire(unsigned long ms) {
return _impl->tryAcquire(ms);
}
// V
void PriorityInheritanceMutex::release() {
_impl->release();
}
} // namespace ZThread

View file

@ -1,69 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/PriorityMutex.h"
#include "MutexImpl.h"
#include "ThreadOps.h"
namespace ZThread {
class PriorityMutexImpl : public MutexImpl<priority_list, NullBehavior> { };
PriorityMutex::PriorityMutex() {
_impl = new PriorityMutexImpl();
}
PriorityMutex::~PriorityMutex() {
if(_impl != 0)
delete _impl;
}
// P
void PriorityMutex::acquire() {
_impl->acquire();
}
// P
bool PriorityMutex::tryAcquire(unsigned long ms) {
return _impl->tryAcquire(ms);
}
// V
void PriorityMutex::release() {
_impl->release();
}
} // namespace ZThread

View file

@ -1,104 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "Debug.h"
#include "zthread/PrioritySemaphore.h"
#include "SemaphoreImpl.h"
namespace ZThread {
class PrioritySemaphoreImpl : public SemaphoreImpl<priority_list> {
public:
PrioritySemaphoreImpl(int count, unsigned int maxCount)
: SemaphoreImpl<priority_list>(count, maxCount, true) { }
};
/**
* Create a new semaphore of a given size with a given count
*
* @param initialCount initial count to assign this semaphore
* @param maxCount maximum size of the semaphore count
*/
PrioritySemaphore::PrioritySemaphore(int count, unsigned int maxCount) {
_impl = new PrioritySemaphoreImpl(count, maxCount);
}
PrioritySemaphore::~PrioritySemaphore() {
if(_impl != 0)
delete _impl;
}
void PrioritySemaphore::wait() {
_impl->acquire();
}
bool PrioritySemaphore::tryWait(unsigned long ms) {
return _impl->tryAcquire(ms);
}
void PrioritySemaphore::post() {
_impl->release();
}
int PrioritySemaphore::count() {
return _impl->count();
}
///////////////////////////////////////////////////////////////////////////////
// Locakable compatibility
//
void PrioritySemaphore::acquire() {
_impl->acquire();
}
bool PrioritySemaphore::tryAcquire(unsigned long ms) {
return _impl->tryAcquire(ms);
}
void PrioritySemaphore::release() {
_impl->release();
}
} // namespace ZThread

View file

@ -1,61 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/RecursiveMutex.h"
#include "RecursiveMutexImpl.h"
namespace ZThread {
RecursiveMutex::RecursiveMutex() {
_impl = new RecursiveMutexImpl();
}
RecursiveMutex::~RecursiveMutex() {
if(_impl != (RecursiveMutexImpl*)0 )
delete _impl;
}
void RecursiveMutex::acquire() {
_impl->acquire();
}
bool RecursiveMutex::tryAcquire(unsigned long ms) {
return _impl->tryAcquire(ms);
}
void RecursiveMutex::release() {
_impl->release();
}
} // namespace ZThread

View file

@ -1,286 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "Debug.h"
#include "RecursiveMutexImpl.h"
#include "ThreadImpl.h"
#include "zthread/Guard.h"
#include <assert.h>
#include <errno.h>
#include <algorithm>
namespace ZThread {
/**
* Create a new RecursiveMutexImpl
*
* @exception Initialization_Exception thrown if resources could not be
* properly allocated
*/
RecursiveMutexImpl::RecursiveMutexImpl()
: _owner(0), _count(0) {
}
/**
* Destroy this RecursiveMutexImpl and release its resources
*/
RecursiveMutexImpl::~RecursiveMutexImpl() {
#ifndef NDEBUG
// It is an error to destroy a mutex that has not been released
if(_owner != 0) {
ZTDEBUG("** You are destroying a mutex which was never released. **\n");
assert(0); // Destroyed mutex while in use
}
if(!_waiters.empty()) {
ZTDEBUG("** You are destroying a mutex which is blocking %d threads. **\n", _waiters.size());
assert(0); // Destroyed mutex while in use
}
#endif
}
void RecursiveMutexImpl::acquire() {
// Get the monitor for the current thread
Monitor& m = ThreadImpl::current()->getMonitor();
Monitor::STATE state;
Guard<FastLock> g1(_lock);
// If there is an entry count and the current thread is
// the owner, increment the count and continue.
if(_owner == &m)
_count++;
else {
// Acquire the lock if it is free and there are no waiting threads
if(_owner == 0 && _waiters.empty()) {
assert(_count == 0);
_owner = &m;
_count++;
} else { // Otherwise, wait()
_waiters.push_back(&m);
m.acquire();
{
Guard<FastLock, UnlockedScope> g2(g1);
state = m.wait();
}
m.release();
// Remove from waiter list, regarless of weather release() is called or
// not. The monitor is sticky, so its possible a state 'stuck' from a
// previous operation and will leave the wait() w/o release() having
// been called.
List::iterator i = std::find(_waiters.begin(), _waiters.end(), &m);
if(i != _waiters.end())
_waiters.erase(i);
// If awoke due to a notify(), take ownership.
switch(state) {
case Monitor::SIGNALED:
assert(_owner == 0);
assert(_count == 0);
_owner = &m;
_count++;
break;
case Monitor::INTERRUPTED:
throw Interrupted_Exception();
default:
throw Synchronization_Exception();
}
}
}
}
bool RecursiveMutexImpl::tryAcquire(unsigned long timeout) {
// Get the monitor for the current thread
Monitor& m = ThreadImpl::current()->getMonitor();
Guard<FastLock> g1(_lock);
// If there is an entry count and the current thread is
// the owner, increment the count and continue.
if(_owner == &m)
_count++;
else {
// Acquire the lock if it is free and there are no waiting threads
if(_owner == 0 && _waiters.empty()) {
assert(_count == 0);
_owner = &m;
_count++;
} else { // Otherwise, wait()
_waiters.push_back(&m);
Monitor::STATE state = Monitor::TIMEDOUT;
// Don't bother waiting if the timeout is 0
if(timeout) {
m.acquire();
{
Guard<FastLock, UnlockedScope> g2(g1);
state = m.wait(timeout);
}
m.release();
}
// Remove from waiter list, regarless of weather release() is called or
// not. The monitor is sticky, so its possible a state 'stuck' from a
// previous operation and will leave the wait() w/o release() having
// been called.
List::iterator i = std::find(_waiters.begin(), _waiters.end(), &m);
if(i != _waiters.end())
_waiters.erase(i);
// If awoke due to a notify(), take ownership.
switch(state) {
case Monitor::SIGNALED:
assert(_count == 0);
assert(_owner == 0);
_owner = &m;
_count++;
break;
case Monitor::INTERRUPTED:
throw Interrupted_Exception();
case Monitor::TIMEDOUT:
return false;
default:
throw Synchronization_Exception();
}
}
}
return true;
}
void RecursiveMutexImpl::release() {
// Get the monitor for the current thread
Monitor& m = ThreadImpl::current()->getMonitor();
Guard<FastLock> g1(_lock);
// Make sure the operation is valid
if(!(_owner == &m))
throw InvalidOp_Exception();
// Update the count, if it has reached 0, wake another waiter.
if(--_count == 0) {
_owner = 0;
// Try to find a waiter with a backoff & retry scheme
for(;;) {
// Go through the list, attempt to notify() a waiter.
for(List::iterator i = _waiters.begin(); i != _waiters.end();) {
// Try the monitor lock, if it cant be locked skip to the next waiter
Monitor* n = *i;
if(n->tryAcquire()) {
// If notify() is not sucessful, it is because the wait() has already
// been ended (killed/interrupted/notify'd)
bool woke = n->notify();
n->release();
// Once notify() succeeds, return
if(woke)
return;
} else ++i;
}
if(_waiters.empty())
return;
{ // Backoff and try again
Guard<FastLock, UnlockedScope> g2(g1);
ThreadImpl::yield();
}
}
}
}
} // namespace ZThread

View file

@ -1,78 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTRECURSIVEMUTEXIMPL_H__
#define __ZTRECURSIVEMUTEXIMPL_H__
#include "zthread/Exceptions.h"
#include "FastLock.h"
#include <vector>
namespace ZThread {
class Monitor;
/**
* @class RecursiveMutexImpl
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T19:58:26-0400>
* @version 2.1.6
*
* This synchronization object provides serialized access
* through an acquire/release protocol.
*/
class ZTHREAD_API RecursiveMutexImpl {
typedef std::vector<Monitor*> List;
//! List of Events that are waiting for notification
List _waiters;
//! Serialize access to this Mutex
FastLock _lock;
//! Current owning Event object
Monitor* _owner;
//! Entry count
size_t _count;
public:
RecursiveMutexImpl();
virtual ~RecursiveMutexImpl();
void acquire();
bool tryAcquire(unsigned long);
void release();
}; /* RecursiveMutexImpl */
};
#endif

View file

@ -1,96 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTSCHEDULING_H__
#define __ZTSCHEDULING_H__
#include "ThreadImpl.h"
#include <algorithm>
#include <functional>
#include <deque>
#include <utility>
namespace ZThread {
/**
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T20:01:18-0400>
* @version 2.2.0
* @class fifo_list
*/
class fifo_list : public std::deque<ThreadImpl*> {
public:
void insert(const value_type& val) { push_back(val); }
};
/**
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T20:01:18-0400>
* @version 2.2.0
* @struct priority_order
*/
struct priority_order : public std::binary_function<ThreadImpl*, ThreadImpl*, bool> {
std::less<const ThreadImpl*> id;
bool operator()(const ThreadImpl* t0, const ThreadImpl* t1) const {
if(t0->getPriority() > t1->getPriority())
return true;
else if (t0->getPriority() < t1->getPriority())
return false;
return id(t0, t1);
}
};
/**
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T20:01:18-0400>
* @version 2.2.0
* @class priority_list
*/
class priority_list : public std::deque<ThreadImpl*> {
priority_order comp;
public:
void insert(const value_type& val) {
push_back(val);
std::sort(begin(), end(), comp);
}
};
} // namespace ZThread
#endif // __ZTSCHEDULING_H__

View file

@ -1,101 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/Semaphore.h"
#include "SemaphoreImpl.h"
namespace ZThread {
/**
* Create a new semaphore of a given size with a given count
*
* @param initialCount initial count to assign this semaphore
* @param maxCount maximum size of the semaphore count
*/
Semaphore::Semaphore(int count, unsigned int maxCount) {
_impl = new FifoSemaphoreImpl(count, maxCount, true);
}
Semaphore::~Semaphore() {
if(_impl != 0)
delete _impl;
}
void Semaphore::wait() {
_impl->acquire();
}
bool Semaphore::tryWait(unsigned long ms) {
return _impl->tryAcquire(ms);
}
void Semaphore::post() {
_impl->release();
}
int Semaphore::count() {
return _impl->count();
}
///////////////////////////////////////////////////////////////////////////////
// Locakable compatibility
//
void Semaphore::acquire() {
_impl->acquire();
}
bool Semaphore::tryAcquire(unsigned long ms) {
return _impl->tryAcquire(ms);
}
void Semaphore::release() {
_impl->release();
}
} // namespace ZThread

View file

@ -1,348 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTSEMAPHOREIMPL_H__
#define __ZTSEMAPHOREIMPL_H__
#include "zthread/Guard.h"
#include "Debug.h"
#include "FastLock.h"
#include "Scheduling.h"
#include <assert.h>
namespace ZThread {
class Monitor;
/**
* @class SemaphoreImpl
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T20:03:20-0400>
* @version 2.2.11
*
* The SemaphoreImpl template allows how waiter lists are sorted
* to be parameteized
*/
template <typename List>
class SemaphoreImpl {
//! List of waiting events
List _waiters;
//! Serialize access to this object
FastLock _lock;
//! Current count
volatile int _count;
//! Maximum count if any
volatile int _maxCount;
//! Flag for bounded or unbounded count
volatile bool _checked;
//! Entry count
volatile int _entryCount;
public:
/**
* Create a new SemaphoreImpl. Initialzes one pthreads mutex for
* internal use.
*
* @exception Initialization_Exception thrown if resources could not be
* properly allocated
*/
SemaphoreImpl(int count, unsigned int maxCount, bool checked)
: _count(count), _maxCount(maxCount), _checked(checked), _entryCount(0) { }
~SemaphoreImpl();
void acquire();
void release();
bool tryAcquire(unsigned long timeout);
int count();
};
/**
* Destroy this SemaphoreImpl and release its resources.
*/
template <typename List>
SemaphoreImpl<List>::~SemaphoreImpl() {
#ifndef NDEBUG
if(!_waiters.empty()) {
ZTDEBUG("** You are destroying a semaphore which is blocking %d threads. **\n", _waiters.size());
assert(0); // Destroyed semaphore while in use
}
#endif
}
/**
* Get the count for the Semaphore
*
* @return int
*/
template <typename List>
int SemaphoreImpl<List>::count() {
Guard<FastLock> g(_lock);
return _count;
}
/**
* Decrement the count, blocking when that count becomes 0 or less.
*
* @exception Interrupted_Exception thrown when the caller status is interrupted
* @exception Synchronization_Exception thrown if there is some other error.
*/
template <typename List>
void SemaphoreImpl<List>::acquire() {
// Get the monitor for the current thread
ThreadImpl* self = ThreadImpl::current();
Monitor& m = self->getMonitor();
Monitor::STATE state;
Guard<FastLock> g1(_lock);
// Update the count without waiting if possible.
if(_count > 0 && _entryCount == 0)
_count--;
// Otherwise, wait() for the lock by placing the waiter in the list
else {
++_entryCount;
_waiters.insert(self);
m.acquire();
{
Guard<FastLock, UnlockedScope> g2(g1);
state = m.wait();
}
m.release();
// Remove from waiter list, regarless of weather release() is called or
// not. The monitor is sticky, so its possible a state 'stuck' from a
// previous operation and will leave the wait() w/o release() having
// been called.
typename List::iterator i = std::find(_waiters.begin(), _waiters.end(), self);
if(i != _waiters.end())
_waiters.erase(i);
--_entryCount;
switch(state) {
// If awoke due to a notify(), update the count
case Monitor::SIGNALED:
_count--;
break;
case Monitor::INTERRUPTED:
throw Interrupted_Exception();
default:
throw Synchronization_Exception();
}
}
}
/**
* Decrement the count, blocking when it that count is 0 or less. If the timeout
* expires before the count is raise above 0, the thread will stop blocking
* and return.
*
* @exception Interrupted_Exception thrown when the caller status is interrupted
* @exception Synchronization_Exception thrown if there is some other error.
*/
template <typename List>
bool SemaphoreImpl<List>::tryAcquire(unsigned long timeout) {
// Get the monitor for the current thread
ThreadImpl* self = ThreadImpl::current();
Monitor& m = self->getMonitor();
Guard<FastLock> g1(_lock);
// Update the count without waiting if possible.
if(_count > 0 && _entryCount == 0)
_count--;
// Otherwise, wait() for the lock by placing the waiter in the list
else {
++_entryCount;
_waiters.push_back(self);
Monitor::STATE state = Monitor::TIMEDOUT;
// Don't bother waiting if the timeout is 0
if(timeout) {
m.acquire();
{
Guard<FastLock, UnlockedScope> g2(g1);
state = m.wait(timeout);
}
m.release();
}
// Remove from waiter list, regarless of weather release() is called or
// not. The monitor is sticky, so its possible a state 'stuck' from a
// previous operation and will leave the wait() w/o release() having
// been called.
typename List::iterator i = std::find(_waiters.begin(), _waiters.end(), self);
if(i != _waiters.end())
_waiters.erase(i);
--_entryCount;
switch(state) {
// If awoke due to a notify(), update the count
case Monitor::SIGNALED:
_count--;
break;
case Monitor::INTERRUPTED:
throw Interrupted_Exception();
case Monitor::TIMEDOUT:
return false;
default:
throw Synchronization_Exception();
}
}
return true;
}
/**
* Increment the count and release a waiter if there are any. If the semaphore
* is checked, then an exception will be raised if the maximum count is about to
* be exceeded.
*
* @exception InvalidOp_Exception thrown if the maximum count is exceeded while
* the checked flag is set.
*/
template <typename List>
void SemaphoreImpl<List>::release() {
Guard<FastLock> g1(_lock);
// Make sure the operation is valid
if(_checked && _count == _maxCount)
throw InvalidOp_Exception();
// Increment the count
_count++;
// Try to find a waiter with a backoff & retry scheme
for(;;) {
// Go through the list, attempt to notify() a waiter.
for(typename List::iterator i = _waiters.begin(); i != _waiters.end();) {
// Try the monitor lock, if it cant be locked skip to the next waiter
ThreadImpl* impl = *i;
Monitor& m = impl->getMonitor();
if(m.tryAcquire()) {
// Notify the monitor & remove from the waiter list so time isn't
// wasted checking it again.
i = _waiters.erase(i);
// If notify() is not sucessful, it is because the wait() has already
// been ended (killed/interrupted/notify'd)
bool woke = m.notify();
m.release();
// Once notify() succeeds, return
if(woke)
return;
} else ++i;
}
if(_waiters.empty())
return;
{ // Backoff and try again
Guard<FastLock, UnlockedScope> g2(g1);
ThreadImpl::yield();
}
}
}
class FifoSemaphoreImpl : public SemaphoreImpl<fifo_list> {
public:
FifoSemaphoreImpl(int count, unsigned int maxCount, bool checked)
/* throw(Synchronization_Exception) */
: SemaphoreImpl<fifo_list>(count, maxCount, checked) { }
};
} // namespace ZThread
#endif // __ZTSEMAPHOREIMPL_H__

View file

@ -1,151 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTSTATE_H__
#define __ZTSTATE_H__
namespace ZThread {
/**
* @class State
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T20:04:01-0400>
* @version 2.2.1
*
* Class to encapsulate the current state of the threads life-cycle.
*/
class State {
public:
//! Various states
typedef enum { REFERENCE, IDLE, RUNNING, JOINED } STATE;
/**
* Create State with the given flag set.
*/
State(STATE initialState) : _state(initialState) {}
/**
* Test for the IDLE state. No task has yet run.
*/
bool isIdle() const {
return _state == IDLE;
}
/**
* Test for the JOINED state. A task has completed and
* the thread is join()ed.
*
* @return bool
*/
bool isJoined() const {
return _state == JOINED;
}
/**
* Test for the RUNNING state. A task is in progress.
*
* @return bool
*/
bool isRunning() const {
return _state == RUNNING;
}
/**
* Test for the REFERENCE state. A task is in progress but not
* under control of this library.
*
* @return bool
*/
bool isReference() const {
return _state == REFERENCE;
}
/**
* Transition to the IDLE state.
*
* @return bool true if successful
*/
bool setIdle() {
if(_state != RUNNING)
return false;
_state = IDLE;
return true;
}
/**
* Transition to the RUNNING state.
*
* @return bool true if successful
*/
bool setRunning() {
if(_state != IDLE)
return false;
_state = RUNNING;
return true;
}
/**
* Transition to the REFERENCE state.
*
* @return bool true if successful
*/
bool setReference() {
if(_state != IDLE)
return false;
_state = REFERENCE;
return true;
}
/**
* Transition to the JOINED state.
*
* @return bool true if successful
*/
bool setJoined() {
_state = JOINED;
return true;
}
private:
//! Current state
STATE _state;
};
};
#endif

View file

@ -1,179 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTBLOCKINGSTATE_H__
#define __ZTBLOCKINGSTATE_H__
#include <assert.h>
namespace ZThread {
/**
* @class Status
* @version 2.3.0
*
* A Status is associated with each Thread's Monitor. Monitors rely on a
* Status object for providing information that will affect a blocking operations.
*/
class Status {
public:
//! Aggregate of pending status changes
volatile unsigned short _pending;
//! Interest mask
volatile unsigned short _mask;
public:
//! State for the monitor
typedef enum {
// Default
INVALID = 0x00,
// Valid states
SIGNALED = 0x01,
INTERRUPTED = 0x02,
TIMEDOUT = 0x04,
CANCELED = 0x08,
// Mask
ANYTHING = (~INVALID & ~CANCELED)
} STATE;
Status() : _pending((unsigned short)INVALID), _mask((unsigned short)ANYTHING) { }
/**
* Set the mask for the STATE's that next() will report.
* STATE's not covered by the interest mask can still be
* set, they just aren't reported until the mask is changed
* to cover that STATE.
*
* @param STATE
* @pre accessed ONLY by the owning thread.
*/
void interest(STATE mask) {
_mask = static_cast<unsigned short>(mask);
}
bool masked(STATE mask) {
return (_mask & static_cast<unsigned short>(mask)) == 0;
}
/**
* Return true if next() will return a STATE covered
* by the current interest mask and by the mask given
* to this function.
*
* @param unsigned short
* @pre accessed ONLY by the owning thread.
*/
bool pending(unsigned short mask) {
assert(mask != INVALID);
return ((_pending & _mask) & mask) != INVALID;
}
/**
* Check the state without the interest mask.
*
* @param state
* @return true if the flag is set
* @pre access must be serial
*/
bool examine(STATE state) {
return (_pending & static_cast<unsigned short>(state)) != INVALID;
}
/**
* Add the flags to the current state.
*
* @param interest - the flags to add to the current state.
* @pre access must be serial
*/
void push(STATE interest) {
_pending |= interest;
}
/**
* Clear the flags from the current state
*
* @param interest - the flags to clear from the current state.
* @pre access must be serial
*/
void clear(STATE interest) {
assert(interest != INVALID);
assert(interest != ANYTHING);
assert(interest != CANCELED);
_pending &= ~interest;
}
/**
* Get the next state from set that has accumulated. The order STATES are
* reported in is SIGNALED, TIMEOUT, or INTERRUPTED. Setting the
* intrest mask allows certain state to be selectively ignored for
* a time - but not lost. The states will become visible again as soon
* as the interest mask is changed appropriately. The interest mask is
* generally used to create uninterruptable waits (waiting for threads
* to start, reacquiring a conditions predicate lock, etc)
*
* @return STATE
* @pre access must be serial
*/
STATE next() {
STATE state = INVALID;
if(((_pending & _mask) & SIGNALED) != 0) {
// Absorb the timeout if it happens when a signal
// is available at the same time
_pending &= ~(SIGNALED|TIMEDOUT);
state = SIGNALED;
} else if(((_pending & _mask) & TIMEDOUT) != 0) {
_pending &= ~TIMEDOUT;
state = TIMEDOUT;
} else if(((_pending & _mask) & INTERRUPTED) != 0) {
_pending &= ~INTERRUPTED;
state = INTERRUPTED;
}
assert(state != INVALID);
return state;
}
};
}; // namespace ZThread
#endif

View file

@ -1,90 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/SynchronousExecutor.h"
namespace ZThread {
SynchronousExecutor::SynchronousExecutor()
: _canceled(false) {}
SynchronousExecutor::~SynchronousExecutor() {
}
void SynchronousExecutor::cancel() {
Guard<Mutex> g(_lock);
_canceled = true;
}
bool SynchronousExecutor::isCanceled() {
Guard<Mutex> g(_lock);
return _canceled;
}
void SynchronousExecutor::interrupt() {
}
void SynchronousExecutor::execute(const Task& task) {
// Canceled Executors will not accept new tasks, quick
// check to avoid excessive locking in the canceled state
if(_canceled)
throw Cancellation_Exception();
Guard<Mutex> g(_lock);
if(_canceled) // Double check
throw Cancellation_Exception();
// Run the task.
Task(task)->run();
}
void SynchronousExecutor::wait() {
if(Thread::interrupted())
throw Interrupted_Exception();
Guard<Mutex> g(_lock);
}
/**
* @see Executor::wait(unsigned long)
*/
bool SynchronousExecutor::wait(unsigned long) {
if(Thread::interrupted())
throw Interrupted_Exception();
Guard<Mutex> g(_lock);
return true;
}
}

View file

@ -1,52 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTTSSSELECT_H__
#define __ZTTSSSELECT_H__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// Select the correct TSS implementation based on
// what the compilation environment has defined
#if defined(ZT_POSIX)
#include "posix/TSS.h"
#elif defined(ZT_WIN32) || defined(ZT_WIN9X)
#include "win32/TSS.h"
#elif defined(ZT_MACOS)
#include "macos/TSS.h"
#endif
#ifndef __ZTTSS_H__
#error "No TSS implementation could be selected"
#endif
#endif // __ZTTSSSELECT_H__

View file

@ -1,127 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/Runnable.h"
#include "zthread/Thread.h"
#include "ThreadImpl.h"
namespace ZThread {
Thread::Thread()
: _impl( ThreadImpl::current() ) {
// ThreadImpl's start out life with a reference count
// of one, and the they are added to the ThreadQueue.
_impl->addReference();
}
Thread::Thread(const Task& task, bool autoCancel)
: _impl( new ThreadImpl(task, autoCancel) ) {
_impl->addReference();
}
bool Thread::operator==(const Thread& t) const {
return (t._impl == _impl);
}
Thread::~Thread() {
_impl->delReference();
}
void Thread::wait() {
_impl->join(0);
}
bool Thread::wait(unsigned long timeout) {
return _impl->join(timeout == 0 ? 1 : timeout);
}
bool Thread::interrupted() {
return ThreadImpl::current()->isInterrupted();
}
bool Thread::canceled() {
return ThreadImpl::current()->isCanceled();
}
void Thread::setPriority(Priority n) {
_impl->setPriority(n);
}
Priority Thread::getPriority() {
return _impl->getPriority();
}
bool Thread::interrupt() {
return _impl->interrupt();
}
void Thread::cancel() {
if(ThreadImpl::current() == _impl)
throw InvalidOp_Exception();
_impl->cancel();
}
bool Thread::isCanceled() {
return _impl->isCanceled();
}
void Thread::sleep(unsigned long ms) {
ThreadImpl::sleep(ms);
}
void Thread::yield() {
ThreadImpl::yield();
}
} // namespace ZThread

View file

@ -1,470 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "Debug.h"
#include "zthread/Runnable.h"
#include "ThreadImpl.h"
#include "ThreadQueue.h"
#include "DeferredInterruptionScope.h"
#include <assert.h>
namespace ZThread {
TSS<ThreadImpl*> ThreadImpl::_threadMap;
namespace {
class Launcher : public Runnable {
ThreadImpl* x;
ThreadImpl* y;
Task z;
public:
Launcher(ThreadImpl* a, ThreadImpl* b, const Task& c) : x(a), y(b), z(c) {}
void run() {
y->dispatch(x,y,z);
}
};
}
ThreadImpl::ThreadImpl()
: _state(State::REFERENCE), _priority(Medium), _autoCancel(false) {
ZTDEBUG("Reference thread created.\n");
}
ThreadImpl::ThreadImpl(const Task& task, bool autoCancel)
: _state(State::IDLE), _priority(Medium), _autoCancel(autoCancel) {
ZTDEBUG("User thread created.\n");
start(task);
}
ThreadImpl::~ThreadImpl() {
_tls.clear();
if(isActive()) {
ZTDEBUG("You are destroying an executing thread!\n");
abort();
}
ZTDEBUG("Thread destroyed.\n");
}
Monitor& ThreadImpl::getMonitor() {
return _monitor;
}
void ThreadImpl::cancel(bool autoCancel) {
if(!autoCancel || _autoCancel)
_monitor.cancel();
}
bool ThreadImpl::interrupt() {
return _monitor.interrupt();
}
bool ThreadImpl::isInterrupted() {
return _monitor.isInterrupted();
}
bool ThreadImpl::isCanceled() {
return _monitor.isCanceled();
}
Priority ThreadImpl::getPriority() const {
return _priority;
}
bool ThreadImpl::isReference() {
return _state.isReference();
}
/**
* Join the thread, blocking the caller until it is interrupted or until
* the thread represented by this object exits.
*
* Reference threads are not under the control of ZThreads and cannot be
* joined.
*/
bool ThreadImpl::join(unsigned long timeout) {
// Serial access to this ThreadImpl's state
Guard<Monitor> g1(_monitor);
// Make sure a thread is not trying to join() itself.
if(ThreadOps::isCurrent(this))
throw Deadlock_Exception("Cannot join self.");
// Reference threads can't be joined.
if(_state.isReference())
throw InvalidOp_Exception("Can not join this thread.");
/*
TODO: Insert cyclic join check.
*/
// If the task has not completed yet, wait for completion
if(!_state.isJoined()) {
// Add the current thread to the joiner list
ThreadImpl* impl = current();
_joiners.push_back(impl);
Monitor::STATE result;
{ // Release this ThreadImpl's lock while the joiner sleeps
_monitor.release();
Guard<Monitor> g3(impl->getMonitor());
result = impl->_monitor.wait(timeout);
_monitor.acquire();
}
// Update the joiner list
List::iterator i = std::find(_joiners.begin(), _joiners.end(), impl);
if(i != _joiners.end())
_joiners.erase(i);
switch(result) {
case Monitor::TIMEDOUT:
return false;
case Monitor::INTERRUPTED:
throw Interrupted_Exception();
default:
break;
}
}
return true;
}
/**
* Translate the priority into a pthread value, and update the thread priority.
*
* This is not available on all platforms, and probably works differently
* the platforms that do support it. Pthreads does not have very portable
* priority support as far I am aware.
*
* If SCHED_OTHER is not supported priority values are still set but
* dont not actually in affect anything.
*
* @param prio PRIORITY value
*
* @exception Killed_Exception thrown by KILLED threads.
* @exception InvalidOp_Exception thrown by IDLE, JOINING or JOINED threads.
*/
void ThreadImpl::setPriority(Priority p) {
Guard<Monitor> g(_monitor);
// Only set the native priority when the thread is running
if(_state.isRunning())
ThreadOps::setPriority(this, p);
_priority = p;
}
/**
* Test the state Monitor of this thread to determine if the thread
* is an active thread created by zthreads.
*
* @return bool indicating the activity of the thread.
*/
bool ThreadImpl::isActive() {
Guard<Monitor> g(_monitor);
return _state.isRunning();
}
/**
* Get a reference to an implmenetation that maps to the current thread.
* Accomplished by checking the TLS map. This will always return a valid
* ThreadImpl instance.
*
* @return ThreadImpl* current implementation that maps to the
* executing thread.
*/
ThreadImpl* ThreadImpl::current() {
// Get the ThreadImpl previously mapped onto the executing thread.
ThreadImpl* impl = _threadMap.get();
// Create a reference thread for any threads that have been 'discovered'
// because they are not created by ZThreads.
if(impl == 0) {
// Create a ThreadImpl to represent this thread.
impl = new ThreadImpl();
impl->_state.setReference();
ThreadOps::activate(impl);
// Map a reference thread and insert it into the queue
_threadMap.set(impl);
ThreadQueue::instance()->insertReferenceThread(impl);
}
assert(impl != 0);
return impl;
}
/**
* Make current thread sleep for the given number of milliseconds.
* This sleep can be interrupt()ed.
*
* @param ms timeout for the sleep.
*
* @post the calling thread is blocked by waiting on the internal condition
* variable. This can be signaled in the monitor of an interrupt
*/
void ThreadImpl::sleep(unsigned long ms) {
// Make sleep()ing for 0 milliseconds equivalent to a yield.
if(ms == 0) {
yield();
return;
}
// Get the monitor for the current thread
Monitor& monitor = current()->getMonitor();
// Acquire that threads Monitor with a Guard
Guard<Monitor> g(monitor);
for(;;) {
switch(monitor.wait(ms)) {
case Monitor::INTERRUPTED:
throw Interrupted_Exception();
default:
return;
}
}
}
/**
* Yield the current timeslice to another thread.
* If sched_yield() is available it is used.
* Otherwise, the state Monitor for this thread is used to simiulate a
* yield by blocking for 1 millisecond, which should give the
* scheduler a chance to schedule another thread.
*/
void ThreadImpl::yield() {
// Try to yield with the native operation. If it fails, then
// simulate with a short wait() on the monitor.
if(!ThreadOps::yield()) {
// Get the monitor for the current thread
Monitor& monitor = current()->getMonitor();
// Attempt a wait().
Guard<Monitor> g(monitor);
monitor.wait(1);
}
}
void ThreadImpl::start(const Task& task) {
Guard<Monitor> g1(_monitor);
// A Thread must be idle in order to be eligable to run a task.
if(!_state.isIdle())
throw InvalidOp_Exception("Thread is not idle.");
_state.setRunning();
// Spawn a new thread, blocking the parent (current) thread until
// the child starts.
ThreadImpl* parent = current();
Launcher launch(parent, this, task);
// Attempt to start the child thread
Guard<Monitor> g2(parent->_monitor);
if(!spawn(&launch)) {
// Return to the idle state & report the error if it doesn't work out.
_state.setIdle();
throw Synchronization_Exception();
}
// Wait, uninterruptably, for the child's signal. The parent thread
// still can be interrupted and killed; it just won't take effect
// until the child has started.
Guard<Monitor, DeferredInterruptionScope> g3(parent->_monitor);
if(parent->_monitor.wait() != Monitor::SIGNALED) {
assert(0);
}
}
void ThreadImpl::dispatch(ThreadImpl* parent, ThreadImpl* impl, Task task) {
// Map the implementation object onto the running thread.
_threadMap.set(impl);
// Update the reference count on a ThreadImpl before the 'Thread'
// that owns it can go out of scope (by signaling the parent)
impl->addReference();
// Update the priority of the thread
if(parent->_state.isReference())
ThreadOps::setPriority(impl,
parent->_state.isReference() ? impl->_priority : parent->_priority);
// Inherit ThreadLocal values from the parent
typedef ThreadLocalMap::const_iterator It;
for(It i = parent->getThreadLocalMap().begin(); i != parent->getThreadLocalMap().end(); ++i)
if( (i->second)->isInheritable() )
impl->getThreadLocalMap()[ i->first ] = (i->second)->clone();
// Insert a user-thread mapping
ThreadQueue::instance()->insertUserThread(impl);
// Wake the parent once the thread is setup
parent->_monitor.notify();
ZTDEBUG("Thread starting...\n");
// not catch exceptions, let program terminate
//try {
task->run();
//} catch(...) {
// Result of running a task that threw an exception.
// ZTDEBUG("The task has thrown an unhandled exception\n");
//assert(0); // UQ1: Go to debugger...
//}
ZTDEBUG("Thread joining...\n");
{ // Update the state of the thread
Guard<Monitor> g(impl->_monitor);
impl->_state.setJoined();
// Wake the joiners that will be easy to join first
for(List::iterator i = impl->_joiners.begin(); i != impl->_joiners.end();) {
ThreadImpl* joiner = *i;
Monitor& m = joiner->getMonitor();
if(m.tryAcquire()) {
m.notify();
m.release();
i = impl->_joiners.erase(i);
} else
++i;
}
// Wake the joiners that might take a while next
for(List::iterator i = impl->_joiners.begin(); i != impl->_joiners.end(); ++i) {
ThreadImpl* joiner = *i;
Monitor& m = joiner->getMonitor();
m.acquire();
m.notify();
m.release();
}
}
ZTDEBUG("Thread exiting...\n");
// Insert a pending-thread mapping, allowing the resources to be reclaimed
ThreadQueue::instance()->insertPendingThread(impl);
// Cleanup ThreadLocal values
impl->getThreadLocalMap().clear();
// Update the reference count allowing it to be destroyed
impl->delReference();
}
} // namespace ZThread

View file

@ -1,122 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTTHREADIMPL_H__
#define __ZTTHREADIMPL_H__
#include "zthread/ThreadLocalImpl.h"
#include "zthread/Thread.h"
#include "zthread/Exceptions.h"
#include "IntrusivePtr.h"
#include "Monitor.h"
#include "TSS.h"
#include "ThreadOps.h"
#include "State.h"
#include <map>
#include <deque>
namespace ZThread {
/**
* @class ThreadImpl
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-27T13:39:03-0400>
* @version 2.3.0
*/
class ThreadImpl : public IntrusivePtr<ThreadImpl, FastLock>, public ThreadOps {
typedef std::deque<ThreadImpl*> List;
//! TSS to store implementation to current thread mapping.
static TSS<ThreadImpl*> _threadMap;
//! The Monitor for controlling this thread
Monitor _monitor;
//! Current state for the thread
State _state;
//! Joining threads
List _joiners;
public:
typedef std::map<const ThreadLocalImpl*, ThreadLocalImpl::ValuePtr > ThreadLocalMap;
private:
ThreadLocalMap _tls;
//! Cached thread priority
Priority _priority;
//! Request cancel() when main() goes out of scope
bool _autoCancel;
void start(const Task& task);
public:
ThreadImpl();
ThreadImpl(const Task&, bool);
~ThreadImpl();
Monitor& getMonitor();
void cancel(bool autoCancel = false);
bool interrupt();
bool isInterrupted();
bool isCanceled();
Priority getPriority() const;
// ThreadLocalMap& getThreadLocalMap();
ThreadLocalMap& getThreadLocalMap() { return _tls; }
bool join(unsigned long);
void setPriority(Priority);
bool isActive();
bool isReference();
static void sleep(unsigned long);
static void yield();
static ThreadImpl* current();
static void dispatch(ThreadImpl*, ThreadImpl*, Task);
};
} // namespace ZThread
#endif // __ZTTHREADIMPL_H__

View file

@ -1,66 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/ThreadLocalImpl.h"
#include "ThreadImpl.h"
namespace ZThread {
ThreadLocalImpl::ThreadLocalImpl() {}
ThreadLocalImpl::~ThreadLocalImpl() {}
void ThreadLocalImpl::clearAll() {
typedef ThreadImpl::ThreadLocalMap Map;
Map& m = ThreadImpl::current()->getThreadLocalMap();
m.clear();
}
void ThreadLocalImpl::clear() const {
typedef ThreadImpl::ThreadLocalMap Map;
Map& m = ThreadImpl::current()->getThreadLocalMap();
Map::iterator i = m.find(this);
if(i != m.end())
m.erase(i);
}
ThreadLocalImpl::ValuePtr ThreadLocalImpl::value( ValuePtr(*pfn)() ) const {
typedef ThreadImpl::ThreadLocalMap Map;
Map& m = ThreadImpl::current()->getThreadLocalMap();
Map::iterator i = m.find(this);
if(i != m.end())
return i->second;
m[ this ] = ValuePtr( pfn() );
return m[ this ];
}
} // namespace ZThread

View file

@ -1,54 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTTHREADOPSIMPLSELECT_CXX__
#define __ZTTHREADOPSIMPLSELECT_CXX__
#include "ThreadOps.h"
// This file will select an implementation for a ThreadOps based on
// what ThreadOps.h selects. This method is for selecting the
// source files, to improve portability. Currently, the project is
// based on the autoconf tool-set, which doesn't support conditional
// compilation well. Additionally, this should make the library
// easier to port since its working around conditional compilation
// by using C++ features and people won't have to fiddle around with
// their make tool as much to compile the source
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
// Check for sched_yield()
#if !defined(HAVE_SCHED_YIELD)
# if defined(HAVE_UNISTD_H)
# include <unistd.h>
# if defined(_POSIX_PRIORITY_SCHEDULING)
# define HAVE_SCHED_YIELD 1
# endif
# endif
#endif
#include ZT_THREADOPS_IMPLEMENTATION
#endif

View file

@ -1,67 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTTHREADOPSSELECT_H__
#define __ZTTHREADOPSSELECT_H__
#include "zthread/Config.h"
#if defined(ZT_THREADOPS_IMPLEMENTATION)
# error "Reserved symbol defined"
#endif
// Select the correct implementation
#if defined(ZT_POSIX)
# include "posix/ThreadOps.h"
# define ZT_THREADOPS_IMPLEMENTATION "posix/ThreadOps.cxx"
#elif defined(ZT_WIN32) || defined(ZT_WIN9X)
// Visual C provides the _beginthreadex function, other compilers
// might not have this if they don't use Microsoft's C runtime.
// _beginthreadex is similar to in effect defining REENTRANT on a
// POSIX system. CreateThreadEx doesn't use reentrant parts of the
// Microsfot C runtime, but if your not using that runtime, no problem.
# if !defined(HAVE_BEGINTHREADEX)
# if defined(_MSC_VER)
# define HAVE_BEGINTHREADEX
# endif
# endif
# include "win32/ThreadOps.h"
# define ZT_THREADOPS_IMPLEMENTATION "win32/ThreadOps.cxx"
#elif defined(ZT_MACOS)
# include "macos/ThreadOps.h"
# define ZT_THREADOPS_IMPLEMENTATION "macos/ThreadOps.cxx"
#endif
#ifndef __ZTTHREADOPS_H__
#error "No ThreadOps implementation could be selected"
#endif
#endif // __ZTTHREADOPSSELECT_H__

View file

@ -1,266 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "DeferredInterruptionScope.h"
#include "Debug.h"
#include "ThreadImpl.h"
#include "ThreadQueue.h"
#include <algorithm>
#include <deque>
namespace ZThread {
ThreadQueue::ThreadQueue()
: _waiter(0) {
ZTDEBUG("ThreadQueue created\n");
}
ThreadQueue::~ThreadQueue() {
ZTDEBUG("ThreadQueue waiting on remaining threads...\n");
// Ensure the current thread is mapped.
ThreadImpl* impl = ThreadImpl::current();
bool threadsWaiting = false;
bool waitRequired = false;
{
TaskList shutdownTasks;
{ // Check the queue to for pending user threads
Guard<FastLock> g(_lock);
waitRequired = (_waiter != (ThreadImpl*)1);
_waiter = impl;
threadsWaiting = !_userThreads.empty() || !_pendingThreads.empty();
//ZTDEBUG("Wait required: %d\n", waitRequired);
//ZTDEBUG("Threads waiting: %d\n", threadsWaiting);
// Auto-cancel any active threads at the time main() goes out of scope
// "force" a gentle exit from the executing tasks; eventually the user-
// threads will transition into pending-threads
pollUserThreads();
// Remove all the tasks about to be run from the task list so an indication
// can be given to threads calling removeShutdownTask() too late.
std::remove_copy(_shutdownTasks.begin(),
_shutdownTasks.end(),
std::back_inserter(shutdownTasks),
Task((Runnable*)0));
//ZTDEBUG("Threads waiting: %d\n", threadsWaiting);
}
// Execute the shutdown tasks
for(TaskList::iterator i = shutdownTasks.begin(); i != shutdownTasks.end(); ++i) {
try {
(*i)->run();
} catch(...) { }
}
}
// Wait for all the users threads to get into the appropriate state
if(threadsWaiting) {
Monitor& m = _waiter->getMonitor();
// Defer interruption while this thread waits for a signal from
// the last pending user thread
Guard<Monitor, CompoundScope<DeferredInterruptionScope, LockedScope> > g(m);
//ZTDEBUG("Threads waiting: %d %d\n", _userThreads.size(), _pendingThreads.size());
// Avoid race-condition where the last threads are done with thier tasks, but
// only begin the final part of the clean up phase after this destructor begins
// to run. Takes advantage of the fact that if all remaining threads have transitioned
// into a pending state by the time execution reaches this point, then there is no
// need to wait.
waitRequired = waitRequired && !(_userThreads.empty() && !_pendingThreads.empty());
// Reference threads can't be interrupted or otherwise
// manipulated. The only signal this monitor will receive
// at this point will be from the last pending thread.
if(waitRequired && m.wait() != Monitor::SIGNALED) {
assert(0);
}
// Join those pending threads
pollPendingThreads();
}
// Clean up the reference threads
pollReferenceThreads();
ZTDEBUG("ThreadQueue destroyed\n");
}
void ThreadQueue::insertPendingThread(ThreadImpl* impl) {
ZTDEBUG("insertPendingThread()\n");
Guard<FastLock> g(_lock);
// Move from the user-thread list to the pending-thread list
ThreadList::iterator i = std::find(_userThreads.begin(), _userThreads.end(), impl);
if(i != _userThreads.end())
_userThreads.erase(i);
_pendingThreads.push_back(impl);
// Wake the main thread,if its waiting, when the last pending-thread becomes available;
// Otherwise, take note that no wait for pending threads to finish is needed
if(_userThreads.empty())
if(_waiter && _waiter != (ThreadImpl*)1)
_waiter->getMonitor().notify();
else
_waiter = (ThreadImpl*)!_waiter;
ZTDEBUG("1 pending-thread added.\n");
}
void ThreadQueue::insertReferenceThread(ThreadImpl* impl) {
Guard<FastLock> g(_lock);
_referenceThreads.push_back(impl);
ZTDEBUG("1 reference-thread added.\n");
}
void ThreadQueue::insertUserThread(ThreadImpl* impl) {
Guard<FastLock> g(_lock);
_userThreads.push_back(impl);
// Reclaim pending-threads
pollPendingThreads();
// Auto-cancel threads that are started when main() is out of scope
if(_waiter)
impl->cancel(true);
ZTDEBUG("1 user-thread added.\n");
}
void ThreadQueue::pollPendingThreads() {
ZTDEBUG("pollPendingThreads()\n");
for(ThreadList::iterator i = _pendingThreads.begin(); i != _pendingThreads.end();) {
ThreadImpl* impl = (ThreadImpl*)*i;
ThreadOps::join(impl);
impl->delReference();
i = _pendingThreads.erase(i);
ZTDEBUG("1 pending-thread reclaimed.\n");
}
}
void ThreadQueue::pollReferenceThreads() {
ZTDEBUG("pollReferenceThreads()\n");
for(ThreadList::iterator i = _referenceThreads.begin(); i != _referenceThreads.end(); ++i) {
ThreadImpl* impl = (ThreadImpl*)*i;
impl->delReference();
ZTDEBUG("1 reference-thread reclaimed.\n");
}
}
void ThreadQueue::pollUserThreads() {
ZTDEBUG("pollUserThreads()\n");
for(ThreadList::iterator i = _userThreads.begin(); i != _userThreads.end(); ++i) {
ThreadImpl* impl = *i;
impl->cancel(true);
ZTDEBUG("1 user-thread reclaimed.\n");
}
}
void ThreadQueue::insertShutdownTask(Task& task) {
bool hasWaiter = false;
{
Guard<FastLock> g(_lock);
// Execute later when the ThreadQueue is destroyed
if( !(hasWaiter = (_waiter != 0)) ) {
_shutdownTasks.push_back(task);
//ZTDEBUG("1 shutdown task added. %d\n", _shutdownTasks.size());
}
}
// Execute immediately if things are shutting down
if(hasWaiter)
task->run();
}
bool ThreadQueue::removeShutdownTask(const Task& task) {
Guard<FastLock> g(_lock);
TaskList::iterator i = std::find(_shutdownTasks.begin(), _shutdownTasks.end(), task);
bool removed = (i != _shutdownTasks.end());
if(removed)
_shutdownTasks.erase(i);
//ZTDEBUG("1 shutdown task removed (%d)-%d\n", removed, _shutdownTasks.size());
return removed;
}
};

View file

@ -1,134 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTTHREADQUEUE_H__
#define __ZTTHREADQUEUE_H__
#include "zthread/Singleton.h"
#include "zthread/Guard.h"
#include "FastLock.h"
namespace ZThread {
class ThreadImpl;
/**
* @class ThreadQueue
* @version 2.3.0
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-27T20:52:05-0400>
*
* A ThreadQueue accumulates references to user and reference threads.
* These are threads that are running outside the scope of the Thread
* object that created them. ZThreads doesn't have a central manager for
* all threads (partly why I renamed the ThreadManager to someting more
* appropriate). Instead, ZThreads will discover threads it did not create
* and create a reference thread that allows ZThreads to interact with it.
* Non user threads that are created by the user never have to touch the
* ThreadQueue.
*/
class ThreadQueue : public Singleton<ThreadQueue, StaticInstantiation> {
typedef std::deque<ThreadImpl*> ThreadList;
typedef std::deque<Task> TaskList;
//! Managed thread lists
ThreadList _pendingThreads;
ThreadList _referenceThreads;
ThreadList _userThreads;
//! Shutdown handlers
TaskList _shutdownTasks;
//! Serilize access to the thread list
FastLock _lock;
//! Reference thread waiting to cleanup any user & reference threads
ThreadImpl* _waiter;
public:
ThreadQueue();
/**
* The thread destroys a ThreadQueue will be a reference thread,
* probably the main thread; but it could be another thread that
* started and loaded the library.
*/
~ThreadQueue();
/**
* Insert a user-thread into the queue. User-threads are inserted as they
* begin thier task. Once that task completes, user-threads are automatically
* transitioned to pending-threads via <i>insertPendingThread()</i>.
*
* User-threads are known to be executing thier tasks and will be cancel()ed
* as the ThreadQueue is destroyed when main() goes out of scope. This sends
* a request to the task to complete soon. Once the task exits, the thread is
* transitioned to pending-thread status.
*/
void insertUserThread(ThreadImpl*);
/**
* Insert a pending-thread into the queue.
*
* Pending-threads are known to have completed thier tasks and thier
* resources are reclaimed (lazily) as more threads are started or as the
* ThreadQueue is destroyed.
*/
void insertPendingThread(ThreadImpl*);
/**
* Insert reference thread. Reference threads are not removed until
* the ThreadQueue goes out of scope.
*/
void insertReferenceThread(ThreadImpl*);
/**
* Insert a task to be run before threads are joined.
* Any items inserted after the ThreadQueue desctructor has begun to
* execute will be run() immediately.
*/
void insertShutdownTask(Task&);
/**
* Remove an existing shutdown task.
*/
bool removeShutdownTask(const Task&);
private:
void pollPendingThreads();
void pollUserThreads();
void pollReferenceThreads();
};
} // namespace ZThread
#endif // __ZTTHREADQUEUE_H__

View file

@ -1,464 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/ThreadedExecutor.h"
#include "zthread/Guard.h"
#include "zthread/FastMutex.h"
#include "zthread/Time.h"
#include "ThreadImpl.h"
namespace ZThread {
namespace {
//!
class WaiterQueue {
typedef std::deque<ThreadImpl*> ThreadList;
typedef struct group_t {
size_t id;
size_t count;
ThreadList waiters;
group_t(size_t n) : id(n), count(0) {}
} Group;
typedef std::deque<Group> GroupList;
//! Predicate to find a specific group
struct by_id : public std::unary_function<bool, Group> {
size_t id;
by_id(size_t n) : id(n) {}
bool operator()(const Group& grp) {
return grp.id == id;
}
};
//! Functor to count groups
struct counter : public std::unary_function<void, Group> {
size_t count;
counter() : count(0) {}
void operator()(const Group& grp) { count += grp.count; }
operator size_t() { return count; }
};
FastMutex _lock;
GroupList _list;
size_t _id;
size_t _generation;
public:
WaiterQueue() : _id(0), _generation(0) {
// At least one empty-group exists
_list.push_back( Group(_id++) );
}
/**
* Insert the current thread into the current waiter list
*
* @pre At least one empty group exists
* @post At least one empty group exists
*/
bool wait(unsigned long timeout) {
ThreadImpl* self = ThreadImpl::current();
Monitor& m = self->getMonitor();
Monitor::STATE state;
Guard<Lockable> g1(_lock);
// At least one empty-group exists
assert(!_list.empty());
// Return w/o waiting if there are no executing tasks
if((size_t)std::for_each(_list.begin(), _list.end(), counter()) < 1)
return true;
// Update the waiter list for the active group
_list.back().waiters.push_back(self);
size_t n = _list.back().id;
m.acquire();
{
Guard<Lockable, UnlockedScope> g2(g1);
state = timeout == 0 ? m.wait() : m.wait(timeout);
}
m.release();
// If awoke due to a reason other than the last task in the group 'n' completing,
// then then find the group 'self' is waiting in
GroupList::iterator i = std::find_if(_list.begin(), _list.end(), by_id(n));
if(i != _list.end()) {
// Remove 'self' from that list if it is still a member
ThreadList::iterator j = std::find(i->waiters.begin(), i->waiters.end(), self);
if(j != i->waiters.end())
i->waiters.erase(j);
}
// At least one empty-group exists
assert(!_list.empty());
switch(state) {
case Monitor::SIGNALED:
break;
case Monitor::TIMEDOUT:
return false;
case Monitor::INTERRUPTED:
throw Interrupted_Exception();
default:
throw Synchronization_Exception();
}
return true;
}
/**
* Increment the active group count
*
* @pre at least 1 empty group exists
* @post at least 1 non-empty group exists
*/
std::pair<size_t, size_t> increment() {
Guard<FastMutex> g(_lock);
// At least one empty-group exists
assert(!_list.empty());
GroupList::iterator i = --_list.end();
size_t n = i->id;
if(i == _list.end()) {
// A group should never have been removed until
// the final task in that group completed
assert(0);
}
i->count++;
// When the active group is being incremented, insert a new active group
// to replace it if there were waiting threads
if(i == --_list.end() && !i->waiters.empty())
_list.push_back(Group(_id++));
// At least 1 non-empty group exists
assert((size_t)std::for_each(_list.begin(), _list.end(), counter()) > 0);
return std::make_pair(n, _generation);
}
/**
* Decrease the count for the group with the given id.
*
* @param n group id
*
* @pre At least 1 non-empty group exists
* @post At least 1 empty group exists
*/
void decrement(size_t n) {
Guard<FastMutex> g1(_lock);
// At least 1 non-empty group exists
assert((size_t)std::for_each(_list.begin(), _list.end(), counter()) > 0);
// Find the requested group
GroupList::iterator i = std::find_if(_list.begin(), _list.end(), by_id(n));
if(i == _list.end()) {
// A group should never have been removed until
// the final task in that group completed
assert(0);
}
// Decrease the count for tasks in this group,
if(--i->count == 0 && i == _list.begin()) {
do {
// When the first group completes, wake all waiters for every
// group, starting from the first until a group that is not
// complete is reached
/*
// Don't remove the empty active group
if(i == --_list.end() && i->waiters.empty())
break;
*/
if( awaken(*i) ) {
// If all waiters were awakened, remove the group
i = _list.erase(i);
} else {
{
// Otherwise, unlock and yield allowing the waiter
// lists to be updated if other threads are busy
Guard<FastLock, UnlockedScope> g2(g1);
ThreadImpl::yield();
}
i = _list.begin();
}
} while(i != _list.end() && i->count == 0);
// Ensure that an active group exists
if(_list.empty())
_list.push_back( Group(++_id) );
}
// At least one group exists
assert(!_list.empty());
}
/**
*/
size_t generation(bool next = false) {
Guard<FastMutex> g(_lock);
return next ? _generation++ : _generation;
}
private:
/**
* Awaken all the waiters remaining in the given group
*
* @return
* - true if all the waiting threads were successfully awakened.
* - false if there were one or more threads that could not be awakened.
*/
bool awaken(Group& grp) {
// Go through the waiter list in the given group;
for(ThreadList::iterator i = grp.waiters.begin(); i != grp.waiters.end();) {
ThreadImpl* impl = *i;
Monitor& m = impl->getMonitor();
// Try the monitor lock, if it cant be locked skip to the next waiter
if(m.tryAcquire()) {
// Notify the monitor & remove from the waiter list so time isn't
// wasted checking it again.
i = grp.waiters.erase(i);
// Try to wake the waiter, it doesn't matter if this is successful
// or not (only fails when the monitor is already going to stop waiting).
m.notify();
m.release();
} else ++i;
}
return grp.waiters.empty();
}
};
//! Synchronization point for the Executor
class ExecutorImpl {
typedef std::deque<ThreadImpl*> ThreadList;
bool _canceled;
FastMutex _lock;
//! Worker threads
ThreadList _threads;
WaiterQueue _queue;
public:
ExecutorImpl() : _canceled(false) {}
WaiterQueue& getWaiterQueue() {
return _queue;
}
void registerThread(size_t generation) {
// Interrupt slow starting threads
if(getWaiterQueue().generation() != generation)
ThreadImpl::current()->interrupt();
// Enqueue for possible future interrupt()
else {
Guard<FastMutex> g(_lock);
_threads.push_back( ThreadImpl::current() );
}
}
void unregisterThread() {
Guard<FastMutex> g(_lock);
std::remove(_threads.begin(), _threads.end(), ThreadImpl::current() );
}
void cancel() {
Guard<FastMutex> g(_lock);
_canceled = true;
}
bool isCanceled() {
if(_canceled)
return true;
Guard<FastMutex> g(_lock);
return _canceled;
}
void interrupt() {
Guard<FastMutex> g(_lock);
// Interrupt all the registered threads
for(ThreadList::iterator i = _threads.begin(); i != _threads.end(); ++i)
(*i)->interrupt();
// Bump the generation up, ensuring slow starting threads get this interrupt
getWaiterQueue().generation( true );
}
}; /* ExecutorImpl */
//! Wrap a generation and a group around a task
class Worker : public Runnable {
CountedPtr< ExecutorImpl > _impl;
Task _task;
size_t _generation;
size_t _group;
public:
Worker(const CountedPtr< ExecutorImpl >& impl, const Task& task)
: _impl(impl), _task(task) {
std::pair<size_t, size_t> pr( _impl->getWaiterQueue().increment() );
_group = pr.first;
_generation = pr.second;
}
size_t group() const {
return _group;
}
size_t generation() const {
return _generation;
}
void run() {
// Register this thread once its begun; the generation is used to ensure
// threads that are slow starting are properly interrupted
_impl->registerThread( generation() );
try {
_task->run();
} catch(...) {
/* consume the exceptions the work propogates */
}
_impl->getWaiterQueue().decrement( group() );
// Unregister this thread
_impl->unregisterThread();
}
}; /* Worker */
}
ThreadedExecutor::ThreadedExecutor() : _impl(new ExecutorImpl) {}
ThreadedExecutor::~ThreadedExecutor() {}
void ThreadedExecutor::execute(const Task& task) {
Thread t( new Worker(_impl, task) );
}
void ThreadedExecutor::interrupt() {
_impl->interrupt();
}
void ThreadedExecutor::cancel() {
_impl->cancel();
}
bool ThreadedExecutor::isCanceled() {
return _impl->isCanceled();
}
void ThreadedExecutor::wait() {
_impl->getWaiterQueue().wait(0);
}
bool ThreadedExecutor::wait(unsigned long timeout) {
return _impl->getWaiterQueue().wait(timeout == 0 ? 1 : timeout);
}
}

View file

@ -1,45 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "zthread/Time.h"
#include "TimeStrategy.h"
using namespace ZThread;
Time::Time() {
// System startup time
static TimeStrategy firstHelper;
TimeStrategy helper;
Time then(firstHelper.seconds(), firstHelper.milliseconds());
Time now(helper.seconds(), helper.milliseconds());
now -= then;
_seconds = now.seconds();
_milliseconds = now.milliseconds();
}

View file

@ -1,86 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTTIMESELECT_H__
#define __ZTTIMESELECT_H__
#include "zthread/Config.h"
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
// Select the correct TimeOps implementation based on
// what the complilation environment has defined
#ifndef HAVE_FTIME
# if defined(ZT_WIN32) || defined(ZT_WIN9X)
# if !defined(__MWERKS__)
# ifndef HAVE_FTIME
# define HAVE_FTIME
# endif
# elif defined(__MWERKS__)
# ifndef HAVE_PERFORMANCECOUNTER
# define HAVE_PERFORMANCECOUNTER
# endif
# endif
# endif
#endif
// Some systems require this to complete the definition of timespec
// which is needed by pthreads.
#if defined(HAVE_SYS_TYPES_H)
# include <sys/types.h>
#endif
#if defined(ZT_MACOS)
# include "macos/UpTimeStrategy.h"
#elif defined(HAVE_PERFORMANCECOUNTER)
# include "win32/PerformanceCounterStrategy.h"
#elif defined(HAVE_FTIME)
# include "posix/FtimeStrategy.h"
#else
# include "posix/GetTimeOfDayStrategy.h"
#endif
#ifndef __ZTTIMESTRATEGY_H__
#error "No TimeStrategy implementation could be selected"
#endif
#endif // __ZTTIMESELECT_H__

View file

@ -1,95 +0,0 @@
/* src/config.h. Generated by configure. */
/* src/config.h.in. Generated from configure.ac by autoheader. */
/* Defined if <bits/atomicity.h> is usable */
/* #undef HAVE_ATOMIC_GCC */
/* Defined if <asm/atomic.h> is usable */
/* #undef HAVE_ATOMIC_LINUX */
/* _beginthreadex() */
/* #undef HAVE_BEGINTHREADEX */
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* defined when pthreads is available */
#define HAVE_POSIX_THREADS
/* Defined if pthread_keycreate() is available */
/* #undef HAVE_PTHREADKEYCREATE */
/* Defined if pthread_key_create() is available */
#define HAVE_PTHREADKEY_CREATE
/* Defined if pthread_yield() is available */
#define HAVE_PTHREAD_YIELD
/* Defined if -lrt is needed for RT scheduling */
#define HAVE_SCHED_RT
/* Defined if sched_yield() is available */
#define HAVE_SCHED_YIELD
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Name of package */
//#define PACKAGE "ZThread"
/* Define to the address where bug reports for this package should be sent. */
//#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
//#define PACKAGE_NAME ""
/* Define to the full name and version of this package. */
//#define PACKAGE_STRING ""
/* Define to the one symbol short name of this package. */
//#define PACKAGE_TARNAME ""
/* Define to the version of this package. */
//#define PACKAGE_VERSION ""
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Defined if ftime()/_ftime() is usable */
#define SYSTEM_FTIME ftime
/* Version number of package */
//#define VERSION "2.3.2"
/* No interrupt() hooks */
/* #undef ZTHREAD_DISABLE_INTERRUPT */
/* No OS priority support */
/* #undef ZTHREAD_DISABLE_PRIORITY */

View file

@ -1,73 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTATOMICCOUNTIMPL_H__
#define __ZTATOMICCOUNTIMPL_H__
#include <asm/atomic.h>
#include <assert.h>
namespace ZThread {
typedef struct atomic_count_t {
atomic_t count;
atomic_count_t() {
atomic_t init = ATOMIC_INIT(0);
count = init;
}
~atomic_count_t() {
assert(atomic_read(&count) == 0);
}
} ATOMIC_COUNT;
AtomicCount::AtomicCount() {
_value = reinterpret_cast<void*>(new ATOMIC_COUNT);
}
AtomicCount::~AtomicCount() {
delete reinterpret_cast<ATOMIC_COUNT*>(_value);
}
void AtomicCount::increment() {
atomic_inc(&reinterpret_cast<ATOMIC_COUNT*>(_value)->count);
}
bool AtomicCount::decrement() {
return atomic_dec_and_test(&reinterpret_cast<ATOMIC_COUNT*>(_value)->count);
}
};
#endif // __ZTATOMICCOUNTIMPL_H__

View file

@ -1,117 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTFASTLOCK_H__
#define __ZTFASTLOCK_H__
#include "zthread/NonCopyable.h"
#include "../ThreadOps.h"
#include <assert.h>
#include <asm/atomic.h>
#if !defined(NDEBUG)
# include <pthread.h>
#endif
namespace ZThread {
/**
* @class FastLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:27:03-0400>
* @version 2.2.0
*
* This implementation of a FastLock uses the atomic operations that
* linux provides with its kernel sources. This demonstrates how to implement
* a spinlock with a decrement and test primative.
*/
class FastLock : private NonCopyable {
atomic_t _value;
#if !defined(NDEBUG)
pthread_t _owner;
#endif
public:
inline FastLock() {
atomic_t tmp = ATOMIC_INIT(1);
_value = tmp;
}
inline ~FastLock() {
assert(atomic_read(&_value) == 1);
assert(_owner == 0);
}
inline void acquire() {
while(!atomic_dec_and_test(&_value)) {
atomic_inc(&_value);
ThreadOps::yield();
}
#if !defined(NDEBUG)
_owner = pthread_self();
#endif
}
inline void release() {
#if !defined(NDEBUG)
assert(pthread_equal(_owner, pthread_self()) != 0);
#endif
atomic_inc(&_value);
_owner = 0;
}
inline bool tryAcquire(unsigned long timeout=0) {
bool wasLocked = atomic_dec_and_test(&_value);
if(!wasLocked)
atomic_inc(&_value);
#if !defined(NDEBUG)
if(wasLocked)
_owner = pthread_self();
#endif
return wasLocked;
}
}; /* FastLock */
} // namespace ZThread
#endif

View file

@ -1,83 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTFASTRECURSIVELOCK_H__
#define __ZTFASTRECURSIVELOCK_H__
#include "zthread/NonCopyable.h"
#include <pthread.h>
namespace ZThread {
/**
* @class FastRecursiveLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:27:14-0400>
* @version 2.2.0
*
* This implementation of a FastRecursiveLock uses the recursive mutex
* that linux pthreads provides.
*/
class FastRecursiveLock : private NonCopyable {
pthread_mutex_t _mtx;
public:
inline FastRecursiveLock() {
static const pthread_mutexattr_t attr = { PTHREAD_MUTEX_RECURSIVE_NP };
pthread_mutex_init(&_mtx, &attr);
}
inline ~FastRecursiveLock() {
pthread_mutex_destroy(&_mtx);
}
inline void acquire() {
pthread_mutex_lock(&_mtx);
}
inline void release() {
pthread_mutex_unlock(&_mtx);
}
inline bool tryAcquire(unsigned long timeout=0) {
return (pthread_mutex_trylock(&_mtx) == 0);
}
}; /* FastRecursiveLock */
} // namespace ZThread
#endif

View file

@ -1,139 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTFASTLOCK_H__
#define __ZTFASTLOCK_H__
#include "zthread/NonCopyable.h"
#include "zthread/Exceptions.h"
#include <assert.h>
#include <CoreServices/CoreServices.h>
//#include <Multiprocessing.h>
namespace ZThread {
/**
* @class FastLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:25:31-0400>
* @version 2.1.6
*
*/
class FastLock : private NonCopyable {
MPCriticalRegionID _mtx;
public:
/**
* Create a new FastLock. No safety or state checks are performed.
*
* @exception Initialization_Exception - not thrown
*/
inline FastLock() {
// Apple TN1071
static bool init = MPLibraryIsLoaded();
if(!init || MPCreateCriticalRegion(&_mtx) != noErr) {
assert(0);
throw Initialization_Exception();
}
}
/**
* Destroy a FastLock. No safety or state checks are performed.
*/
inline ~FastLock() throw () {
OSStatus status = MPDeleteCriticalRegion(_mtx);
if(status != noErr)
assert(false);
}
/**
* Acquire an exclusive lock. No safety or state checks are performed.
*
* @exception Synchronization_Exception - not thrown
*/
inline void acquire() {
if(MPEnterCriticalRegion(_mtx, kDurationForever) != noErr)
throw Synchronization_Exception();
}
/**
* Try to acquire an exclusive lock. No safety or state checks are performed.
* This function returns immediately regardless of the value of the timeout
*
* @param timeout Unused
* @return bool
* @exception Synchronization_Exception - not thrown
*/
inline bool tryAcquire(unsigned long timeout=0) {
OSStatus status =
MPEnterCriticalRegion(_mtx, kDurationMillisecond * timeout);
switch(status) {
case kMPTimeoutErr:
return false;
case noErr:
return true;
}
assert(0);
throw Synchronization_Exception();
}
/**
* Release an exclusive lock. No safety or state checks are performed.
* The caller should have already acquired the lock, and release it
* only once.
*
* @exception Synchronization_Exception - not thrown
*/
inline void release() {
if(MPExitCriticalRegion(_mtx) != noErr)
throw Synchronization_Exception();
}
}; /* FastLock */
};
#endif

View file

@ -1,280 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "Monitor.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
using namespace ZThread;
Monitor::Monitor() : _owner(0), _waiting(false), _pending(false) {
if(MPCreateSemaphore(1, 0, &_sema) != noErr) {
assert(0);
throw Initialization_Exception();
}
}
Monitor::~Monitor() throw() {
assert(!_waiting);
OSStatus status = MPDeleteSemaphore(_sema);
if(status != noErr)
assert(false);
}
Monitor::STATE Monitor::wait(unsigned long timeout) {
// Calcuate the time, taking into account Intertask Signaling Time
// http://developer.apple.com/techpubs/macosx/Carbon/oss/MultiPServices/Multiprocessing_Services/index.html?http://developer.apple.com/techpubs/macosx/Carbon/oss/MultiPServices/Multiprocessing_Services/Functions/Creating_and_ssage_Queues.html
AbsoluteTime tTarget;
Duration waitDuration =
(timeout == 0) ? kDurationForever : (kDurationMillisecond * timeout);
if(waitDuration != kDurationForever)
tTarget = AddDurationToAbsolute(waitDuration, UpTime());
// Update the owner on first use. The owner will not change, each
// thread waits only on a single Monitor and a Monitor is never
// shared
if(_owner == 0)
_owner = MPCurrentTaskID();
STATE state(INVALID);
// Serialize access to the state of the Monitor
// and test the state to determine if a wait is needed.
_waitLock.acquire();
if(pending(ANYTHING)) {
// Return without waiting when possible
state = next();
_waitLock.release();
return state;
}
// Unlock the external lock if a wait() is probably needed.
// Access to the state is still serial.
_lock.release();
// Wait for a transition in the state that is of interest, this
// allows waits to exclude certain flags (e.g. INTERRUPTED)
// for a single wait() w/o actually discarding those flags -
// they will remain set until a wait interested in those flags
// occurs.
// Wait, ignoring signals
_waiting = true;
_waitLock.release();
// Update the wait time
if(waitDuration != kDurationForever)
waitDuration = AbsoluteDeltaToDuration(tTarget, UpTime());
// Sleep until a signal arrives or a timeout occurs
OSStatus status = MPWaitOnSemaphore(_sema, waitDuration);
// Reacquire serialized access to the state
_waitLock.acquire();
// Awaken only when the event is set or the timeout expired
assert(status == kMPTimeoutErr || status == noErr);
if(status == kMPTimeoutErr)
push(TIMEDOUT);
// Get the next available STATE
state = next();
_waiting = false;
// Its possible that a timeout will wake the thread before a signal is
// delivered. Absorb that leftover so the next wait isn't aborted right away
if(status == kMPTimeoutErr && _pending) {
status = MPWaitOnSemaphore(_sema, kDurationForever);
assert(status == noErr);
}
_pending = false;
// Acquire the internal lock & release the external lock
_waitLock.release();
// Reaquire the external lock, keep from deadlocking threads calling
// notify(), interrupt(), etc.
_lock.acquire();
return state;
}
bool Monitor::interrupt() {
// Serialize access to the state
_waitLock.acquire();
bool wasInterruptable = !pending(INTERRUPTED);
bool hasWaiter = false;
// Update the state & wake the waiter if there is one
if(wasInterruptable) {
push(INTERRUPTED);
wasInterruptable = false;
if(_waiting && !_pending) {
_pending = true;
hasWaiter = true;
} else
wasInterruptable = !(_owner == MPCurrentTaskID());
}
_waitLock.release();
if(hasWaiter && !masked(Monitor::INTERRUPTED))
MPSignalSemaphore(_sema);
return wasInterruptable;
}
bool Monitor::isInterrupted() {
// Serialize access to the state
_waitLock.acquire();
bool wasInterrupted = pending(INTERRUPTED);
clear(INTERRUPTED);
_waitLock.release();
return wasInterrupted;
}
bool Monitor::notify() {
// Serialize access to the state
_waitLock.acquire();
bool wasNotifyable = !pending(INTERRUPTED);
bool hasWaiter = false;
// Set the flag if theres a waiter
if(wasNotifyable) {
push(SIGNALED);
if(_waiting && !_pending) {
_pending = true;
hasWaiter = true;
}
}
_waitLock.release();
if(hasWaiter)
MPSignalSemaphore(_sema);
return wasNotifyable;
}
bool Monitor::cancel() {
// Serialize access to the state
_waitLock.acquire();
bool wasInterrupted = !pending(INTERRUPTED);
bool hasWaiter = false;
push(CANCELED);
// Update the state if theres a waiter
if(wasInterrupted) {
push(INTERRUPTED);
if(_waiting && !_pending) {
_pending = true;
hasWaiter = true;
}
}
_waitLock.release();
if(hasWaiter && !masked(Monitor::INTERRUPTED))
MPSignalSemaphore(_sema);
return wasInterrupted;
}
bool Monitor::isCanceled() {
// Serialize access to the state
_waitLock.acquire();
bool wasCanceled = Status::examine(CANCELED);
if(_owner == MPCurrentTaskID())
clear(INTERRUPTED);
_waitLock.release();
return wasCanceled;
}

View file

@ -1,156 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTMONITOR_H__
#define __ZTMONITOR_H__
#include "../Status.h"
#include "../FastLock.h"
namespace ZThread {
/**
* @class Monitor
* @author Eric Crahen <http://www.code-foo.com/>
* @date <2003-07-29T11:24:58-0400>
* @version 2.2.1
*/
class Monitor : public Status, private NonCopyable {
//! Serialize access to external objects
FastLock _lock;
//! Serialize access to internal state
FastLock _waitLock;
//! Semaphore to control the owning thread
MPSemaphoreID _sema;
//! Owning thread
MPTaskID _owner;
//! Waiting flag, to avoid uneccessary signals
volatile bool _waiting;
//! Waiting flag, to avoid too many signals
volatile bool _pending;
//! State of the monitor
volatile int _state;
public:
//! Create a new monitor.
Monitor();
//! Destroy the monitor.
~Monitor() throw();
//! Acquire the external lock for this monitor.
inline void acquire() {
_lock.acquire();
}
//! Try to acquire the external lock for this monitor.
inline bool tryAcquire() {
return _lock.tryAcquire();
}
//! Release the external lock for this monitor.
inline void release() {
_lock.release();
}
/**
* Wait for a state change and atomically unlock the external lock.
* Blocks for an indefinent amount of time.
*
* @return INTERRUPTED if the wait was ended by a interrupt()
* or SIGNALED if the wait was ended by a notify()
*
* @post the external lock is always acquired before this function returns
*/
inline STATE wait() {
return wait(0);
}
/**
* Wait for a state change and atomically unlock the external lock.
* May blocks for an indefinent amount of time.
*
* @param timeout - maximum time to block (milliseconds) or 0 to
* block indefinently
*
* @return INTERRUPTED if the wait was ended by a interrupt()
* or TIMEDOUT if the maximum wait time expired.
* or SIGNALED if the wait was ended by a notify()
*
* @post the external lock is always acquired before this function returns
*/
STATE wait(unsigned long timeout);
/**
* Interrupt this monitor. If there is a thread blocked on this monitor object
* it will be signaled and released. If there is no waiter, a flag is set and
* the next attempt to wait() will return INTERRUPTED w/o blocking.
*
* @return false if the thread was previously INTERRUPTED.
*/
bool interrupt();
/**
* Notify this monitor. If there is a thread blocked on this monitor object
* it will be signaled and released. If there is no waiter, a flag is set and
* the next attempt to wait() will return SIGNALED w/o blocking, if no other
* flag is set.
*
* @return false if the thread was previously INTERRUPTED.
*/
bool notify();
/**
* Check the state of this monitor, clearing the INTERRUPTED status if set.
*
* @return bool true if the monitor was INTERRUPTED.
* @post INTERRUPTED flag cleared if the calling thread owns the monitor.
*/
bool isInterrupted();
/**
* Mark the Status CANCELED, and INTERRUPT the montor.
*
* @see interrupt()
*/
bool cancel();
/**
* Test the CANCELED Status, clearing the INTERRUPTED status if set.
*
* @return bool
*/
bool isCanceled();
};
};
#endif

View file

@ -1,120 +0,0 @@
/*
* Copyright (c) 2005, Eric Crahen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __ZTTSS_H__
#define __ZTTSS_H__
#include "zthread/NonCopyable.h"
#include "zthread/Exceptions.h"
#include <assert.h>
#include <CoreServices/CoreServices.h>
//#include <Multiprocessing.h>
namespace ZThread {
/**
* @class TSS
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-27T14:19:10-0400>
* @version 2.1.6
*
* An abstraction for dealing with POSIX thread specific storage (tss).
* Provides get/set and creation/destruction.
*/
template <typename T>
class TSS : private NonCopyable {
TaskStorageIndex _key;
public:
/**
* Create a new object for accessing tss.
*/
TSS() {
// Apple TN1071
static bool init = MPLibraryIsLoaded();
if(!init || MPAllocateTaskStorageIndex(&_key) != noErr) {
assert(0);
throw Initialization_Exception();
}
}
/**
* Destroy the underlying supoprt for accessing tss with this
* object.
*/
~TSS() {
OSStatus status = MPDeallocateTaskStorageIndex(_key);
if(status != noErr)
assert(0);
}
/**
* Get the value stored in tss.
*
* @return T
*
* @exception InvalidOp_exception thrown when the tss is not properly initialized
*/
T get() const {
return reinterpret_cast<T>(MPGetTaskStorageValue(_key));
}
/**
* Store a value in tss.
*
* @param value T
* @return T old value
*
* @exception InvalidOp_exception thrown when the tss is not properly initialized
*/
T set(T value) const {
T oldValue = get();
OSStatus status =
MPSetTaskStorageValue(_key, reinterpret_cast<TaskStorageValue>(value));
if(status != noErr) {
assert(0);
throw Synchronization_Exception();
}
return oldValue;
}
};
}
#endif

Some files were not shown because too many files have changed in this diff Show more