This commit is contained in:
TheLuda 2008-10-14 00:29:20 +02:00
parent d767495d5b
commit 800ee76535
3322 changed files with 903437 additions and 0 deletions

View file

@ -0,0 +1,57 @@
/*
* 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

@ -0,0 +1,54 @@
/*
* 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

@ -0,0 +1,80 @@
/*
* 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

@ -0,0 +1,377 @@
/*
* 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

@ -0,0 +1,92 @@
/*
* 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

32
dep/src/zthread/Debug.h Normal file
View file

@ -0,0 +1,32 @@
/*
* 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

@ -0,0 +1,63 @@
/*
* 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

@ -0,0 +1,71 @@
/*
* 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

@ -0,0 +1,53 @@
/*
* 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

@ -0,0 +1,74 @@
/*
* 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

@ -0,0 +1,53 @@
/*
* 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

@ -0,0 +1,99 @@
/*
* 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

132
dep/src/zthread/Makefile.am Normal file
View file

@ -0,0 +1,132 @@
## 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

@ -0,0 +1,39 @@
/*
* 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

60
dep/src/zthread/Monitor.h Normal file
View file

@ -0,0 +1,60 @@
/*
* 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__

68
dep/src/zthread/Mutex.cxx Normal file
View file

@ -0,0 +1,68 @@
/*
* 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

377
dep/src/zthread/MutexImpl.h Normal file
View file

@ -0,0 +1,377 @@
/*
* 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

@ -0,0 +1,629 @@
/*
* 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

@ -0,0 +1,80 @@
/*
* 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

@ -0,0 +1,109 @@
/*
* 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

@ -0,0 +1,69 @@
/*
* 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

@ -0,0 +1,104 @@
/*
* 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

@ -0,0 +1,61 @@
/*
* 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

@ -0,0 +1,286 @@
/*
* 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

@ -0,0 +1,78 @@
/*
* 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

@ -0,0 +1,96 @@
/*
* 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

@ -0,0 +1,101 @@
/*
* 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

@ -0,0 +1,348 @@
/*
* 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__

151
dep/src/zthread/State.h Normal file
View file

@ -0,0 +1,151 @@
/*
* 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

179
dep/src/zthread/Status.h Normal file
View file

@ -0,0 +1,179 @@
/*
* 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

@ -0,0 +1,90 @@
/*
* 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;
}
}

52
dep/src/zthread/TSS.h Normal file
View file

@ -0,0 +1,52 @@
/*
* 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__

127
dep/src/zthread/Thread.cxx Normal file
View file

@ -0,0 +1,127 @@
/*
* 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

@ -0,0 +1,470 @@
/*
* 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

@ -0,0 +1,122 @@
/*
* 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

@ -0,0 +1,66 @@
/*
* 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

@ -0,0 +1,54 @@
/*
* 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

@ -0,0 +1,67 @@
/*
* 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

@ -0,0 +1,266 @@
/*
* 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

@ -0,0 +1,134 @@
/*
* 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

@ -0,0 +1,464 @@
/*
* 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);
}
}

45
dep/src/zthread/Time.cxx Normal file
View file

@ -0,0 +1,45 @@
/*
* 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

@ -0,0 +1,86 @@
/*
* 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

@ -0,0 +1,73 @@
/*
* 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

@ -0,0 +1,117 @@
/*
* 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

@ -0,0 +1,83 @@
/*
* 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

@ -0,0 +1,139 @@
/*
* 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

@ -0,0 +1,280 @@
/*
* 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

@ -0,0 +1,156 @@
/*
* 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

120
dep/src/zthread/macos/TSS.h Normal file
View file

@ -0,0 +1,120 @@
/*
* 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

View file

@ -0,0 +1,103 @@
/*
* 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 "ThreadOps.h"
#include "zthread/Exceptions.h"
#include "zthread/Runnable.h"
namespace ZThread {
const ThreadOps ThreadOps::INVALID(0);
ThreadOps::ThreadOps() : _queue(0), _tid(0) {
if(MPCreateQueue(&_queue) != noErr)
throw Initialization_Exception();
}
ThreadOps::~ThreadOps() throw() {
if(_queue != 0) {
OSStatus status = MPDeleteQueue(_queue);
if(status != noErr)
assert(0);
}
}
bool ThreadOps::join(ThreadOps* ops) {
assert(ops);
assert(ops->_tid != 0);
OSStatus status = MPWaitOnQueue(ops->_queue, NULL, NULL, NULL, kDurationForever);
return status == noErr;
}
bool ThreadOps::yield() {
MPYield();
return true;
}
bool ThreadOps::setPriority(ThreadOps* impl, Priority p) {
return true;
}
bool ThreadOps::getPriority(ThreadOps* impl, Priority& p) {
return true;
}
bool ThreadOps::spawn(Runnable* task) {
OSStatus status =
MPCreateTask(&_dispatch, task, 0UL, _queue, NULL, NULL, 0UL, &_tid);
return status == noErr;
}
OSStatus ThreadOps::_dispatch(void *arg) {
Runnable* task = reinterpret_cast<Runnable*>(arg);
assert(task);
// Run the task from the correct context
task->run();
// Exit the thread
MPExit(noErr);
return noErr;
}
} // namespace ZThread

View file

@ -0,0 +1,167 @@
/*
* 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 __ZTTHREADOPS_H__
#define __ZTTHREADOPS_H__
#include "zthread/Priority.h"
#include <assert.h>
#include <CoreServices/CoreServices.h>
//#include <Multiprocessing.h>
//#include <MultiprocessingInfo.h>
namespace ZThread {
class Runnable;
/**
* @class ThreadOps
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:26:01-0400>
* @version 2.2.0
*
* This class is an abstraction used to perform various operations on a
* native POSIX thread.
*/
class ThreadOps {
//! Keep track of the pthreads handle for the native thread
MPQueueID _queue;
MPTaskID _tid;
ThreadOps(MPTaskID tid) : _queue(0), _tid(tid) { }
static OSStatus _dispatch(void*);
public:
const static ThreadOps INVALID;
/**
* Create a new ThreadOps to manipulate a native thread.
*/
ThreadOps();
ThreadOps(const ThreadOps& ops) : _queue(0), _tid(ops._tid) {}
~ThreadOps() throw();
inline bool operator==(const ThreadOps& ops) const {
return ops._tid == _tid;
}
const ThreadOps& operator=(const ThreadOps& ops) {
assert(_queue == 0);
_tid = ops._tid;
return *this;
}
static ThreadOps self() {
return ThreadOps(MPCurrentTaskID());
}
/**
* Activating an instance of ThreadOps will map it onto the currently
* executing thread.
*/
static void activate(ThreadOps* ops) {
assert(ops);
assert(ops->_tid == 0);
ops->_tid = MPCurrentTaskID();
}
/**
* Test if this object represents the currently executing
* native thread.
*
* @return bool true if successful
*/
static bool isCurrent(ThreadOps* ops) {
assert(ops);
return MPCurrentTaskID() == ops->_tid;
}
/**
* Join a native thread.
*
* @return bool true if successful
*/
static bool join(ThreadOps*);
/**
* Force the current native thread to yield, letting the scheduler
* give the CPU time to another thread.
*
* @return bool true if successful, false if the operation can't
* be supported.
*/
static bool yield();
/**
* Set the priority for the native thread if supported by the
* system.
*
* @param PRIORITY requested priority
* @return bool false if unsuccessful
*/
static bool setPriority(ThreadOps*, Priority);
/**
* Set the priority for the native thread if supported by the
* system.
*
* @param Thread::PRIORITY& current priority
* @return bool false if unsuccessful
*/
static bool getPriority(ThreadOps*, Priority&);
protected:
/**
* Spawn a native thread.
*
* @param ThreadImpl* parent thread
* @param ThreadImpl* child thread being started.
* @param Runnable* task being executed.
*
* @return bool true if successful
*/
bool spawn(Runnable*);
};
}
#endif // __ZTTHREADOPS_H__

View file

@ -0,0 +1,86 @@
/*
* 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 __ZTTIMESTRATEGY_H__
#define __ZTTIMESTRATEGY_H__
#include <CoreServices/CoreServices.h>
//#include <DriverServices.h>
namespace ZThread {
/**
* @class TimeStrategy
*
* Implement a strategy for time operatons based on UpTime
*/
class TimeStrategy {
unsigned long _ms;
unsigned long _s;
public:
TimeStrategy() {
// Get the absolute time in milliseconds relative to the program startup
static AbsoluteTime sysUpTime(UpTime());
AbsoluteTime delta = AbsoluteDeltaToNanoseconds(UpTime(), sysUpTime);
uint64_t now = *reinterpret_cast<uint64_t*>(&delta) / 1000000;
_s = now / 1000;
_ms = now % 1000;
}
inline unsigned long seconds() const {
return _s;
}
inline unsigned long milliseconds() const {
return _ms;
}
unsigned long seconds(unsigned long s) {
unsigned long z = seconds();
_s = s;
return z;
}
unsigned long milliseconds(unsigned long ms) {
unsigned long z = milliseconds();
_ms = ms;
return z;
}
};
};
#endif // __ZTTIMESTRATEGY_H__

View file

@ -0,0 +1,146 @@
/*
* 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>
#include <errno.h>
#include <assert.h>
namespace ZThread {
/**
* @class FastRecursiveLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:28:37-0400>
* @version 2.2.0
*
* This is an implementation of a FastRecursiveLock for any vannila
* POSIX system. It is based on a condition variable and a mutex;
* because of this it is important to not that its waiting properties
* are not the same as other mutex implementations that generally
* based on spin locks. Under high contention, this implementation may
* be preferable to a spin lock, although refactoring the design of
* code that puts a mutex under alot of preasure may be worth investigating.
*/
class FastRecursiveLock : private NonCopyable {
//! Serialize state
pthread_mutex_t _mtx;
//! Wait for lock
pthread_cond_t _cond;
//! Owner
pthread_t _owner;
//! Count
volatile unsigned int _count;
public:
inline FastRecursiveLock() : _owner(0), _count(0) {
pthread_mutex_init(&_mtx, 0);
if(pthread_cond_init(&_cond, 0) != 0) {
assert(0);
}
}
inline ~FastRecursiveLock() {
pthread_mutex_destroy(&_mtx);
if(pthread_cond_destroy(&_cond) != 0) {
assert(0);
}
}
inline void acquire() {
pthread_t self = pthread_self();
pthread_mutex_lock(&_mtx);
// If the caller does not own the lock, wait until there is no owner
if(_owner != 0 && !pthread_equal(_owner, self)) {
int status = 0;
do { // ignore signals
status = pthread_cond_wait(&_cond, &_mtx);
} while(status == EINTR && _owner == 0);
}
_owner = self;
_count++;
pthread_mutex_unlock(&_mtx);
}
inline bool tryAcquire(unsigned long timeout=0) {
pthread_t self = pthread_self();
pthread_mutex_lock(&_mtx);
// If the caller owns the lock, or there is no owner update the count
bool success = (_owner == 0 || pthread_equal(_owner, self));
if(success) {
_owner = self;
_count++;
}
pthread_mutex_unlock(&_mtx);
return success;
}
inline void release() {
assert(pthread_equal(_owner, pthread_self()));
pthread_mutex_lock(&_mtx);
if(--_count == 0) {
_owner = 0;
pthread_cond_signal(&_cond);
}
pthread_mutex_unlock(&_mtx);
}
}; /* FastRecursiveLock */
} // namespace ZThread
#endif

View file

@ -0,0 +1,121 @@
/*
* 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/Exceptions.h"
#include "zthread/NonCopyable.h"
#include <pthread.h>
#include <assert.h>
namespace ZThread {
/**
* @class FastLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:28:07-0400>
* @version 2.2.8
*
* This is the smallest and fastest synchronization object in the library.
* It is an implementation of fast mutex, an all or nothing exclusive
* lock. It should be used only where you need speed and are willing
* to sacrifice all the state & safety checking provided by the framework
* for speed.
*/
class FastLock : private NonCopyable {
pthread_mutex_t _mtx;
public:
/**
* Create a new FastLock. No safety or state checks are performed.
*
* @exception Initialization_Exception - not thrown
*/
inline FastLock() {
if(pthread_mutex_init(&_mtx, 0) != 0)
throw Initialization_Exception();
}
/**
* Destroy a FastLock. No safety or state checks are performed.
*/
inline ~FastLock() {
if(pthread_mutex_destroy(&_mtx) != 0) {
assert(0);
}
}
/**
* Acquire an exclusive lock. No safety or state checks are performed.
*
* @exception Synchronization_Exception - not thrown
*/
inline void acquire() {
if(pthread_mutex_lock(&_mtx) != 0)
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) {
return (pthread_mutex_trylock(&_mtx) == 0);
}
/**
* 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(pthread_mutex_unlock(&_mtx) != 0)
throw Synchronization_Exception();
}
}; /* FastLock */
};
#endif

View file

@ -0,0 +1,84 @@
/*
* 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 __ZTTIMESTRATEGY_H__
#define __ZTTIMESTRATEGY_H__
#include <sys/timeb.h>
#if defined(_MSC_VER)
# include <time.h>
# define timeb _timeb
# define ftime _ftime
#endif
namespace ZThread {
/**
* @class TimeStrategy
*
* Implement a strategy for time operatons based on ftime
*/
class TimeStrategy {
struct timeb _value;
public:
TimeStrategy() {
ftime(&_value);
}
inline unsigned long seconds() const {
return (unsigned long)_value.time;
}
inline unsigned long milliseconds() const {
return _value.millitm;
}
unsigned long seconds(unsigned long s) {
unsigned long z = seconds();
_value.time = s;
return z;
}
unsigned long milliseconds(unsigned long ms) {
unsigned long z = milliseconds();
_value.millitm = (unsigned short)ms;
return z;
}
};
};
#endif // __ZTTIMESTRATEGY_H__

View file

@ -0,0 +1,75 @@
/*
* 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 __ZTTIMESTRATEGY_H__
#define __ZTTIMESTRATEGY_H__
#include <sys/time.h>
namespace ZThread {
/**
* @class TimeStrategy
*
* Implement a strategy for time operatons based on gettimeofday
*/
class TimeStrategy {
struct timeval _value;
public:
TimeStrategy() {
gettimeofday(&_value, 0);
}
inline unsigned long seconds() const {
return _value.tv_sec;
}
inline unsigned long milliseconds() const {
return _value.tv_usec/1000;
}
unsigned long seconds(unsigned long s) {
unsigned long z = seconds();
_value.tv_sec = s;
return z;
}
unsigned long milliseconds(unsigned long ms) {
unsigned long z = milliseconds();
_value.tv_usec = ms*1000;
return z;
}
};
};
#endif // __ZTTIMESTRATEGY_H__

View file

@ -0,0 +1,257 @@
/*
* 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"
#include "../Debug.h"
#include "../TimeStrategy.h"
#include <errno.h>
#include <assert.h>
#include <signal.h>
namespace ZThread {
Monitor::Monitor() : _owner(0), _waiting(false) {
pthread_cond_init(&_waitCond, 0);
pthread_mutex_init(&_waitLock, 0);
}
Monitor::~Monitor() {
assert(!_waiting);
pthread_cond_destroy(&_waitCond);
pthread_mutex_destroy(&_waitLock);
}
Monitor::STATE Monitor::wait(unsigned long ms) {
// 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 = pthread_self();
STATE state(INVALID);
// Serialize access to the state of the Monitor
// and test the state to determine if a wait is needed.
pthread_mutex_lock(&_waitLock);
if(pending(ANYTHING)) {
// Return without waiting when possible
state = next();
pthread_mutex_unlock(&_waitLock);
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.
// if(!currentState(interest)) {
// Wait, ignoring signals
_waiting = true;
int status = 0;
if(ms == 0) { // Wait forever
do { // ignore signals unless the state is interesting
status = pthread_cond_wait(&_waitCond, &_waitLock);
} while(status == EINTR && !pending(ANYTHING));
// Akwaken only when a state is pending
assert(status == 0);
} else {
// Find the target time
TimeStrategy t;
ms += t.milliseconds();
unsigned long s = t.seconds() + (ms / 1000);
ms %= 1000;
// Convert to a timespec
struct ::timespec timeout;
timeout.tv_sec = s;
timeout.tv_nsec = ms*1000000;
// Wait ignoring signals until the state is interesting
do {
// When a timeout occurs, update the state to reflect that.
status = pthread_cond_timedwait(&_waitCond, &_waitLock, &timeout);
} while(status == EINTR && !pending(ANYTHING));
// Akwaken only when a state is pending or when the timeout expired
assert(status == 0 || status == ETIMEDOUT);
if(status == ETIMEDOUT)
push(TIMEDOUT);
}
// Get the next available STATE
state = next();
_waiting = false;
pthread_mutex_unlock(&_waitLock);
// Reaquire the external lock, keep from deadlocking threads calling
// notify(), interrupt(), etc.
_lock.acquire();
return state;
}
bool Monitor::interrupt() {
// Serialize access to the state
pthread_mutex_lock(&_waitLock);
bool wasInterruptable = !pending(INTERRUPTED);
bool hadWaiter = _waiting;
if(wasInterruptable) {
// Update the state & wake the waiter if there is one
push(INTERRUPTED);
wasInterruptable = false;
if(hadWaiter && !masked(Monitor::INTERRUPTED))
pthread_cond_signal(&_waitCond);
else
wasInterruptable = !pthread_equal(_owner, pthread_self());
}
pthread_mutex_unlock(&_waitLock);
// Only returns true when an interrupted thread is not currently blocked
return wasInterruptable;
}
bool Monitor::isInterrupted() {
// Serialize access to the state
pthread_mutex_lock(&_waitLock);
bool wasInterrupted = pending(INTERRUPTED);
clear(INTERRUPTED);
pthread_mutex_unlock(&_waitLock);
return wasInterrupted;
}
bool Monitor::isCanceled() {
// Serialize access to the state
pthread_mutex_lock(&_waitLock);
bool wasCanceled = examine(CANCELED);
if(pthread_equal(_owner, pthread_self()))
clear(INTERRUPTED);
pthread_mutex_unlock(&_waitLock);
return wasCanceled;
}
bool Monitor::cancel() {
// Serialize access to the state
pthread_mutex_lock(&_waitLock);
bool wasInterrupted = !pending(INTERRUPTED);
bool hadWaiter = _waiting;
push(CANCELED);
if(wasInterrupted) {
// Update the state & wake the waiter if there is one
push(INTERRUPTED);
if(hadWaiter && !masked(Monitor::INTERRUPTED))
pthread_cond_signal(&_waitCond);
}
pthread_mutex_unlock(&_waitLock);
return wasInterrupted;
}
bool Monitor::notify() {
// Serialize access to the state
pthread_mutex_lock(&_waitLock);
bool wasNotifyable = !pending(INTERRUPTED);
if(wasNotifyable) {
// Set the flag and wake the waiter if there
// is one
push(SIGNALED);
if(_waiting)
pthread_cond_signal(&_waitCond);
}
pthread_mutex_unlock(&_waitLock);
return wasNotifyable;
}
} // namespace ZThread

View file

@ -0,0 +1,153 @@
/*
* 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-18T08:16:09-0400>
* @version 2.2.8
*/
class Monitor : public Status, private NonCopyable {
private:
//! Serialize access to external objects
FastLock _lock;
//! Condition variable used to block a thread.
pthread_cond_t _waitCond;
//! Serialize access to the internal state of the monitor
pthread_mutex_t _waitLock;
//! Owning thread
pthread_t _owner;
//! Waiting flag, to avoid uneccessary signals
volatile bool _waiting;
public:
typedef Status::STATE STATE;
//! Create a new monitor.
Monitor();
//! Destroy the monitor.
~Monitor();
//! Acquire the lock for this monitor.
inline void acquire() {
_lock.acquire();
}
//! Acquire the lock for this monitor.
inline bool tryAcquire() {
return _lock.tryAcquire();
}
//! Release the 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

@ -0,0 +1,51 @@
/*
* 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 __ZTPRIORITYOPS_H__
#define __ZTPRIORITYOPS_H__
#include "zthread/Priority.h"
#include "../ThreadOps.h"
namespace ZThread {
/**
* @class PriorityOps
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:30:00-0400>
* @version 2.2.0
*
* This class is an abstraction used to perform various operations on a
* native POSIX thread.
*/
class PriorityOps {
public:
};
} // namespace ZThread
#endif // __ZTPRIORITYOPS_H__

104
dep/src/zthread/posix/TSS.h Normal file
View file

@ -0,0 +1,104 @@
/*
* 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 <pthread.h>
#include <assert.h>
namespace ZThread {
/**
* @class TSS
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-27T14:18:37-0400>
* @version 2.3.0
*
* An abstraction for dealing with POSIX thread specific storage (tss).
* Provides get/set and creation/destruction.
*/
template <typename T>
class TSS : private NonCopyable {
pthread_key_t _key;
public:
/**
* Create a new object for accessing tss.
*/
TSS() {
if(pthread_key_create(&_key, 0) != 0) {
assert(0); // Key creation failed
}
}
/**
* Destroy the underlying supoprt for accessing tss with this
* object.
*/
~TSS() {
pthread_key_delete(_key);
}
/**
* 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>(pthread_getspecific(_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();
pthread_setspecific(_key, value);
return oldValue;
}
};
}
#endif

View file

@ -0,0 +1,147 @@
/*
* 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 "ThreadOps.h"
#include "zthread/Guard.h"
#include "zthread/Runnable.h"
#include <errno.h>
#if defined(HAVE_SCHED_YIELD)
# include <sched.h>
#endif
namespace ZThread {
const ThreadOps ThreadOps::INVALID(0);
bool ThreadOps::join(ThreadOps* ops) {
assert(ops);
assert(ops->_tid != 0);
int err = 0;
do {
err = pthread_join(ops->_tid, NULL);
} while(err == EINTR);
return err == 0;
}
bool ThreadOps::yield() {
bool result = false;
#if defined(HAVE_SCHED_YIELD)
result = sched_yield() == 0;
#endif
return result;
}
bool ThreadOps::setPriority(ThreadOps* impl, Priority p) {
assert(impl);
bool result = true;
#if !defined(ZTHREAD_DISABLE_PRIORITY)
struct sched_param param;
switch(p) {
case Low:
param.sched_priority = 0;
break;
case High:
param.sched_priority = 10;
break;
case Medium:
default:
param.sched_priority = 5;
}
result = pthread_setschedparam(impl->_tid, SCHED_OTHER, &param) == 0;
#endif
return result;
}
bool ThreadOps::getPriority(ThreadOps* impl, Priority& p) {
assert(impl);
bool result = true;
#if !defined(ZTHREAD_DISABLE_PRIORITY)
struct sched_param param;
int policy = SCHED_OTHER;
if(result = (pthread_getschedparam(impl->_tid, &policy, &param) == 0)) {
// Convert to one of the PRIORITY values
if(param.sched_priority < 10)
p = Low;
else if(param.sched_priority == 10)
p = Medium;
else
p = High;
}
#endif
return result;
}
bool ThreadOps::spawn(Runnable* task) {
return pthread_create(&_tid, 0, _dispatch, task) == 0;
}
extern "C" void *_dispatch(void *arg) {
Runnable* task = reinterpret_cast<Runnable*>(arg);
assert(task);
// Run the task from the correct context
task->run();
// Exit the thread
pthread_exit((void**)0);
return (void*)0;
}
} // namespace ZThread

View file

@ -0,0 +1,154 @@
/*
* 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 __ZTTHREADOPS_H__
#define __ZTTHREADOPS_H__
#include "zthread/Priority.h"
#include <pthread.h>
#include <assert.h>
namespace ZThread {
class Runnable;
//! Dispatch function for native pthreads required extern C
//! linkage.
extern "C" void* _dispatch(void*);
/**
* @class ThreadOps
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:30:25-0400>
* @version 2.2.8
*
* This class is an abstraction used to perform various operations on a
* native POSIX thread.
*/
class ThreadOps {
//! Keep track of the pthreads handle for the native thread
pthread_t _tid;
ThreadOps(pthread_t tid) : _tid(tid) { }
public:
const static ThreadOps INVALID;
/**
* Create a new ThreadOps to manipulate a native thread.
*/
ThreadOps() : _tid(0) { }
inline bool operator==(const ThreadOps& ops) const {
return pthread_equal(_tid, ops._tid);
}
static ThreadOps self() {
return ThreadOps(pthread_self());
}
/**
* Activating an instance of ThreadOps will map it onto the currently
* executing thread.
*/
static void activate(ThreadOps* ops) {
assert(ops);
assert(ops->_tid == 0);
ops->_tid = pthread_self();
}
/**
* Test if this object represents the currently executing
* native thread.
*
* @return bool true if successful
*/
static bool isCurrent(ThreadOps* ops) {
assert(ops);
return pthread_equal(pthread_self(), ops->_tid);
}
/**
* Join a native thread.
*
* @return bool true if successful
*/
static bool join(ThreadOps*);
/**
* Force the current native thread to yield, letting the scheduler
* give the CPU time to another thread.
*
* @return bool true if successful, false if the operation can't
* be supported.
*/
static bool yield();
/**
* Set the priority for the native thread if supported by the
* system.
*
* @param PRIORITY requested priority
* @return bool false if unsuccessful
*/
static bool setPriority(ThreadOps*, Priority);
/**
* Set the priority for the native thread if supported by the
* system.
*
* @param Thread::PRIORITY& current priority
* @return bool false if unsuccessful
*/
static bool getPriority(ThreadOps*, Priority&);
protected:
/**
* Spawn a native thread.
*
* @param ThreadImpl* parent thread
* @param ThreadImpl* child thread being started.
* @param Runnable* task being executed.
*
* @return bool true if successful
*/
bool spawn(Runnable*);
};
}
#endif // __ZTTHREADOPS_H__

View file

@ -0,0 +1,122 @@
/*
* 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:31:23-0400>
* @version 2.2.0
*
* This FastRecursiveLock implementation uses pthreads mutex attribute
* functions to create a recursive lock. This implementation is not
* specific to solaris and will work on any system that supports
* pthread_mutexattr_settype().
*/
class FastRecursiveLock : private NonCopyable {
pthread_mutex_t _mtx;
/**
* @class Attribute
*
* Utility class to maintain the attribute as long as it is needed.
*/
class Attribute {
pthread_mutexattr_t _attr;
public:
Attribute() {
if(pthread_mutexattr_init(&_attr) != 0) {
assert(0);
}
if(pthread_mutexattr_settype(&_attr, PTHREAD_MUTEX_RECURSIVE) != 0) {
assert(0);
}
}
~Attribute() {
if(pthread_mutexattr_destroy(&_attr) != 0) {
assert(0);
}
}
operator pthread_mutexattr_t*() {
return &_attr;
}
};
public:
inline FastRecursiveLock() {
static Attribute attr;
pthread_mutex_init(&_mtx, (pthread_mutexattr_t*)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

@ -0,0 +1,173 @@
/*
* 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 "../FastLock.h"
#include "../ThreadOps.h"
#include <assert.h>
namespace ZThread {
/**
* @class FastRecursiveLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:31:09-0400>
* @version 2.2.8
*
* This is a vanilla FastRecursiveLock implementation for a
* system that doesn't provide recurisve locks. This implementation
* is based on using a pair of mutexes, because of this, it performs
* roughly the same as a spin lock would.
*/
class FastRecursiveLock : private NonCopyable {
//! Lock for blocking
FastLock _blockingLock;
//! Serialize state
FastLock _stateLock;
//! Owner
ThreadOps _owner;
//! Count
volatile unsigned int _count;
public:
inline FastRecursiveLock() : _owner(ThreadOps::INVALID), _count(0) { }
inline ~FastRecursiveLock() {
assert(_owner == ThreadOps::INVALID);
assert(_count == 0);
}
void acquire() {
ThreadOps self(ThreadOps::self());
// Try to lock the blocking mutex first
bool wasLocked = _blockingLock.tryAcquire();
if(!wasLocked) {
// Otherwise, grab the lock for the state
_stateLock.acquire();
wasLocked = (_owner == self);
if(wasLocked)
_count++;
_stateLock.release();
if(wasLocked)
return;
// Try to be cooperative
ThreadOps::yield();
_blockingLock.acquire();
}
// Serialze access to the state
_stateLock.acquire();
// Take ownership
assert(_owner == ThreadOps::INVALID || _owner == self);
_owner = self;
_count++;
_stateLock.release();
}
bool tryAcquire(unsigned long timeout = 0) {
ThreadOps self(ThreadOps::self());
// Try to lock the blocking mutex first
bool wasLocked = _blockingLock.tryAcquire();
if(!wasLocked) {
// Otherwise, grab the lock for the state
_stateLock.acquire();
wasLocked = (_owner == self);
if(wasLocked)
_count++;
_stateLock.release();
return wasLocked;
}
// Serialze access to the state
_stateLock.acquire();
// Take ownership
assert(_owner == ThreadOps::INVALID || _owner == self);
_owner = self;
_count++;
_stateLock.release();
return true;
}
void release() {
// Assume that release is only used by the owning thread, as it
// should be.
assert(_count != 0);
assert(_owner == ThreadOps::self());
_stateLock.acquire();
// If the lock was owned and the count has reached 0, give up
// ownership and release the blocking lock
if(--_count == 0) {
_owner = ThreadOps::INVALID;
_blockingLock.release();
}
_stateLock.release();
}
}; /* FastRecursiveLock */
} // namespace ZThread
#endif

View file

@ -0,0 +1,100 @@
/*
* 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 "zthread/Guard.h"
#include "../FastLock.h"
#include <assert.h>
namespace ZThread {
typedef struct atomic_count_t {
FastLock lock;
unsigned long count;
atomic_count_t() : count(0) {}
} ATOMIC_COUNT;
AtomicCount::AtomicCount() {
ATOMIC_COUNT* c = new ATOMIC_COUNT;
_value = reinterpret_cast<void*>(c);
}
AtomicCount::~AtomicCount() {
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
assert(c->count == 0);
delete c;
}
//! Postfix decrement and return the current value
size_t AtomicCount::operator--(int) {
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
Guard<FastLock> g(c->lock);
return c->count--;
}
//! Postfix increment and return the current value
size_t AtomicCount::operator++(int) {
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
Guard<FastLock> g(c->lock);
return c->count++;
}
//! Prefix decrement and return the current value
size_t AtomicCount::operator--() {
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
Guard<FastLock> g(c->lock);
return --c->count;
}
//! Prefix increment and return the current value
size_t AtomicCount::operator++() {
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
Guard<FastLock> g(c->lock);
return ++c->count;
}
};
#endif // __ZTATOMICCOUNTIMPL_H__

View file

@ -0,0 +1,130 @@
/*
* 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 "../FastLock.h"
#include "../ThreadOps.h"
#include <assert.h>
namespace ZThread {
/**
* @class FastRecursiveLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:30:59-0400>
* @version 2.2.8
*
* This implementation of a FastRecursiveLock uses the which ever FastLock
* that is selected to create a recursive spin lock.
*/
class FastRecursiveLock : private NonCopyable {
FastLock _lock;
ThreadOps _owner;
volatile unsigned int _count;
public:
inline FastRecursiveLock() : _owner(ThreadOps::INVALID), _count(0) {}
inline ~FastRecursiveLock() {
assert(_owner == ThreadOps::INVALID);
assert(_count == 0);
}
inline void acquire() {
ThreadOps self(ThreadOps::self());
bool wasLocked = false;
do {
_lock.acquire();
// If there is no owner, or the owner is the caller
// update the count
if(_owner == ThreadOps::INVALID || _owner == self) {
_owner = self;
_count++;
wasLocked = true;
}
_lock.release();
} while(!wasLocked);
assert(_owner == ThreadOps::self());
}
inline void release() {
assert(_owner == ThreadOps::self());
_lock.acquire();
if(--_count == 0)
_owner = ThreadOps::INVALID;
_lock.release();
}
inline bool tryAcquire(unsigned long timeout=0) {
ThreadOps self(ThreadOps::self());
bool wasLocked = false;
_lock.acquire();
if(_owner == ThreadOps::INVALID || _owner == self) {
_owner = self;
_count++;
wasLocked = true;
}
_lock.release();
assert(!wasLocked || _owner == ThreadOps::self());
return wasLocked;
}
}; /* FastRecursiveLock */
} // namespace ZThread
#endif

View file

@ -0,0 +1,60 @@
/*
* 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 <windows.h>
#include <assert.h>
namespace ZThread {
AtomicCount::AtomicCount() {
_value = reinterpret_cast<void*>(new LONG(0));
}
AtomicCount::~AtomicCount() {
assert(*reinterpret_cast<LPLONG>(_value) == 0);
delete reinterpret_cast<LPLONG>(_value);
}
void AtomicCount::increment() {
::InterlockedIncrement(reinterpret_cast<LPLONG>(_value));
}
bool AtomicCount::decrement() {
LONG v = ::InterlockedDecrement(reinterpret_cast<LPLONG>(_value));
return static_cast<unsigned long>(v) == 0;
}
};
#endif // __ZTATOMICCOUNTIMPL_H__

View file

@ -0,0 +1,122 @@
/*
* 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 <windows.h>
#include <assert.h>
namespace ZThread {
/**
* @class FastLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:32:20-0400>
* @version 2.1.6
*
* This is the smallest and fastest synchronization object in the library.
* It is an implementation of fast mutex, an all or nothing exclusive
* lock. It should be used only where you need speed and are willing
* to sacrifice all the state & safety checking provided by the framework
* for speed.
*
* The current Platform SDK defines:
*
* LONG InterlockedExchange(LPLONG, LONG)
* LONG InterlockedCompareExchange(LPLONG, LONG, LONG, LONG)
*
* If your compiler complains about LPLONG not being implicitly casted to
* a PVOID, then you should get the SDK update from microsoft or use the
* WIN9X implementation of this class.
*
* ----
* Because Windows 95 and earlier can run on processors prior to the 486, they
* don't all support the CMPXCHG function, and so Windows 95 an earlier dont support
* InterlockedCompareExchange. For this, you should use the win9x implementation
* of this class
*/
class FastLock : private NonCopyable {
#pragma pack(push, 8)
LONG volatile _lock;
#pragma pack(pop)
public:
/**
* Create a new FastLock
*/
inline FastLock() : _lock(0) { }
/**
* Destroy FastLock
*/
inline ~FastLock() { assert(_lock == 0); }
/**
* Lock the fast Lock, no error check.
*
* @exception None
*/
inline void acquire() {
while (::InterlockedCompareExchange(const_cast<LPLONG>(&_lock), 1, 0) != 0)
::Sleep(0);
}
/**
* Release the fast Lock, no error check.
*
* @exception None
*/
inline void release() {
::InterlockedExchange(const_cast<LPLONG>(&_lock), (LONG)0);
}
/**
* 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) {
return ::InterlockedCompareExchange(const_cast<LPLONG>(&_lock), 1, 0) == 0;
}
}; /* FastLock */
};
#endif

View file

@ -0,0 +1,158 @@
/*
* 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 <windows.h>
#include <assert.h>
namespace ZThread {
/**
* @class FastRecursiveLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:32:34-0400>
* @version 2.1.6
*
* This is the smaller and faster implementation of a RecursiveLock.
* A single thread can acquire the mutex any number of times, but it
* must perform a release for each acquire(). Other threads are blocked
* until a thread has released all of its locks on the mutex.
*
* This particular implementation performs fewer safety checks. Like
* the FastLock implementation, any waiting caused by an acquire() request
* is not interruptable. This is so that the mutex can have the fastest
* response time for a time critical application while still having a good
* degree of reliability.
*
* TryEnterCriticalSection() does not work at all on some systems, so its
* not used.
*
*
* The current Platform SDK defines:
*
* LONG InterlockedExchange(LPLONG, LONG)
* LONG InterlockedCompareExchange(LPLONG, LONG, LONG, LONG)
*
* If your compiler complains about LPLONG not being implicitly casted to
* a PVOID, then you should get the SDK update from microsoft or use the
* WIN9X implementation of this class.
*
* ----
* Because Windows 95 and earlier can run on processors prior to the 486, they
* don't all support the CMPXCHG function, and so Windows 95 an earlier dont support
* InterlockedCompareExchange. If you define ZT_WIN9X, you'll get a version of the
* FastLock that uses the XCHG instruction
*/
class FastRecursiveLock : private NonCopyable {
// Add def for mingw32 or other non-ms compiler to align on 64-bit
// boundary
#pragma pack(push, 8)
LONG volatile _lock;
#pragma pack(pop)
LONG _count;
public:
/**
* Create a new FastRecursiveLock
*/
inline FastRecursiveLock() : _lock(0), _count(0) { }
/**
* Destroy FastLock
*/
inline ~FastRecursiveLock() {
assert(_lock == 0);
}
/**
* Lock the fast Lock, no error check.
*
* @exception None
*/
inline void acquire() {
DWORD id = ::GetCurrentThreadId();
// Take ownership if the lock is free or owned by the calling thread
do {
DWORD owner = (DWORD)::InterlockedCompareExchange(const_cast<LPLONG>(&_lock), id, 0);
if(owner == 0 || owner == id)
break;
::Sleep(0);
} while(1);
_count++;
}
/**
* Release the fast Lock, no error check.
*
* @exception None
*/
inline void release() {
if(--_count == 0)
::InterlockedExchange(const_cast<LPLONG>(&_lock), 0);
}
/**
* 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) {
DWORD id = ::GetCurrentThreadId();
DWORD owner = (DWORD)::InterlockedCompareExchange(const_cast<LPLONG>(&_lock), id, 0);
if(owner == 0 || owner == id) {
_count++;
return true;
}
return false;
}
}; /* FastRecursiveLock */
};
#endif

View file

@ -0,0 +1,146 @@
/*
* 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/Exceptions.h"
#include "zthread/NonCopyable.h"
#include "../ThreadOps.h"
#include <windows.h>
#include <assert.h>
namespace ZThread {
/**
* @class FastLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:32:44-0400>
* @version 2.2.11
*
* This FastLock implementation is based on a Win32 Mutex
* object. This will perform better under high contention,
* but will not be as fast as the spin lock under reasonable
* circumstances.
*/
class FastLock : private NonCopyable {
HANDLE _hMutex;
#ifndef NDEBUG
volatile bool _locked;
#endif
public:
/**
* Create a new FastLock
*/
FastLock() {
#ifndef NDEBUG
_locked = false;
#endif
_hMutex = ::CreateMutex(0, 0, 0);
assert(_hMutex != NULL);
if(_hMutex == NULL)
throw Initialization_Exception();
}
~FastLock() {
::CloseHandle(_hMutex);
}
void acquire() {
if(::WaitForSingleObject(_hMutex, INFINITE) != WAIT_OBJECT_0) {
assert(0);
throw Synchronization_Exception();
}
#ifndef NDEBUG
// Simulate deadlock to provide consistent behavior. This
// will help avoid errors when porting. Avoiding situations
// where a FastMutex mistakenly behaves as a recursive lock.
while(_locked)
ThreadOps::yield();
_locked = true;
#endif
}
void release() {
#ifndef NDEBUG
_locked = false;
#endif
if(::ReleaseMutex(_hMutex) == 0) {
assert(0);
throw Synchronization_Exception();
}
}
bool tryAcquire(unsigned long timeout = 0) {
switch(::WaitForSingleObject(_hMutex, timeout)) {
case WAIT_OBJECT_0:
#ifndef NDEBUG
// Simulate deadlock to provide consistent behavior. This
// will help avoid errors when porting. Avoiding situations
// where a FastMutex mistakenly behaves as a recursive lock.
while(_locked)
ThreadOps::yield();
_locked = true;
#endif
return true;
case WAIT_TIMEOUT:
return false;
default:
break;
}
assert(0);
throw Synchronization_Exception();
}
};
} // namespace ZThread
#endif

View file

@ -0,0 +1,109 @@
/*
* 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/Exceptions.h"
#include "zthread/NonCopyable.h"
#include <windows.h>
#include <assert.h>
namespace ZThread {
/**
* @class FastRecursiveLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:32:56-0400>
* @version 2.2.11
*
* This FastRecursiveLock implementation is based on a Win32 Mutex
* object. This will perform better under high contention,
* but will not be as fast as the spin lock under reasonable
* circumstances.
*/
class FastRecursiveLock : private NonCopyable {
HANDLE _hMutex;
volatile unsigned int _count;
public:
/**
* Create a new FastRecursiveLock
*/
FastRecursiveLock() : _count(0) {
_hMutex = ::CreateMutex(0, 0, 0);
assert(_hMutex != NULL);
if(_hMutex == NULL)
throw Initialization_Exception();
}
~FastRecursiveLock() {
::CloseHandle(_hMutex);
}
void acquire() {
if(::WaitForSingleObject(_hMutex, INFINITE) != WAIT_OBJECT_0) {
assert(0);
throw Synchronization_Exception();
}
}
void release() {
if(::ReleaseMutex(_hMutex) == 0) {
assert(0);
throw Synchronization_Exception();
}
}
bool tryAcquire(unsigned long) {
switch(::WaitForSingleObject(_hMutex, 0)) {
case WAIT_OBJECT_0:
return true;
case WAIT_TIMEOUT:
return false;
default:
break;
}
assert(0);
throw Synchronization_Exception();
}
}; /* FastRecursiveLock */
} // namespace ZThread
#endif

View file

@ -0,0 +1,242 @@
/*
* 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) {
_handle = ::CreateEvent(0, TRUE, FALSE, 0);
if(_handle == NULL) {
assert(0);
}
}
Monitor::~Monitor() {
assert(!_waiting);
::CloseHandle(_handle);
}
Monitor::STATE Monitor::wait(unsigned long ms) {
// 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 = ::GetCurrentThreadId();
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.
// if(!currentState(interest)) {
// Wait, ignoring signals
_waiting = true;
// Block until the event is set.
_waitLock.release();
// The event is manual reset so this lack of atmoicity will not
// be an issue
DWORD dwResult =
::WaitForSingleObject(_handle, ((ms == 0) ? INFINITE : (DWORD)ms));
// Reacquire serialized access to the state
_waitLock.acquire();
// Awaken only when the event is set or the timeout expired
assert(dwResult == WAIT_OBJECT_0 || dwResult == WAIT_TIMEOUT);
if(dwResult == WAIT_TIMEOUT)
push(TIMEDOUT);
// Get the next available STATE
state = next();
_waiting = false;
::ResetEvent(_handle);
// 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 hadWaiter = _waiting;
if(wasInterruptable) {
// Update the state & wake the waiter if there is one
push(INTERRUPTED);
wasInterruptable = false;
if(hadWaiter && !masked(Monitor::INTERRUPTED)) {
// Blocked on a synchronization object
if(::SetEvent(_handle) == FALSE) {
assert(0);
}
} else
wasInterruptable = !(_owner == ::GetCurrentThreadId());
}
_waitLock.release();
// Only returns true when an interrupted thread is not currently blocked
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);
if(wasNotifyable) {
// Set the flag and wake the waiter if there
// is one
push(SIGNALED);
// If there is a waiter then send the signal.
if(_waiting)
if(::SetEvent(_handle) == FALSE) {
assert(0);
}
}
_waitLock.release();
return wasNotifyable;
}
bool Monitor::cancel() {
// Serialize access to the state
_waitLock.acquire();
bool wasInterrupted = !pending(INTERRUPTED);
bool hadWaiter = _waiting;
push(CANCELED);
if(wasInterrupted) {
// Update the state & wake the waiter if there is one
push(INTERRUPTED);
// If there is a waiter then send the signal.
if(hadWaiter && !masked(Monitor::INTERRUPTED))
if(::SetEvent(_handle) == FALSE) {
assert(0);
}
}
_waitLock.release();
return wasInterrupted;
}
bool Monitor::isCanceled() {
// Serialize access to the state
_waitLock.acquire();
bool wasCanceled = examine(CANCELED);
if(_owner == ::GetCurrentThreadId())
clear(INTERRUPTED);
_waitLock.release();
return wasCanceled;
}

View file

@ -0,0 +1,153 @@
/*
* 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-16T23:33:10-0400>
* @version 2.2.11
*/
class Monitor : public Status, private NonCopyable {
//! Serialize access to external objects
FastLock _lock;
//! Event used to block thread
HANDLE _handle;
//! Serialize access to the internal state of the monitor
FastLock _waitLock;
//! Owning thread
DWORD _owner;
//! Waiting flag, to avoid uneccessary signals
volatile bool _waiting;
//! State of the monitor
volatile int _state;
public:
//! Create a new monitor.
Monitor();
//! Destroy the monitor.
~Monitor();
//! 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

@ -0,0 +1,108 @@
/*
* 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 __ZTTIMESTRATEGY_H__
#define __ZTTIMESTRATEGY_H__
#include <assert.h>
#include <windows.h>
namespace ZThread {
/**
* @class PerformanceCounterStrategy
*
* Implement a strategy for time operatons based on
* Windows QueryPerformanceXXX() functions.
* This only (erroneously) considers the lower 32 bits.
*/
class TimeStrategy {
unsigned long _secs;
unsigned long _millis;
public:
TimeStrategy() {
// Keep track of the relative time the program started
static LARGE_INTEGER i;
static BOOL valid(::QueryPerformanceCounter(&i));
assert(valid == TRUE);
LARGE_INTEGER j;
::QueryPerformanceCounter(&j);
j.LowPart -= i.LowPart;
j.LowPart /= frequency();
// Mask off the high bits
_millis = (unsigned long)j.LowPart / 1000;
_secs = (unsigned long)j.LowPart - _millis;
}
unsigned long seconds() const {
return _secs;
}
unsigned long milliseconds() const {
return _millis;
}
unsigned long seconds(unsigned long s) {
unsigned long z = seconds();
_secs = s;
return z;
}
unsigned long milliseconds(unsigned long ms) {
unsigned long z = milliseconds();
_millis = ms;
return z;
}
private:
// Get the frequency
static DWORD frequency() {
static LARGE_INTEGER i;
static BOOL valid(::QueryPerformanceFrequency(&i));
assert(valid == TRUE);
return i.LowPart;
}
};
};
#endif // __ZTTIMESTRATEGY_H__

108
dep/src/zthread/win32/TSS.h Normal file
View file

@ -0,0 +1,108 @@
/*
* 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 <windows.h>
namespace ZThread {
/**
* @class TSS
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-27T14:18:43-0400>
* @version 2.3.0
*
* An abstraction for dealing with WIN32 thread specific storage (tss).
* Provides get/set and creation/destruction.
*/
template <typename T>
class TSS {
DWORD _key;
bool _valid;
public:
/**
* Create a new object for accessing tss. The def
*/
TSS() {
_key = ::TlsAlloc();
_valid = (_key != 0xFFFFFFFF);
}
/**
* Destroy the underlying supoprt for accessing tss with this
* object.
*/
virtual ~TSS() {
if(_valid)
::TlsFree(_key);
}
/**
* Get the value stored in tss.
*
* @return T
*
* @exception InvalidOp_exception thrown when the tss is not properly initialized
*/
inline T get() const {
if(!_valid)
throw InvalidOp_Exception();
return static_cast<T>(::TlsGetValue(_key));
}
/**
* Store a value in tss.
*
* @param value T
* @return T old value
*
* @exception InvalidOp_exception thrown when the tss is not properly initialized
*/
inline T set(T value) const {
T oldValue = get();
::TlsSetValue(_key, value);
return oldValue;
}
};
}
#endif

View file

@ -0,0 +1,197 @@
/*
* 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 "ThreadOps.h"
#include "zthread/Runnable.h"
#include <process.h>
namespace ZThread {
const ThreadOps ThreadOps::INVALID(0);
/**
* Detect OS at runtime and attempt to locate the SwitchToThread
* function, which will assist in making the spin lock implementation
* which use ThreadOps::yield() a bit fairer.
*/
class YieldOps {
typedef BOOL (*Yield)(void);
Yield _fnYield;
public:
YieldOps() : _fnYield(NULL) {
OSVERSIONINFO v;
v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if(::GetVersionEx(&v) && (v.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
// Uses GetModuleHandle() so the reference count on the dll is
// not affected. There is a warning about race conditions involving
// this function being called as FreeLibrary() completes; however
// nearly all win32 applications load this particular and will keep it
// in memory until the process exits.
HINSTANCE hInst = ::GetModuleHandle("Kernel32.dll");
if(hInst != NULL)
_fnYield = (Yield)::GetProcAddress(hInst, "SwitchToThread");
// REMIND: possibly need to use _T() macro for these strings
}
}
bool operator()() {
// Attempt to yield using the best function available
if(!_fnYield || !_fnYield())
::Sleep(0);
return true;
}
};
bool ThreadOps::join(ThreadOps* ops) {
assert(ops);
assert(ops->_tid != 0);
assert(ops->_hThread != NULL);
if(::WaitForSingleObjectEx(ops->_hThread, INFINITE, FALSE) != WAIT_OBJECT_0)
return false;
::CloseHandle(ops->_hThread);
ops->_hThread = NULL;
return true;
}
bool ThreadOps::yield() {
static YieldOps yielder;
yielder();
return true;
}
bool ThreadOps::setPriority(ThreadOps* impl, Priority p) {
assert(impl);
#if !defined(ZTHREAD_DISABLE_PRIORITY)
bool result;
// Convert
int n;
switch(p) {
case Low:
n = THREAD_PRIORITY_BELOW_NORMAL;
break;
case High:
n = THREAD_PRIORITY_ABOVE_NORMAL;
break;
case Medium:
default:
n = THREAD_PRIORITY_NORMAL;
}
result = (::SetThreadPriority(impl->_hThread, n) != THREAD_PRIORITY_ERROR_RETURN);
return result;
#else
return true;
#endif
}
bool ThreadOps::getPriority(ThreadOps* impl, Priority& p) {
assert(impl);
bool result = true;
#if !defined(ZTHREAD_DISABLE_PRIORITY)
// Convert to one of the PRIORITY values
switch(::GetThreadPriority(impl->_hThread)) {
case THREAD_PRIORITY_ERROR_RETURN:
result = false;
case THREAD_PRIORITY_BELOW_NORMAL:
p = Low;
break;
case THREAD_PRIORITY_ABOVE_NORMAL:
p = High;
break;
case THREAD_PRIORITY_NORMAL:
default:
p = Medium;
}
#endif
return result;
}
bool ThreadOps::spawn(Runnable* task) {
// Start the thread.
#if defined(HAVE_BEGINTHREADEX)
_hThread = (HANDLE)::_beginthreadex(0, 0, &_dispatch, task, 0, (unsigned int*)&_tid);
#else
_hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&_dispatch, task, 0, (DWORD*)&_tid);
#endif
return _hThread != NULL;
}
unsigned int __stdcall ThreadOps::_dispatch(void *arg) {
Runnable* task = reinterpret_cast<Runnable*>(arg);
assert(task);
// Run the task from the correct context
task->run();
// Exit the thread
#if defined(HAVE_BEGINTHREADEX)
::_endthreadex(0);
#else
ExitThread(0);
#endif
return 0;
}
}

View file

@ -0,0 +1,152 @@
/*
* 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 __ZTTHREADOPS_H__
#define __ZTTHREADOPS_H__
#include "zthread/Priority.h"
#include <windows.h>
#include <assert.h>
namespace ZThread {
class Runnable;
/**
* @class ThreadOps
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:33:59-0400>
* @version 2.2.8
*
* This class is an abstraction used to perform various operations on a
* native WIN32 thread.
*/
class ThreadOps {
//! Dispatch function for native thread
static unsigned int __stdcall _dispatch(void*);
//! TID while the thread is executing.
HANDLE _hThread;
DWORD _tid;
ThreadOps(DWORD tid) : _tid(tid) { }
public:
const static ThreadOps INVALID;
/**
* Create a new ThreadOps to represent a native thread.
*/
ThreadOps() : _tid(0), _hThread(NULL) {}
inline bool operator==(const ThreadOps& ops) const {
return _tid == ops._tid;
}
static ThreadOps self() {
return ThreadOps(::GetCurrentThreadId());
}
/**
* Update the native tid for this thread so it matches the current
* thread.
*/
static void activate(ThreadOps* ops) {
assert(ops);
assert(ops->_tid == 0);
ops->_tid = ::GetCurrentThreadId();
}
/**
* Test if this object representative of the currently executing
* native thread.
*
* @return bool true if successful
*/
static bool isCurrent(ThreadOps* ops) {
assert(ops);
return ops->_tid == ::GetCurrentThreadId();
}
/**
* Join a native thread.
*
* @return bool true if successful
*/
static bool join(ThreadOps*);
/**
* Force the current native thread to yield, letting the scheduler
* give the CPU time to another thread.
*
* @return bool true if successful
*/
static bool yield();
/**
* Set the priority for the native thread if supported by the
* system.
*
* @param PRIORITY requested priority
* @return bool false if unsuccessful
*/
static bool setPriority(ThreadOps*, Priority);
/**
* Set the priority for the native thread if supported by the
* system.
*
* @param Thread::PRIORITY& current priority
* @return bool false if unsuccessful
*/
static bool getPriority(ThreadOps*, Priority&);
protected:
/**
* Spawn a native thread.
*
* @param ThreadImpl* parent thread
* @param ThreadImpl* child thread being started.
* @param Runnable* task being executed.
*
* @return bool true if successful
*/
bool spawn(Runnable*);
};
}
#endif

View file

@ -0,0 +1,115 @@
/*
* 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 <windows.h>
#include <assert.h>
namespace ZThread {
typedef struct atomic_count_t {
CRITICAL_SECTION cs;
size_t count;
atomic_count_t() : count(0) {}
} ATOMIC_COUNT;
AtomicCount::AtomicCount() {
ATOMIC_COUNT* c = new ATOMIC_COUNT;
_value = reinterpret_cast<void*>(c);
::InitializeCriticalSection(&c->cs);
}
AtomicCount::~AtomicCount() {
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
assert(c->count == 0);
::DeleteCriticalSection(&c->cs);
delete c;
}
//! Postfix decrement and return the current value
size_t AtomicCount::operator--(int) {
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
size_t value;
::EnterCriticalSection(&c->cs);
value = c->count--;
::LeaveCriticalSection(&c->cs);
return value;
}
//! Postfix increment and return the current value
size_t AtomicCount::operator++(int) {
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
size_t value;
::EnterCriticalSection(&c->cs);
value = c->count++;
::LeaveCriticalSection(&c->cs);
return value;
}
//! Prefix decrement and return the current value
size_t AtomicCount::operator--() {
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
size_t value;
::EnterCriticalSection(&c->cs);
value = --c->count;
::LeaveCriticalSection(&c->cs);
return value;
}
//! Prefix increment and return the current value
size_t AtomicCount::operator++() {
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
size_t value;
::EnterCriticalSection(&c->cs);
value = ++c->count;
::LeaveCriticalSection(&c->cs);
return value;
}
};
#endif // __ZTATOMICCOUNTIMPL_H__

View file

@ -0,0 +1,130 @@
/*
* 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 <windows.h>
#include <assert.h>
namespace ZThread {
/**
* @class FastLock
*
* @author Eric Crahen <http://www.code-foo.com>
* @date <2003-07-16T23:31:51-0400>
* @version 2.2.0
*
* This uses a custom spin lock based on the older swap & compare approach
* using the XCHG instruction. You should only use this is you *absolutely* need
* to use an older system, like Windows 95. If you can, use the Win32 version.
*
* Because Windows 95 and earlier can run on processors prior to the 486, they
* don't all support the CMPXCHG function, and so Windows 95 an earlier dont support
* InterlockedCompareExchange.
*
* This is asm inlined for microsoft visual c, it needs to be changed in order to
* compile with gcc, or another win32 compiler - but more likely than not you'll
* be using the Win32 version on those compilers and this won't be a problem.
*/
class FastLock : private NonCopyable {
// Add def for mingw32 or other non-ms compiler to align on 32-bit boundary
#pragma pack(push, 4)
unsigned char volatile _lock;
#pragma pack(pop)
public:
/**
* Create a new FastLock
*/
inline FastLock() : _lock(0) { }
inline ~FastLock() {
assert(_lock == 0);
}
inline void acquire() {
DWORD dw = (DWORD)&_lock;
_asm { // swap & compare
spin_lock:
mov al, 1
mov esi, dw
xchg [esi], al
and al,al
jz spin_locked
}
::Sleep(0);
_asm {
jmp spin_lock
spin_locked:
}
}
inline void release() {
DWORD dw = (DWORD)&_lock;
_asm {
mov al, 0
mov esi, dw
xchg [esi], al
}
}
inline bool tryAcquire(unsigned long timeout=0) {
volatile DWORD dw = (DWORD)&_lock;
volatile DWORD result;
_asm {
mov al, 1
mov esi, dw
xchg [esi], al
and al,al
mov esi, result
xchg [esi], al
}
return result == 0;
}
}; /* Fast Lock */
} // namespace ZThread
#endif