mirror of
https://github.com/mangosfour/server.git
synced 2025-12-21 19:37:02 +00:00
Imported MaNGOS revision 6767 from http://mangos.svn.sourceforge.net/svnroot/mangos/trunk/
This commit is contained in:
parent
d767495d5b
commit
800ee76535
3322 changed files with 903437 additions and 0 deletions
57
dep/src/zthread/AtomicCount.cxx
Normal file
57
dep/src/zthread/AtomicCount.cxx
Normal 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__
|
||||
54
dep/src/zthread/ConcurrentExecutor.cxx
Normal file
54
dep/src/zthread/ConcurrentExecutor.cxx
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
80
dep/src/zthread/Condition.cxx
Normal file
80
dep/src/zthread/Condition.cxx
Normal 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
|
||||
|
||||
377
dep/src/zthread/ConditionImpl.h
Normal file
377
dep/src/zthread/ConditionImpl.h
Normal 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__
|
||||
92
dep/src/zthread/CountingSemaphore.cxx
Normal file
92
dep/src/zthread/CountingSemaphore.cxx
Normal 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
32
dep/src/zthread/Debug.h
Normal 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
|
||||
63
dep/src/zthread/DeferredInterruptionScope.h
Normal file
63
dep/src/zthread/DeferredInterruptionScope.h
Normal 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__
|
||||
71
dep/src/zthread/FastLock.h
Normal file
71
dep/src/zthread/FastLock.h
Normal 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__
|
||||
53
dep/src/zthread/FastMutex.cxx
Normal file
53
dep/src/zthread/FastMutex.cxx
Normal 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
|
||||
74
dep/src/zthread/FastRecursiveLock.h
Normal file
74
dep/src/zthread/FastRecursiveLock.h
Normal 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__
|
||||
53
dep/src/zthread/FastRecursiveMutex.cxx
Normal file
53
dep/src/zthread/FastRecursiveMutex.cxx
Normal 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
|
||||
99
dep/src/zthread/IntrusivePtr.h
Normal file
99
dep/src/zthread/IntrusivePtr.h
Normal 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
132
dep/src/zthread/Makefile.am
Normal 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
|
||||
39
dep/src/zthread/Monitor.cxx
Normal file
39
dep/src/zthread/Monitor.cxx
Normal 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
60
dep/src/zthread/Monitor.h
Normal 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
68
dep/src/zthread/Mutex.cxx
Normal 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
377
dep/src/zthread/MutexImpl.h
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
629
dep/src/zthread/PoolExecutor.cxx
Normal file
629
dep/src/zthread/PoolExecutor.cxx
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
80
dep/src/zthread/PriorityCondition.cxx
Normal file
80
dep/src/zthread/PriorityCondition.cxx
Normal 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
|
||||
|
||||
109
dep/src/zthread/PriorityInheritanceMutex.cxx
Normal file
109
dep/src/zthread/PriorityInheritanceMutex.cxx
Normal 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
|
||||
|
||||
69
dep/src/zthread/PriorityMutex.cxx
Normal file
69
dep/src/zthread/PriorityMutex.cxx
Normal 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
|
||||
|
||||
104
dep/src/zthread/PrioritySemaphore.cxx
Normal file
104
dep/src/zthread/PrioritySemaphore.cxx
Normal 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
|
||||
61
dep/src/zthread/RecursiveMutex.cxx
Normal file
61
dep/src/zthread/RecursiveMutex.cxx
Normal 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
|
||||
286
dep/src/zthread/RecursiveMutexImpl.cxx
Normal file
286
dep/src/zthread/RecursiveMutexImpl.cxx
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
78
dep/src/zthread/RecursiveMutexImpl.h
Normal file
78
dep/src/zthread/RecursiveMutexImpl.h
Normal 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
|
||||
96
dep/src/zthread/Scheduling.h
Normal file
96
dep/src/zthread/Scheduling.h
Normal 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__
|
||||
101
dep/src/zthread/Semaphore.cxx
Normal file
101
dep/src/zthread/Semaphore.cxx
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
348
dep/src/zthread/SemaphoreImpl.h
Normal file
348
dep/src/zthread/SemaphoreImpl.h
Normal 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
151
dep/src/zthread/State.h
Normal 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
179
dep/src/zthread/Status.h
Normal 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
|
||||
90
dep/src/zthread/SynchronousExecutor.cxx
Normal file
90
dep/src/zthread/SynchronousExecutor.cxx
Normal 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
52
dep/src/zthread/TSS.h
Normal 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
127
dep/src/zthread/Thread.cxx
Normal 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
|
||||
470
dep/src/zthread/ThreadImpl.cxx
Normal file
470
dep/src/zthread/ThreadImpl.cxx
Normal 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
|
||||
122
dep/src/zthread/ThreadImpl.h
Normal file
122
dep/src/zthread/ThreadImpl.h
Normal 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__
|
||||
66
dep/src/zthread/ThreadLocalImpl.cxx
Normal file
66
dep/src/zthread/ThreadLocalImpl.cxx
Normal 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
|
||||
54
dep/src/zthread/ThreadOps.cxx
Normal file
54
dep/src/zthread/ThreadOps.cxx
Normal 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
|
||||
67
dep/src/zthread/ThreadOps.h
Normal file
67
dep/src/zthread/ThreadOps.h
Normal 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__
|
||||
266
dep/src/zthread/ThreadQueue.cxx
Normal file
266
dep/src/zthread/ThreadQueue.cxx
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
134
dep/src/zthread/ThreadQueue.h
Normal file
134
dep/src/zthread/ThreadQueue.h
Normal 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__
|
||||
464
dep/src/zthread/ThreadedExecutor.cxx
Normal file
464
dep/src/zthread/ThreadedExecutor.cxx
Normal 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
45
dep/src/zthread/Time.cxx
Normal 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();
|
||||
|
||||
}
|
||||
|
||||
|
||||
86
dep/src/zthread/TimeStrategy.h
Normal file
86
dep/src/zthread/TimeStrategy.h
Normal 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__
|
||||
73
dep/src/zthread/linux/AtomicCount.cxx
Normal file
73
dep/src/zthread/linux/AtomicCount.cxx
Normal 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__
|
||||
117
dep/src/zthread/linux/AtomicFastLock.h
Normal file
117
dep/src/zthread/linux/AtomicFastLock.h
Normal 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
|
||||
83
dep/src/zthread/linux/FastRecursiveLock.h
Normal file
83
dep/src/zthread/linux/FastRecursiveLock.h
Normal 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
|
||||
139
dep/src/zthread/macos/FastLock.h
Normal file
139
dep/src/zthread/macos/FastLock.h
Normal 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
|
||||
|
||||
|
||||
|
||||
280
dep/src/zthread/macos/Monitor.cxx
Normal file
280
dep/src/zthread/macos/Monitor.cxx
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
156
dep/src/zthread/macos/Monitor.h
Normal file
156
dep/src/zthread/macos/Monitor.h
Normal 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
120
dep/src/zthread/macos/TSS.h
Normal 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
|
||||
|
||||
|
||||
103
dep/src/zthread/macos/ThreadOps.cxx
Normal file
103
dep/src/zthread/macos/ThreadOps.cxx
Normal 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
|
||||
|
||||
|
||||
167
dep/src/zthread/macos/ThreadOps.h
Normal file
167
dep/src/zthread/macos/ThreadOps.h
Normal 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__
|
||||
|
||||
86
dep/src/zthread/macos/UpTimeStrategy.h
Normal file
86
dep/src/zthread/macos/UpTimeStrategy.h
Normal 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__
|
||||
146
dep/src/zthread/posix/ConditionRecursiveLock.h
Normal file
146
dep/src/zthread/posix/ConditionRecursiveLock.h
Normal 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
|
||||
121
dep/src/zthread/posix/FastLock.h
Normal file
121
dep/src/zthread/posix/FastLock.h
Normal 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
|
||||
84
dep/src/zthread/posix/FtimeStrategy.h
Normal file
84
dep/src/zthread/posix/FtimeStrategy.h
Normal 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__
|
||||
75
dep/src/zthread/posix/GetTimeOfDayStrategy.h
Normal file
75
dep/src/zthread/posix/GetTimeOfDayStrategy.h
Normal 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__
|
||||
257
dep/src/zthread/posix/Monitor.cxx
Normal file
257
dep/src/zthread/posix/Monitor.cxx
Normal 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
|
||||
|
||||
153
dep/src/zthread/posix/Monitor.h
Normal file
153
dep/src/zthread/posix/Monitor.h
Normal 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
|
||||
51
dep/src/zthread/posix/PriorityOps.h
Normal file
51
dep/src/zthread/posix/PriorityOps.h
Normal 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
104
dep/src/zthread/posix/TSS.h
Normal 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
|
||||
|
||||
|
||||
147
dep/src/zthread/posix/ThreadOps.cxx
Normal file
147
dep/src/zthread/posix/ThreadOps.cxx
Normal 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, ¶m) == 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, ¶m) == 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
|
||||
|
||||
|
||||
154
dep/src/zthread/posix/ThreadOps.h
Normal file
154
dep/src/zthread/posix/ThreadOps.h
Normal 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__
|
||||
122
dep/src/zthread/solaris/FastRecursiveLock.h
Normal file
122
dep/src/zthread/solaris/FastRecursiveLock.h
Normal 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
|
||||
173
dep/src/zthread/vanilla/DualMutexRecursiveLock.h
Normal file
173
dep/src/zthread/vanilla/DualMutexRecursiveLock.h
Normal 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
|
||||
100
dep/src/zthread/vanilla/SimpleAtomicCount.cxx
Normal file
100
dep/src/zthread/vanilla/SimpleAtomicCount.cxx
Normal 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__
|
||||
130
dep/src/zthread/vanilla/SimpleRecursiveLock.h
Normal file
130
dep/src/zthread/vanilla/SimpleRecursiveLock.h
Normal 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
|
||||
60
dep/src/zthread/win32/AtomicCount.cxx
Normal file
60
dep/src/zthread/win32/AtomicCount.cxx
Normal 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__
|
||||
122
dep/src/zthread/win32/AtomicFastLock.h
Normal file
122
dep/src/zthread/win32/AtomicFastLock.h
Normal 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
|
||||
158
dep/src/zthread/win32/AtomicFastRecursiveLock.h
Normal file
158
dep/src/zthread/win32/AtomicFastRecursiveLock.h
Normal 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
|
||||
146
dep/src/zthread/win32/FastLock.h
Normal file
146
dep/src/zthread/win32/FastLock.h
Normal 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
|
||||
109
dep/src/zthread/win32/FastRecursiveLock.h
Normal file
109
dep/src/zthread/win32/FastRecursiveLock.h
Normal 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
|
||||
242
dep/src/zthread/win32/Monitor.cxx
Normal file
242
dep/src/zthread/win32/Monitor.cxx
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
153
dep/src/zthread/win32/Monitor.h
Normal file
153
dep/src/zthread/win32/Monitor.h
Normal 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
|
||||
108
dep/src/zthread/win32/PerformanceCounterStrategy.h
Normal file
108
dep/src/zthread/win32/PerformanceCounterStrategy.h
Normal 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
108
dep/src/zthread/win32/TSS.h
Normal 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
|
||||
|
||||
|
||||
197
dep/src/zthread/win32/ThreadOps.cxx
Normal file
197
dep/src/zthread/win32/ThreadOps.cxx
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
152
dep/src/zthread/win32/ThreadOps.h
Normal file
152
dep/src/zthread/win32/ThreadOps.h
Normal 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
|
||||
115
dep/src/zthread/win9x/AtomicCount.cxx
Normal file
115
dep/src/zthread/win9x/AtomicCount.cxx
Normal 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__
|
||||
130
dep/src/zthread/win9x/AtomicFastLock.h
Normal file
130
dep/src/zthread/win9x/AtomicFastLock.h
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue