Yet more tabs to spaces
--HG-- branch : trunk
This commit is contained in:
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
namespace ZThread {
|
namespace ZThread {
|
||||||
|
|
||||||
ConcurrentExecutor::ConcurrentExecutor()
|
ConcurrentExecutor::ConcurrentExecutor()
|
||||||
: _executor(1) {}
|
: _executor(1) {}
|
||||||
|
|
||||||
void ConcurrentExecutor::interrupt() {
|
void ConcurrentExecutor::interrupt() {
|
||||||
@@ -34,21 +34,21 @@ namespace ZThread {
|
|||||||
void ConcurrentExecutor::execute(const Task& task) {
|
void ConcurrentExecutor::execute(const Task& task) {
|
||||||
_executor.execute(task);
|
_executor.execute(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConcurrentExecutor::cancel() {
|
void ConcurrentExecutor::cancel() {
|
||||||
_executor.cancel();
|
_executor.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConcurrentExecutor::isCanceled() {
|
bool ConcurrentExecutor::isCanceled() {
|
||||||
return _executor.isCanceled();
|
return _executor.isCanceled();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConcurrentExecutor::wait() {
|
void ConcurrentExecutor::wait() {
|
||||||
_executor.wait();
|
_executor.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConcurrentExecutor::wait(unsigned long timeout) {
|
bool ConcurrentExecutor::wait(unsigned long timeout) {
|
||||||
return _executor.wait(timeout);
|
return _executor.wait(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,14 +32,14 @@ namespace ZThread {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Condition::Condition(Lockable& lock) {
|
Condition::Condition(Lockable& lock) {
|
||||||
|
|
||||||
_impl = new FifoConditionImpl(lock);
|
_impl = new FifoConditionImpl(lock);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Condition::~Condition() {
|
Condition::~Condition() {
|
||||||
|
|
||||||
if(_impl != 0)
|
if(_impl != 0)
|
||||||
delete _impl;
|
delete _impl;
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ namespace ZThread {
|
|||||||
|
|
||||||
|
|
||||||
void Condition::signal() {
|
void Condition::signal() {
|
||||||
|
|
||||||
_impl->signal();
|
_impl->signal();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ namespace ZThread {
|
|||||||
|
|
||||||
|
|
||||||
CountingSemaphore::CountingSemaphore(int initialCount) {
|
CountingSemaphore::CountingSemaphore(int initialCount) {
|
||||||
|
|
||||||
_impl = new FifoSemaphoreImpl(initialCount, 0 , false);
|
_impl = new FifoSemaphoreImpl(initialCount, 0 , false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace ZThread {
|
|||||||
FastMutex::FastMutex() : _lock(new FastLock) { }
|
FastMutex::FastMutex() : _lock(new FastLock) { }
|
||||||
|
|
||||||
FastMutex::~FastMutex() {
|
FastMutex::~FastMutex() {
|
||||||
delete _lock;
|
delete _lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ namespace ZThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool FastMutex::tryAcquire(unsigned long timeout) {
|
bool FastMutex::tryAcquire(unsigned long timeout) {
|
||||||
|
|
||||||
return _lock->tryAcquire(timeout);
|
return _lock->tryAcquire(timeout);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,10 +25,10 @@
|
|||||||
|
|
||||||
namespace ZThread {
|
namespace ZThread {
|
||||||
|
|
||||||
FastRecursiveMutex::FastRecursiveMutex()
|
FastRecursiveMutex::FastRecursiveMutex()
|
||||||
: _lock(new FastRecursiveLock) { }
|
: _lock(new FastRecursiveLock) { }
|
||||||
|
|
||||||
FastRecursiveMutex::~FastRecursiveMutex()
|
FastRecursiveMutex::~FastRecursiveMutex()
|
||||||
{ delete _lock; }
|
{ delete _lock; }
|
||||||
|
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ namespace ZThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool FastRecursiveMutex::tryAcquire(unsigned long timeout) {
|
bool FastRecursiveMutex::tryAcquire(unsigned long timeout) {
|
||||||
|
|
||||||
return _lock->tryAcquire(timeout);
|
return _lock->tryAcquire(timeout);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,10 @@
|
|||||||
#include "Monitor.h"
|
#include "Monitor.h"
|
||||||
|
|
||||||
// This file will select an implementation for a Monitor based on
|
// This file will select an implementation for a Monitor based on
|
||||||
// what Monitor.h selects. This method is for selecting the
|
// what Monitor.h selects. This method is for selecting the
|
||||||
// source files, to improve portability. Currently, the project is
|
// source files, to improve portability. Currently, the project is
|
||||||
// based on the autoconf tool-set, which doesn't support conditional
|
// based on the autoconf tool-set, which doesn't support conditional
|
||||||
// compilation well. Additionally, this should make the library
|
// compilation well. Additionally, this should make the library
|
||||||
// easier to port since its working around conditional compilation
|
// easier to port since its working around conditional compilation
|
||||||
// by using C++ features and people won't have to fiddle around with
|
// by using C++ features and people won't have to fiddle around with
|
||||||
// their make tool as much to compile the source
|
// their make tool as much to compile the source
|
||||||
|
|||||||
@@ -64,5 +64,5 @@ namespace ZThread {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace ZThread
|
} // namespace ZThread
|
||||||
|
|
||||||
|
|||||||
+102
-102
@@ -42,7 +42,7 @@ namespace ZThread {
|
|||||||
class WaiterQueue {
|
class WaiterQueue {
|
||||||
|
|
||||||
typedef std::deque<ThreadImpl*> ThreadList;
|
typedef std::deque<ThreadImpl*> ThreadList;
|
||||||
|
|
||||||
typedef struct group_t {
|
typedef struct group_t {
|
||||||
size_t id;
|
size_t id;
|
||||||
size_t count;
|
size_t count;
|
||||||
@@ -68,14 +68,14 @@ namespace ZThread {
|
|||||||
void operator()(const Group& grp) { count += grp.count; }
|
void operator()(const Group& grp) { count += grp.count; }
|
||||||
operator size_t() { return count; }
|
operator size_t() { return count; }
|
||||||
};
|
};
|
||||||
|
|
||||||
FastMutex _lock;
|
FastMutex _lock;
|
||||||
GroupList _list;
|
GroupList _list;
|
||||||
size_t _id;
|
size_t _id;
|
||||||
size_t _generation;
|
size_t _generation;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
WaiterQueue() : _id(0), _generation(0) {
|
WaiterQueue() : _id(0), _generation(0) {
|
||||||
// At least one empty-group exists
|
// At least one empty-group exists
|
||||||
_list.push_back( Group(_id++) );
|
_list.push_back( Group(_id++) );
|
||||||
@@ -89,7 +89,7 @@ namespace ZThread {
|
|||||||
*/
|
*/
|
||||||
bool wait(unsigned long timeout) {
|
bool wait(unsigned long timeout) {
|
||||||
|
|
||||||
ThreadImpl* current = ThreadImpl::current();
|
ThreadImpl* current = ThreadImpl::current();
|
||||||
Monitor& m = current->getMonitor();
|
Monitor& m = current->getMonitor();
|
||||||
|
|
||||||
Monitor::STATE state;
|
Monitor::STATE state;
|
||||||
@@ -103,15 +103,15 @@ namespace ZThread {
|
|||||||
if((size_t)std::for_each(_list.begin(), _list.end(), counter()) < 1)
|
if((size_t)std::for_each(_list.begin(), _list.end(), counter()) < 1)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Update the waiter list for the active group
|
// Update the waiter list for the active group
|
||||||
_list.back().waiters.push_back(current);
|
_list.back().waiters.push_back(current);
|
||||||
size_t n = _list.back().id;
|
size_t n = _list.back().id;
|
||||||
|
|
||||||
m.acquire();
|
m.acquire();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
Guard<FastMutex, UnlockedScope> g2(g1);
|
Guard<FastMutex, UnlockedScope> g2(g1);
|
||||||
state = timeout == 0 ? m.wait() : m.wait(timeout);
|
state = timeout == 0 ? m.wait() : m.wait(timeout);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -142,22 +142,22 @@ namespace ZThread {
|
|||||||
throw Interrupted_Exception();
|
throw Interrupted_Exception();
|
||||||
default:
|
default:
|
||||||
throw Synchronization_Exception();
|
throw Synchronization_Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment the active group count
|
* Increment the active group count
|
||||||
*
|
*
|
||||||
* @pre at least 1 empty group exists
|
* @pre at least 1 empty group exists
|
||||||
* @post at least 1 non-empty group exists
|
* @post at least 1 non-empty group exists
|
||||||
*/
|
*/
|
||||||
std::pair<size_t, size_t> increment() {
|
std::pair<size_t, size_t> increment() {
|
||||||
|
|
||||||
Guard<FastMutex> g(_lock);
|
Guard<FastMutex> g(_lock);
|
||||||
|
|
||||||
// At least one empty-group exists
|
// At least one empty-group exists
|
||||||
assert(!_list.empty());
|
assert(!_list.empty());
|
||||||
|
|
||||||
@@ -176,7 +176,7 @@ namespace ZThread {
|
|||||||
|
|
||||||
// When the active group is being incremented, insert a new active group
|
// When the active group is being incremented, insert a new active group
|
||||||
// to replace it if there were waiting threads
|
// to replace it if there were waiting threads
|
||||||
if(i == --_list.end() && !i->waiters.empty())
|
if(i == --_list.end() && !i->waiters.empty())
|
||||||
_list.push_back(Group(_id++));
|
_list.push_back(Group(_id++));
|
||||||
|
|
||||||
// At least 1 non-empty group exists
|
// At least 1 non-empty group exists
|
||||||
@@ -185,27 +185,27 @@ namespace ZThread {
|
|||||||
return std::make_pair(n, _generation);
|
return std::make_pair(n, _generation);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrease the count for the group with the given id.
|
* Decrease the count for the group with the given id.
|
||||||
*
|
*
|
||||||
* @param n group id
|
* @param n group id
|
||||||
*
|
*
|
||||||
* @pre At least 1 non-empty group exists
|
* @pre At least 1 non-empty group exists
|
||||||
* @post At least 1 empty group exists
|
* @post At least 1 empty group exists
|
||||||
*/
|
*/
|
||||||
void decrement(size_t n) {
|
void decrement(size_t n) {
|
||||||
|
|
||||||
Guard<FastMutex> g1(_lock);
|
Guard<FastMutex> g1(_lock);
|
||||||
|
|
||||||
// At least 1 non-empty group exists
|
// At least 1 non-empty group exists
|
||||||
assert((size_t)std::for_each(_list.begin(), _list.end(), counter()) > 0);
|
assert((size_t)std::for_each(_list.begin(), _list.end(), counter()) > 0);
|
||||||
|
|
||||||
// Find the requested group
|
// Find the requested group
|
||||||
GroupList::iterator i = std::find_if(_list.begin(), _list.end(), by_id(n));
|
GroupList::iterator i = std::find_if(_list.begin(), _list.end(), by_id(n));
|
||||||
if(i == _list.end()) {
|
if(i == _list.end()) {
|
||||||
|
|
||||||
// A group should never have been removed until
|
// A group should never have been removed until
|
||||||
// the final task in that group completed
|
// the final task in that group completed
|
||||||
assert(0);
|
assert(0);
|
||||||
@@ -214,11 +214,11 @@ namespace ZThread {
|
|||||||
|
|
||||||
// Decrease the count for tasks in this group,
|
// Decrease the count for tasks in this group,
|
||||||
if(--i->count == 0 && i == _list.begin()) {
|
if(--i->count == 0 && i == _list.begin()) {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
||||||
// When the first group completes, wake all waiters for every
|
// When the first group completes, wake all waiters for every
|
||||||
// group, starting from the first until a group that is not
|
// group, starting from the first until a group that is not
|
||||||
// complete is reached
|
// complete is reached
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -226,29 +226,29 @@ namespace ZThread {
|
|||||||
if(i == --_list.end() && i->waiters.empty())
|
if(i == --_list.end() && i->waiters.empty())
|
||||||
break;
|
break;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if( awaken(*i) ) {
|
if( awaken(*i) ) {
|
||||||
|
|
||||||
// If all waiters were awakened, remove the group
|
// If all waiters were awakened, remove the group
|
||||||
i = _list.erase(i);
|
i = _list.erase(i);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
// Otherwise, unlock and yield allowing the waiter
|
// Otherwise, unlock and yield allowing the waiter
|
||||||
// lists to be updated if other threads are busy
|
// lists to be updated if other threads are busy
|
||||||
Guard<FastLock, UnlockedScope> g2(g1);
|
Guard<FastLock, UnlockedScope> g2(g1);
|
||||||
ThreadImpl::yield();
|
ThreadImpl::yield();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i = _list.begin();
|
i = _list.begin();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} while(i != _list.end() && i->count == 0);
|
} while(i != _list.end() && i->count == 0);
|
||||||
|
|
||||||
// Ensure that an active group exists
|
// Ensure that an active group exists
|
||||||
if(_list.empty())
|
if(_list.empty())
|
||||||
_list.push_back( Group(++_id) );
|
_list.push_back( Group(++_id) );
|
||||||
@@ -257,7 +257,7 @@ namespace ZThread {
|
|||||||
|
|
||||||
// At least one group exists
|
// At least one group exists
|
||||||
assert(!_list.empty());
|
assert(!_list.empty());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -268,40 +268,40 @@ namespace ZThread {
|
|||||||
return next ? _generation++ : _generation;
|
return next ? _generation++ : _generation;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Awaken all the waiters remaining in the given group
|
* Awaken all the waiters remaining in the given group
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - true if all the waiting threads were successfully awakened.
|
* - true if all the waiting threads were successfully awakened.
|
||||||
* - false if there were one or more threads that could not be awakened.
|
* - false if there were one or more threads that could not be awakened.
|
||||||
*/
|
*/
|
||||||
bool awaken(Group& grp) {
|
bool awaken(Group& grp) {
|
||||||
|
|
||||||
// Go through the waiter list in the given group;
|
// Go through the waiter list in the given group;
|
||||||
for(ThreadList::iterator i = grp.waiters.begin(); i != grp.waiters.end();) {
|
for(ThreadList::iterator i = grp.waiters.begin(); i != grp.waiters.end();) {
|
||||||
|
|
||||||
ThreadImpl* impl = *i;
|
ThreadImpl* impl = *i;
|
||||||
Monitor& m = impl->getMonitor();
|
Monitor& m = impl->getMonitor();
|
||||||
|
|
||||||
// Try the monitor lock, if it cant be locked skip to the next waiter
|
// Try the monitor lock, if it cant be locked skip to the next waiter
|
||||||
if(m.tryAcquire()) {
|
if(m.tryAcquire()) {
|
||||||
|
|
||||||
// Notify the monitor & remove from the waiter list so time isn't
|
// Notify the monitor & remove from the waiter list so time isn't
|
||||||
// wasted checking it again.
|
// wasted checking it again.
|
||||||
i = grp.waiters.erase(i);
|
i = grp.waiters.erase(i);
|
||||||
|
|
||||||
// Try to wake the waiter, it doesn't matter if this is successful
|
// 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).
|
// or not (only fails when the monitor is already going to stop waiting).
|
||||||
m.notify();
|
m.notify();
|
||||||
m.release();
|
m.release();
|
||||||
|
|
||||||
} else ++i;
|
} else ++i;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return grp.waiters.empty();
|
return grp.waiters.empty();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -310,13 +310,13 @@ namespace ZThread {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @class GroupedRunnable
|
* @class GroupedRunnable
|
||||||
*
|
*
|
||||||
* Wrap a task with group and generation information.
|
* Wrap a task with group and generation information.
|
||||||
*
|
*
|
||||||
* - 'group' allows tasks to be grouped together so that lists of waiting
|
* - 'group' allows tasks to be grouped together so that lists of waiting
|
||||||
* threads can be managed.
|
* threads can be managed.
|
||||||
*
|
*
|
||||||
* - 'generation' allows tasks to be interrupted
|
* - 'generation' allows tasks to be interrupted
|
||||||
*/
|
*/
|
||||||
class GroupedRunnable : public Runnable {
|
class GroupedRunnable : public Runnable {
|
||||||
|
|
||||||
@@ -329,10 +329,10 @@ namespace ZThread {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
GroupedRunnable(const Task& task, WaiterQueue& queue)
|
GroupedRunnable(const Task& task, WaiterQueue& queue)
|
||||||
: _task(task), _queue(queue) {
|
: _task(task), _queue(queue) {
|
||||||
|
|
||||||
std::pair<size_t, size_t> pr( _queue.increment() );
|
std::pair<size_t, size_t> pr( _queue.increment() );
|
||||||
|
|
||||||
_group = pr.first;
|
_group = pr.first;
|
||||||
_generation = pr.second;
|
_generation = pr.second;
|
||||||
|
|
||||||
@@ -368,10 +368,10 @@ namespace ZThread {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class ExecutorImpl {
|
class ExecutorImpl {
|
||||||
|
|
||||||
typedef MonitoredQueue<ExecutorTask, FastMutex> TaskQueue;
|
typedef MonitoredQueue<ExecutorTask, FastMutex> TaskQueue;
|
||||||
typedef std::deque<ThreadImpl*> ThreadList;
|
typedef std::deque<ThreadImpl*> ThreadList;
|
||||||
|
|
||||||
TaskQueue _taskQueue;
|
TaskQueue _taskQueue;
|
||||||
WaiterQueue _waitingQueue;
|
WaiterQueue _waitingQueue;
|
||||||
|
|
||||||
@@ -380,19 +380,19 @@ namespace ZThread {
|
|||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ExecutorImpl() : _size(0) {}
|
ExecutorImpl() : _size(0) {}
|
||||||
|
|
||||||
|
|
||||||
void registerThread() {
|
void registerThread() {
|
||||||
|
|
||||||
Guard<TaskQueue> g(_taskQueue);
|
Guard<TaskQueue> g(_taskQueue);
|
||||||
|
|
||||||
ThreadImpl* impl = ThreadImpl::current();
|
ThreadImpl* impl = ThreadImpl::current();
|
||||||
_threads.push_back(impl);
|
_threads.push_back(impl);
|
||||||
|
|
||||||
// current cancel if too many threads are being created
|
// current cancel if too many threads are being created
|
||||||
if(_threads.size() > _size)
|
if(_threads.size() > _size)
|
||||||
impl->cancel();
|
impl->cancel();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -408,14 +408,14 @@ namespace ZThread {
|
|||||||
|
|
||||||
// Wrap the task with a grouped task
|
// Wrap the task with a grouped task
|
||||||
GroupedRunnable* runnable = new GroupedRunnable(task, _waitingQueue);
|
GroupedRunnable* runnable = new GroupedRunnable(task, _waitingQueue);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
_taskQueue.add( ExecutorTask(runnable) );
|
_taskQueue.add( ExecutorTask(runnable) );
|
||||||
|
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
|
|
||||||
// Incase the queue is canceled between the time the WaiterQueue is
|
// Incase the queue is canceled between the time the WaiterQueue is
|
||||||
// updated and the task is added to the TaskQueue
|
// updated and the task is added to the TaskQueue
|
||||||
_waitingQueue.decrement( runnable->group() );
|
_waitingQueue.decrement( runnable->group() );
|
||||||
throw;
|
throw;
|
||||||
@@ -430,41 +430,41 @@ namespace ZThread {
|
|||||||
_waitingQueue.generation(true);
|
_waitingQueue.generation(true);
|
||||||
|
|
||||||
Guard<TaskQueue> g(_taskQueue);
|
Guard<TaskQueue> g(_taskQueue);
|
||||||
|
|
||||||
// Interrupt all threads currently running, thier tasks would be
|
// Interrupt all threads currently running, thier tasks would be
|
||||||
// from an older generation
|
// from an older generation
|
||||||
for(ThreadList::iterator i = _threads.begin(); i != _threads.end(); ++i)
|
for(ThreadList::iterator i = _threads.begin(); i != _threads.end(); ++i)
|
||||||
(*i)->interrupt();
|
(*i)->interrupt();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Adjust the number of desired workers and return the number of Threads needed
|
//! Adjust the number of desired workers and return the number of Threads needed
|
||||||
size_t workers(size_t n) {
|
size_t workers(size_t n) {
|
||||||
|
|
||||||
Guard<TaskQueue> g(_taskQueue);
|
Guard<TaskQueue> g(_taskQueue);
|
||||||
|
|
||||||
size_t m = (_size < n) ? (n - _size) : 0;
|
size_t m = (_size < n) ? (n - _size) : 0;
|
||||||
_size = n;
|
_size = n;
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t workers() {
|
size_t workers() {
|
||||||
|
|
||||||
Guard<TaskQueue> g(_taskQueue);
|
Guard<TaskQueue> g(_taskQueue);
|
||||||
return _size;
|
return _size;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutorTask next() {
|
ExecutorTask next() {
|
||||||
|
|
||||||
ExecutorTask task;
|
ExecutorTask task;
|
||||||
|
|
||||||
// Draw the task from the queue
|
// Draw the task from the queue
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
task = _taskQueue.next();
|
task = _taskQueue.next();
|
||||||
break;
|
break;
|
||||||
@@ -473,13 +473,13 @@ namespace ZThread {
|
|||||||
|
|
||||||
// Ignore interruption here, it can only come from
|
// Ignore interruption here, it can only come from
|
||||||
// another thread interrupt()ing the executor. The
|
// another thread interrupt()ing the executor. The
|
||||||
// thread was interrupted in the hopes it was busy
|
// thread was interrupted in the hopes it was busy
|
||||||
// with a task
|
// with a task
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interrupt the thread running the tasks when the generation
|
// Interrupt the thread running the tasks when the generation
|
||||||
// does not match the current generation
|
// does not match the current generation
|
||||||
if( task->generation() != _waitingQueue.generation() )
|
if( task->generation() != _waitingQueue.generation() )
|
||||||
@@ -512,31 +512,31 @@ namespace ZThread {
|
|||||||
class Worker : public Runnable {
|
class Worker : public Runnable {
|
||||||
|
|
||||||
CountedPtr< ExecutorImpl > _impl;
|
CountedPtr< ExecutorImpl > _impl;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//! Create a Worker that draws upon the given Queue
|
//! Create a Worker that draws upon the given Queue
|
||||||
Worker(const CountedPtr< ExecutorImpl >& impl)
|
Worker(const CountedPtr< ExecutorImpl >& impl)
|
||||||
: _impl(impl) { }
|
: _impl(impl) { }
|
||||||
|
|
||||||
//! Run until Thread or Queue are canceled
|
//! Run until Thread or Queue are canceled
|
||||||
void run() {
|
void run() {
|
||||||
|
|
||||||
_impl->registerThread();
|
_impl->registerThread();
|
||||||
|
|
||||||
// Run until the Queue is canceled
|
// Run until the Queue is canceled
|
||||||
while(!Thread::canceled()) {
|
while(!Thread::canceled()) {
|
||||||
|
|
||||||
// Draw tasks from the queue
|
// Draw tasks from the queue
|
||||||
ExecutorTask task( _impl->next() );
|
ExecutorTask task( _impl->next() );
|
||||||
task->run();
|
task->run();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_impl->unregisterThread();
|
_impl->unregisterThread();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}; /* Worker */
|
}; /* Worker */
|
||||||
|
|
||||||
|
|
||||||
@@ -547,10 +547,10 @@ namespace ZThread {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Shutdown(const CountedPtr< ExecutorImpl >& impl)
|
Shutdown(const CountedPtr< ExecutorImpl >& impl)
|
||||||
: _impl(impl) { }
|
: _impl(impl) { }
|
||||||
|
|
||||||
void run() {
|
void run() {
|
||||||
_impl->cancel();
|
_impl->cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,35 +560,35 @@ namespace ZThread {
|
|||||||
|
|
||||||
PoolExecutor::PoolExecutor(size_t n)
|
PoolExecutor::PoolExecutor(size_t n)
|
||||||
: _impl( new ExecutorImpl() ), _shutdown( new Shutdown(_impl) ) {
|
: _impl( new ExecutorImpl() ), _shutdown( new Shutdown(_impl) ) {
|
||||||
|
|
||||||
size(n);
|
size(n);
|
||||||
|
|
||||||
// Request cancelation when main() exits
|
// Request cancelation when main() exits
|
||||||
ThreadQueue::instance()->insertShutdownTask(_shutdown);
|
ThreadQueue::instance()->insertShutdownTask(_shutdown);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PoolExecutor::~PoolExecutor() {
|
PoolExecutor::~PoolExecutor() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the shutdown task for this executor has not already been
|
* If the shutdown task for this executor has not already been
|
||||||
* selected to run, then run it locally
|
* selected to run, then run it locally
|
||||||
*/
|
*/
|
||||||
if(ThreadQueue::instance()->removeShutdownTask(_shutdown))
|
if(ThreadQueue::instance()->removeShutdownTask(_shutdown))
|
||||||
_shutdown->run();
|
_shutdown->run();
|
||||||
|
|
||||||
} catch(...) { }
|
} catch(...) { }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PoolExecutor::interrupt() {
|
void PoolExecutor::interrupt() {
|
||||||
_impl->interrupt();
|
_impl->interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PoolExecutor::size(size_t n) {
|
void PoolExecutor::size(size_t n) {
|
||||||
|
|
||||||
if(n < 1)
|
if(n < 1)
|
||||||
throw InvalidOp_Exception();
|
throw InvalidOp_Exception();
|
||||||
|
|
||||||
@@ -604,26 +604,26 @@ namespace ZThread {
|
|||||||
|
|
||||||
void PoolExecutor::execute(const Task& task) {
|
void PoolExecutor::execute(const Task& task) {
|
||||||
|
|
||||||
// Enqueue the task, the Queue will reject it with a
|
// Enqueue the task, the Queue will reject it with a
|
||||||
// Cancelation_Exception if the Executor has been canceled
|
// Cancelation_Exception if the Executor has been canceled
|
||||||
_impl->execute(task);
|
_impl->execute(task);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PoolExecutor::cancel() {
|
void PoolExecutor::cancel() {
|
||||||
_impl->cancel();
|
_impl->cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PoolExecutor::isCanceled() {
|
bool PoolExecutor::isCanceled() {
|
||||||
return _impl->isCanceled();
|
return _impl->isCanceled();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PoolExecutor::wait() {
|
void PoolExecutor::wait() {
|
||||||
_impl->wait(0);
|
_impl->wait(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PoolExecutor::wait(unsigned long timeout) {
|
bool PoolExecutor::wait(unsigned long timeout) {
|
||||||
return _impl->wait(timeout == 0 ? 1 : timeout);
|
return _impl->wait(timeout == 0 ? 1 : timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,14 +32,14 @@ namespace ZThread {
|
|||||||
};
|
};
|
||||||
|
|
||||||
PriorityCondition::PriorityCondition(Lockable& lock) {
|
PriorityCondition::PriorityCondition(Lockable& lock) {
|
||||||
|
|
||||||
_impl = new PriorityConditionImpl(lock);
|
_impl = new PriorityConditionImpl(lock);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PriorityCondition::~PriorityCondition() {
|
PriorityCondition::~PriorityCondition() {
|
||||||
|
|
||||||
if(_impl != 0)
|
if(_impl != 0)
|
||||||
delete _impl;
|
delete _impl;
|
||||||
|
|
||||||
|
|||||||
@@ -28,28 +28,28 @@
|
|||||||
namespace ZThread {
|
namespace ZThread {
|
||||||
|
|
||||||
class InheritPriorityBehavior : public NullBehavior {
|
class InheritPriorityBehavior : public NullBehavior {
|
||||||
|
|
||||||
ThreadImpl* owner;
|
ThreadImpl* owner;
|
||||||
Priority p;
|
Priority p;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// Temporarily raise the effective priority of the owner
|
// Temporarily raise the effective priority of the owner
|
||||||
inline void waiterArrived(ThreadImpl* impl) {
|
inline void waiterArrived(ThreadImpl* impl) {
|
||||||
|
|
||||||
Priority q = impl->getPriority();
|
Priority q = impl->getPriority();
|
||||||
if((int)q > (int)p) {
|
if((int)q > (int)p) {
|
||||||
|
|
||||||
ThreadOps::setPriority(impl, p);
|
ThreadOps::setPriority(impl, p);
|
||||||
p = q;
|
p = q;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Note the owners priority
|
// Note the owners priority
|
||||||
inline void ownerAcquired(ThreadImpl* impl) {
|
inline void ownerAcquired(ThreadImpl* impl) {
|
||||||
|
|
||||||
p = impl->getPriority();
|
p = impl->getPriority();
|
||||||
owner = impl;
|
owner = impl;
|
||||||
@@ -57,7 +57,7 @@ namespace ZThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Restore its original priority
|
// Restore its original priority
|
||||||
inline void ownerReleased(ThreadImpl* impl) {
|
inline void ownerReleased(ThreadImpl* impl) {
|
||||||
|
|
||||||
if(p > owner->getPriority())
|
if(p > owner->getPriority())
|
||||||
ThreadOps::setPriority(impl, impl->getPriority());
|
ThreadOps::setPriority(impl, impl->getPriority());
|
||||||
@@ -66,18 +66,18 @@ namespace ZThread {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PriorityInheritanceMutexImpl :
|
class PriorityInheritanceMutexImpl :
|
||||||
public MutexImpl<priority_list, InheritPriorityBehavior> { };
|
public MutexImpl<priority_list, InheritPriorityBehavior> { };
|
||||||
|
|
||||||
PriorityInheritanceMutex::PriorityInheritanceMutex() {
|
PriorityInheritanceMutex::PriorityInheritanceMutex() {
|
||||||
|
|
||||||
_impl = new PriorityInheritanceMutexImpl();
|
_impl = new PriorityInheritanceMutexImpl();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PriorityInheritanceMutex::~PriorityInheritanceMutex() {
|
PriorityInheritanceMutex::~PriorityInheritanceMutex() {
|
||||||
|
|
||||||
if(_impl != 0)
|
if(_impl != 0)
|
||||||
delete _impl;
|
delete _impl;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,7 @@ namespace ZThread {
|
|||||||
// P
|
// P
|
||||||
void PriorityInheritanceMutex::acquire() {
|
void PriorityInheritanceMutex::acquire() {
|
||||||
|
|
||||||
_impl->acquire();
|
_impl->acquire();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,14 +93,14 @@ namespace ZThread {
|
|||||||
// P
|
// P
|
||||||
bool PriorityInheritanceMutex::tryAcquire(unsigned long ms) {
|
bool PriorityInheritanceMutex::tryAcquire(unsigned long ms) {
|
||||||
|
|
||||||
return _impl->tryAcquire(ms);
|
return _impl->tryAcquire(ms);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// V
|
// V
|
||||||
void PriorityInheritanceMutex::release() {
|
void PriorityInheritanceMutex::release() {
|
||||||
|
|
||||||
_impl->release();
|
_impl->release();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,15 +29,15 @@ namespace ZThread {
|
|||||||
|
|
||||||
class PriorityMutexImpl : public MutexImpl<priority_list, NullBehavior> { };
|
class PriorityMutexImpl : public MutexImpl<priority_list, NullBehavior> { };
|
||||||
|
|
||||||
PriorityMutex::PriorityMutex() {
|
PriorityMutex::PriorityMutex() {
|
||||||
|
|
||||||
_impl = new PriorityMutexImpl();
|
_impl = new PriorityMutexImpl();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PriorityMutex::~PriorityMutex() {
|
PriorityMutex::~PriorityMutex() {
|
||||||
|
|
||||||
if(_impl != 0)
|
if(_impl != 0)
|
||||||
delete _impl;
|
delete _impl;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ namespace ZThread {
|
|||||||
// P
|
// P
|
||||||
void PriorityMutex::acquire() {
|
void PriorityMutex::acquire() {
|
||||||
|
|
||||||
_impl->acquire();
|
_impl->acquire();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,14 +53,14 @@ namespace ZThread {
|
|||||||
// P
|
// P
|
||||||
bool PriorityMutex::tryAcquire(unsigned long ms) {
|
bool PriorityMutex::tryAcquire(unsigned long ms) {
|
||||||
|
|
||||||
return _impl->tryAcquire(ms);
|
return _impl->tryAcquire(ms);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// V
|
// V
|
||||||
void PriorityMutex::release() {
|
void PriorityMutex::release() {
|
||||||
|
|
||||||
_impl->release();
|
_impl->release();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,10 +26,10 @@
|
|||||||
|
|
||||||
namespace ZThread {
|
namespace ZThread {
|
||||||
|
|
||||||
class PrioritySemaphoreImpl : public SemaphoreImpl<priority_list> {
|
class PrioritySemaphoreImpl : public SemaphoreImpl<priority_list> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PrioritySemaphoreImpl(int count, unsigned int maxCount)
|
PrioritySemaphoreImpl(int count, unsigned int maxCount)
|
||||||
: SemaphoreImpl<priority_list>(count, maxCount, true) { }
|
: SemaphoreImpl<priority_list>(count, maxCount, true) { }
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -41,9 +41,9 @@ namespace ZThread {
|
|||||||
* @param maxCount maximum size of the semaphore count
|
* @param maxCount maximum size of the semaphore count
|
||||||
*/
|
*/
|
||||||
PrioritySemaphore::PrioritySemaphore(int count, unsigned int maxCount) {
|
PrioritySemaphore::PrioritySemaphore(int count, unsigned int maxCount) {
|
||||||
|
|
||||||
_impl = new PrioritySemaphoreImpl(count, maxCount);
|
_impl = new PrioritySemaphoreImpl(count, maxCount);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PrioritySemaphore::~PrioritySemaphore() {
|
PrioritySemaphore::~PrioritySemaphore() {
|
||||||
|
|||||||
@@ -26,14 +26,14 @@
|
|||||||
namespace ZThread {
|
namespace ZThread {
|
||||||
|
|
||||||
RecursiveMutex::RecursiveMutex() {
|
RecursiveMutex::RecursiveMutex() {
|
||||||
|
|
||||||
_impl = new RecursiveMutexImpl();
|
_impl = new RecursiveMutexImpl();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RecursiveMutex::~RecursiveMutex() {
|
RecursiveMutex::~RecursiveMutex() {
|
||||||
|
|
||||||
if(_impl != (RecursiveMutexImpl*)0 )
|
if(_impl != (RecursiveMutexImpl*)0 )
|
||||||
delete _impl;
|
delete _impl;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -41,20 +41,20 @@ namespace ZThread {
|
|||||||
|
|
||||||
void RecursiveMutex::acquire() {
|
void RecursiveMutex::acquire() {
|
||||||
|
|
||||||
_impl->acquire();
|
_impl->acquire();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool RecursiveMutex::tryAcquire(unsigned long ms) {
|
bool RecursiveMutex::tryAcquire(unsigned long ms) {
|
||||||
|
|
||||||
return _impl->tryAcquire(ms);
|
return _impl->tryAcquire(ms);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecursiveMutex::release() {
|
void RecursiveMutex::release() {
|
||||||
|
|
||||||
_impl->release();
|
_impl->release();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ namespace ZThread {
|
|||||||
* @exception Initialization_Exception thrown if resources could not be
|
* @exception Initialization_Exception thrown if resources could not be
|
||||||
* properly allocated
|
* properly allocated
|
||||||
*/
|
*/
|
||||||
RecursiveMutexImpl::RecursiveMutexImpl()
|
RecursiveMutexImpl::RecursiveMutexImpl()
|
||||||
: _owner(0), _count(0) {
|
: _owner(0), _count(0) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,14 +52,14 @@ namespace ZThread {
|
|||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
||||||
// It is an error to destroy a mutex that has not been released
|
// It is an error to destroy a mutex that has not been released
|
||||||
if(_owner != 0) {
|
if(_owner != 0) {
|
||||||
|
|
||||||
ZTDEBUG("** You are destroying a mutex which was never released. **\n");
|
ZTDEBUG("** You are destroying a mutex which was never released. **\n");
|
||||||
assert(0); // Destroyed mutex while in use
|
assert(0); // Destroyed mutex while in use
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!_waiters.empty()) {
|
if(!_waiters.empty()) {
|
||||||
|
|
||||||
ZTDEBUG("** You are destroying a mutex which is blocking %d threads. **\n", _waiters.size());
|
ZTDEBUG("** You are destroying a mutex which is blocking %d threads. **\n", _waiters.size());
|
||||||
assert(0); // Destroyed mutex while in use
|
assert(0); // Destroyed mutex while in use
|
||||||
@@ -78,10 +78,10 @@ namespace ZThread {
|
|||||||
Monitor::STATE state;
|
Monitor::STATE state;
|
||||||
|
|
||||||
Guard<FastLock> g1(_lock);
|
Guard<FastLock> g1(_lock);
|
||||||
|
|
||||||
// If there is an entry count and the current thread is
|
// If there is an entry count and the current thread is
|
||||||
// the owner, increment the count and continue.
|
// the owner, increment the count and continue.
|
||||||
if(_owner == &m)
|
if(_owner == &m)
|
||||||
_count++;
|
_count++;
|
||||||
|
|
||||||
else {
|
else {
|
||||||
@@ -91,11 +91,11 @@ namespace ZThread {
|
|||||||
|
|
||||||
assert(_count == 0);
|
assert(_count == 0);
|
||||||
|
|
||||||
_owner = &m;
|
_owner = &m;
|
||||||
_count++;
|
_count++;
|
||||||
|
|
||||||
} else { // Otherwise, wait()
|
} else { // Otherwise, wait()
|
||||||
|
|
||||||
_waiters.push_back(&m);
|
_waiters.push_back(&m);
|
||||||
|
|
||||||
m.acquire();
|
m.acquire();
|
||||||
@@ -108,7 +108,7 @@ namespace ZThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m.release();
|
m.release();
|
||||||
|
|
||||||
// Remove from waiter list, regarless of weather release() is called or
|
// Remove from waiter list, regarless of weather release() is called or
|
||||||
// not. The monitor is sticky, so its possible a state 'stuck' from a
|
// not. The monitor is sticky, so its possible a state 'stuck' from a
|
||||||
// previous operation and will leave the wait() w/o release() having
|
// previous operation and will leave the wait() w/o release() having
|
||||||
@@ -117,39 +117,39 @@ namespace ZThread {
|
|||||||
if(i != _waiters.end())
|
if(i != _waiters.end())
|
||||||
_waiters.erase(i);
|
_waiters.erase(i);
|
||||||
|
|
||||||
// If awoke due to a notify(), take ownership.
|
// If awoke due to a notify(), take ownership.
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case Monitor::SIGNALED:
|
case Monitor::SIGNALED:
|
||||||
|
|
||||||
assert(_owner == 0);
|
assert(_owner == 0);
|
||||||
assert(_count == 0);
|
assert(_count == 0);
|
||||||
|
|
||||||
_owner = &m;
|
_owner = &m;
|
||||||
_count++;
|
_count++;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Monitor::INTERRUPTED:
|
case Monitor::INTERRUPTED:
|
||||||
throw Interrupted_Exception();
|
throw Interrupted_Exception();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw Synchronization_Exception();
|
throw Synchronization_Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RecursiveMutexImpl::tryAcquire(unsigned long timeout) {
|
bool RecursiveMutexImpl::tryAcquire(unsigned long timeout) {
|
||||||
|
|
||||||
// Get the monitor for the current thread
|
// Get the monitor for the current thread
|
||||||
Monitor& m = ThreadImpl::current()->getMonitor();
|
Monitor& m = ThreadImpl::current()->getMonitor();
|
||||||
|
|
||||||
Guard<FastLock> g1(_lock);
|
Guard<FastLock> g1(_lock);
|
||||||
|
|
||||||
// If there is an entry count and the current thread is
|
// If there is an entry count and the current thread is
|
||||||
// the owner, increment the count and continue.
|
// the owner, increment the count and continue.
|
||||||
if(_owner == &m)
|
if(_owner == &m)
|
||||||
_count++;
|
_count++;
|
||||||
@@ -176,14 +176,14 @@ namespace ZThread {
|
|||||||
m.acquire();
|
m.acquire();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
Guard<FastLock, UnlockedScope> g2(g1);
|
Guard<FastLock, UnlockedScope> g2(g1);
|
||||||
state = m.wait(timeout);
|
state = m.wait(timeout);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m.release();
|
m.release();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove from waiter list, regarless of weather release() is called or
|
// Remove from waiter list, regarless of weather release() is called or
|
||||||
@@ -194,7 +194,7 @@ namespace ZThread {
|
|||||||
if(i != _waiters.end())
|
if(i != _waiters.end())
|
||||||
_waiters.erase(i);
|
_waiters.erase(i);
|
||||||
|
|
||||||
// If awoke due to a notify(), take ownership.
|
// If awoke due to a notify(), take ownership.
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case Monitor::SIGNALED:
|
case Monitor::SIGNALED:
|
||||||
|
|
||||||
@@ -203,21 +203,21 @@ namespace ZThread {
|
|||||||
|
|
||||||
_owner = &m;
|
_owner = &m;
|
||||||
_count++;
|
_count++;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Monitor::INTERRUPTED:
|
case Monitor::INTERRUPTED:
|
||||||
throw Interrupted_Exception();
|
throw Interrupted_Exception();
|
||||||
|
|
||||||
case Monitor::TIMEDOUT:
|
case Monitor::TIMEDOUT:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw Synchronization_Exception();
|
throw Synchronization_Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -237,7 +237,7 @@ namespace ZThread {
|
|||||||
|
|
||||||
// Update the count, if it has reached 0, wake another waiter.
|
// Update the count, if it has reached 0, wake another waiter.
|
||||||
if(--_count == 0) {
|
if(--_count == 0) {
|
||||||
|
|
||||||
_owner = 0;
|
_owner = 0;
|
||||||
|
|
||||||
// Try to find a waiter with a backoff & retry scheme
|
// Try to find a waiter with a backoff & retry scheme
|
||||||
@@ -245,24 +245,24 @@ namespace ZThread {
|
|||||||
|
|
||||||
// Go through the list, attempt to notify() a waiter.
|
// Go through the list, attempt to notify() a waiter.
|
||||||
for(List::iterator i = _waiters.begin(); i != _waiters.end();) {
|
for(List::iterator i = _waiters.begin(); i != _waiters.end();) {
|
||||||
|
|
||||||
// Try the monitor lock, if it cant be locked skip to the next waiter
|
// Try the monitor lock, if it cant be locked skip to the next waiter
|
||||||
Monitor* n = *i;
|
Monitor* n = *i;
|
||||||
if(n->tryAcquire()) {
|
if(n->tryAcquire()) {
|
||||||
|
|
||||||
// If notify() is not sucessful, it is because the wait() has already
|
// If notify() is not sucessful, it is because the wait() has already
|
||||||
// been ended (killed/interrupted/notify'd)
|
// been ended (killed/interrupted/notify'd)
|
||||||
bool woke = n->notify();
|
bool woke = n->notify();
|
||||||
n->release();
|
n->release();
|
||||||
|
|
||||||
// Once notify() succeeds, return
|
// Once notify() succeeds, return
|
||||||
if(woke)
|
if(woke)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} else ++i;
|
} else ++i;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_waiters.empty())
|
if(_waiters.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -276,7 +276,7 @@ namespace ZThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ZThread
|
} // namespace ZThread
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ namespace ZThread {
|
|||||||
* @param maxCount maximum size of the semaphore count
|
* @param maxCount maximum size of the semaphore count
|
||||||
*/
|
*/
|
||||||
Semaphore::Semaphore(int count, unsigned int maxCount) {
|
Semaphore::Semaphore(int count, unsigned int maxCount) {
|
||||||
|
|
||||||
_impl = new FifoSemaphoreImpl(count, maxCount, true);
|
_impl = new FifoSemaphoreImpl(count, maxCount, true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Semaphore::~Semaphore() {
|
Semaphore::~Semaphore() {
|
||||||
|
|||||||
@@ -24,12 +24,12 @@
|
|||||||
|
|
||||||
namespace ZThread {
|
namespace ZThread {
|
||||||
|
|
||||||
SynchronousExecutor::SynchronousExecutor()
|
SynchronousExecutor::SynchronousExecutor()
|
||||||
: _canceled(false) {}
|
: _canceled(false) {}
|
||||||
|
|
||||||
SynchronousExecutor::~SynchronousExecutor() {
|
SynchronousExecutor::~SynchronousExecutor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousExecutor::cancel() {
|
void SynchronousExecutor::cancel() {
|
||||||
|
|
||||||
Guard<Mutex> g(_lock);
|
Guard<Mutex> g(_lock);
|
||||||
@@ -38,41 +38,41 @@ namespace ZThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool SynchronousExecutor::isCanceled() {
|
bool SynchronousExecutor::isCanceled() {
|
||||||
|
|
||||||
Guard<Mutex> g(_lock);
|
Guard<Mutex> g(_lock);
|
||||||
return _canceled;
|
return _canceled;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousExecutor::interrupt() {
|
void SynchronousExecutor::interrupt() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousExecutor::execute(const Task& task) {
|
void SynchronousExecutor::execute(const Task& task) {
|
||||||
|
|
||||||
// Canceled Executors will not accept new tasks, quick
|
// Canceled Executors will not accept new tasks, quick
|
||||||
// check to avoid excessive locking in the canceled state
|
// check to avoid excessive locking in the canceled state
|
||||||
if(_canceled)
|
if(_canceled)
|
||||||
throw Cancellation_Exception();
|
throw Cancellation_Exception();
|
||||||
|
|
||||||
Guard<Mutex> g(_lock);
|
Guard<Mutex> g(_lock);
|
||||||
|
|
||||||
if(_canceled) // Double check
|
if(_canceled) // Double check
|
||||||
throw Cancellation_Exception();
|
throw Cancellation_Exception();
|
||||||
|
|
||||||
// Run the task.
|
// Run the task.
|
||||||
Task(task)->run();
|
Task(task)->run();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousExecutor::wait() {
|
void SynchronousExecutor::wait() {
|
||||||
|
|
||||||
if(Thread::interrupted())
|
if(Thread::interrupted())
|
||||||
throw Interrupted_Exception();
|
throw Interrupted_Exception();
|
||||||
|
|
||||||
Guard<Mutex> g(_lock);
|
Guard<Mutex> g(_lock);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Executor::wait(unsigned long)
|
* @see Executor::wait(unsigned long)
|
||||||
*/
|
*/
|
||||||
@@ -80,11 +80,11 @@ namespace ZThread {
|
|||||||
|
|
||||||
if(Thread::interrupted())
|
if(Thread::interrupted())
|
||||||
throw Interrupted_Exception();
|
throw Interrupted_Exception();
|
||||||
|
|
||||||
Guard<Mutex> g(_lock);
|
Guard<Mutex> g(_lock);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -27,20 +27,20 @@
|
|||||||
namespace ZThread {
|
namespace ZThread {
|
||||||
|
|
||||||
|
|
||||||
Thread::Thread()
|
Thread::Thread()
|
||||||
: _impl( ThreadImpl::current() ) {
|
: _impl( ThreadImpl::current() ) {
|
||||||
|
|
||||||
// ThreadImpl's start out life with a reference count
|
// ThreadImpl's start out life with a reference count
|
||||||
// of one, and the they are added to the ThreadQueue.
|
// of one, and the they are added to the ThreadQueue.
|
||||||
_impl->addReference();
|
_impl->addReference();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread::Thread(const Task& task, bool autoCancel)
|
Thread::Thread(const Task& task, bool autoCancel)
|
||||||
: _impl( new ThreadImpl(task, autoCancel) ) {
|
: _impl( new ThreadImpl(task, autoCancel) ) {
|
||||||
|
|
||||||
_impl->addReference();
|
_impl->addReference();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::operator==(const Thread& t) const {
|
bool Thread::operator==(const Thread& t) const {
|
||||||
@@ -94,7 +94,7 @@ namespace ZThread {
|
|||||||
return _impl->interrupt();
|
return _impl->interrupt();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::cancel() {
|
void Thread::cancel() {
|
||||||
|
|
||||||
if(ThreadImpl::current() == _impl)
|
if(ThreadImpl::current() == _impl)
|
||||||
@@ -102,7 +102,7 @@ namespace ZThread {
|
|||||||
|
|
||||||
_impl->cancel();
|
_impl->cancel();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::isCanceled() {
|
bool Thread::isCanceled() {
|
||||||
|
|
||||||
@@ -124,4 +124,4 @@ namespace ZThread {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ZThread
|
} // namespace ZThread
|
||||||
|
|||||||
+141
-141
@@ -34,88 +34,88 @@ namespace ZThread {
|
|||||||
TSS<ThreadImpl*> ThreadImpl::_threadMap;
|
TSS<ThreadImpl*> ThreadImpl::_threadMap;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class Launcher : public Runnable {
|
class Launcher : public Runnable {
|
||||||
|
|
||||||
ThreadImpl* x;
|
ThreadImpl* x;
|
||||||
ThreadImpl* y;
|
ThreadImpl* y;
|
||||||
Task z;
|
Task z;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Launcher(ThreadImpl* a, ThreadImpl* b, const Task& c) : x(a), y(b), z(c) {}
|
Launcher(ThreadImpl* a, ThreadImpl* b, const Task& c) : x(a), y(b), z(c) {}
|
||||||
|
|
||||||
void run() {
|
void run() {
|
||||||
y->dispatch(x,y,z);
|
y->dispatch(x,y,z);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadImpl::ThreadImpl()
|
ThreadImpl::ThreadImpl()
|
||||||
: _state(State::REFERENCE), _priority(Medium), _autoCancel(false) {
|
: _state(State::REFERENCE), _priority(Medium), _autoCancel(false) {
|
||||||
|
|
||||||
ZTDEBUG("Reference thread created.\n");
|
ZTDEBUG("Reference thread created.\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadImpl::ThreadImpl(const Task& task, bool autoCancel)
|
ThreadImpl::ThreadImpl(const Task& task, bool autoCancel)
|
||||||
: _state(State::IDLE), _priority(Medium), _autoCancel(autoCancel) {
|
: _state(State::IDLE), _priority(Medium), _autoCancel(autoCancel) {
|
||||||
|
|
||||||
ZTDEBUG("User thread created.\n");
|
ZTDEBUG("User thread created.\n");
|
||||||
|
|
||||||
start(task);
|
start(task);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ThreadImpl::~ThreadImpl() {
|
ThreadImpl::~ThreadImpl() {
|
||||||
|
|
||||||
_tls.clear();
|
_tls.clear();
|
||||||
|
|
||||||
if(isActive()) {
|
if(isActive()) {
|
||||||
|
|
||||||
ZTDEBUG("You are destroying an executing thread!\n");
|
ZTDEBUG("You are destroying an executing thread!\n");
|
||||||
abort();
|
abort();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ZTDEBUG("Thread destroyed.\n");
|
ZTDEBUG("Thread destroyed.\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Monitor& ThreadImpl::getMonitor() {
|
Monitor& ThreadImpl::getMonitor() {
|
||||||
return _monitor;
|
return _monitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadImpl::cancel(bool autoCancel) {
|
void ThreadImpl::cancel(bool autoCancel) {
|
||||||
if(!autoCancel || _autoCancel)
|
if(!autoCancel || _autoCancel)
|
||||||
_monitor.cancel();
|
_monitor.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThreadImpl::interrupt() {
|
bool ThreadImpl::interrupt() {
|
||||||
return _monitor.interrupt();
|
return _monitor.interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThreadImpl::isInterrupted() {
|
bool ThreadImpl::isInterrupted() {
|
||||||
return _monitor.isInterrupted();
|
return _monitor.isInterrupted();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThreadImpl::isCanceled() {
|
bool ThreadImpl::isCanceled() {
|
||||||
return _monitor.isCanceled();
|
return _monitor.isCanceled();
|
||||||
}
|
}
|
||||||
|
|
||||||
Priority ThreadImpl::getPriority() const {
|
Priority ThreadImpl::getPriority() const {
|
||||||
return _priority;
|
return _priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool ThreadImpl::isReference() {
|
bool ThreadImpl::isReference() {
|
||||||
return _state.isReference();
|
return _state.isReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Join the thread, blocking the caller until it is interrupted or until
|
* Join the thread, blocking the caller until it is interrupted or until
|
||||||
* the thread represented by this object exits.
|
* the thread represented by this object exits.
|
||||||
@@ -124,27 +124,27 @@ namespace ZThread {
|
|||||||
* joined.
|
* joined.
|
||||||
*/
|
*/
|
||||||
bool ThreadImpl::join(unsigned long timeout) {
|
bool ThreadImpl::join(unsigned long timeout) {
|
||||||
|
|
||||||
// Serial access to this ThreadImpl's state
|
// Serial access to this ThreadImpl's state
|
||||||
Guard<Monitor> g1(_monitor);
|
Guard<Monitor> g1(_monitor);
|
||||||
|
|
||||||
// Make sure a thread is not trying to join() itself.
|
// Make sure a thread is not trying to join() itself.
|
||||||
if(ThreadOps::isCurrent(this))
|
if(ThreadOps::isCurrent(this))
|
||||||
throw Deadlock_Exception("Cannot join self.");
|
throw Deadlock_Exception("Cannot join self.");
|
||||||
|
|
||||||
// Reference threads can't be joined.
|
// Reference threads can't be joined.
|
||||||
if(_state.isReference())
|
if(_state.isReference())
|
||||||
throw InvalidOp_Exception("Can not join this thread.");
|
throw InvalidOp_Exception("Can not join this thread.");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
TODO: Insert cyclic join check.
|
TODO: Insert cyclic join check.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// If the task has not completed yet, wait for completion
|
// If the task has not completed yet, wait for completion
|
||||||
if(!_state.isJoined()) {
|
if(!_state.isJoined()) {
|
||||||
|
|
||||||
// Add the current thread to the joiner list
|
// Add the current thread to the joiner list
|
||||||
ThreadImpl* impl = current();
|
ThreadImpl* impl = current();
|
||||||
_joiners.push_back(impl);
|
_joiners.push_back(impl);
|
||||||
@@ -153,49 +153,49 @@ namespace ZThread {
|
|||||||
|
|
||||||
{ // Release this ThreadImpl's lock while the joiner sleeps
|
{ // Release this ThreadImpl's lock while the joiner sleeps
|
||||||
|
|
||||||
_monitor.release();
|
_monitor.release();
|
||||||
Guard<Monitor> g3(impl->getMonitor());
|
Guard<Monitor> g3(impl->getMonitor());
|
||||||
|
|
||||||
result = impl->_monitor.wait(timeout);
|
result = impl->_monitor.wait(timeout);
|
||||||
|
|
||||||
_monitor.acquire();
|
_monitor.acquire();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the joiner list
|
// Update the joiner list
|
||||||
List::iterator i = std::find(_joiners.begin(), _joiners.end(), impl);
|
List::iterator i = std::find(_joiners.begin(), _joiners.end(), impl);
|
||||||
if(i != _joiners.end())
|
if(i != _joiners.end())
|
||||||
_joiners.erase(i);
|
_joiners.erase(i);
|
||||||
|
|
||||||
|
|
||||||
switch(result) {
|
switch(result) {
|
||||||
|
|
||||||
case Monitor::TIMEDOUT:
|
case Monitor::TIMEDOUT:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case Monitor::INTERRUPTED:
|
case Monitor::INTERRUPTED:
|
||||||
throw Interrupted_Exception();
|
throw Interrupted_Exception();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translate the priority into a pthread value, and update the thread priority.
|
* Translate the priority into a pthread value, and update the thread priority.
|
||||||
*
|
*
|
||||||
* This is not available on all platforms, and probably works differently
|
* This is not available on all platforms, and probably works differently
|
||||||
* the platforms that do support it. Pthreads does not have very portable
|
* the platforms that do support it. Pthreads does not have very portable
|
||||||
* priority support as far I am aware.
|
* priority support as far I am aware.
|
||||||
*
|
*
|
||||||
* If SCHED_OTHER is not supported priority values are still set but
|
* If SCHED_OTHER is not supported priority values are still set but
|
||||||
* dont not actually in affect anything.
|
* dont not actually in affect anything.
|
||||||
*
|
*
|
||||||
* @param prio PRIORITY value
|
* @param prio PRIORITY value
|
||||||
@@ -204,18 +204,18 @@ namespace ZThread {
|
|||||||
* @exception InvalidOp_Exception thrown by IDLE, JOINING or JOINED threads.
|
* @exception InvalidOp_Exception thrown by IDLE, JOINING or JOINED threads.
|
||||||
*/
|
*/
|
||||||
void ThreadImpl::setPriority(Priority p) {
|
void ThreadImpl::setPriority(Priority p) {
|
||||||
|
|
||||||
Guard<Monitor> g(_monitor);
|
Guard<Monitor> g(_monitor);
|
||||||
|
|
||||||
// Only set the native priority when the thread is running
|
// Only set the native priority when the thread is running
|
||||||
if(_state.isRunning())
|
if(_state.isRunning())
|
||||||
ThreadOps::setPriority(this, p);
|
ThreadOps::setPriority(this, p);
|
||||||
|
|
||||||
_priority = p;
|
_priority = p;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the state Monitor of this thread to determine if the thread
|
* Test the state Monitor of this thread to determine if the thread
|
||||||
* is an active thread created by zthreads.
|
* is an active thread created by zthreads.
|
||||||
@@ -223,13 +223,13 @@ namespace ZThread {
|
|||||||
* @return bool indicating the activity of the thread.
|
* @return bool indicating the activity of the thread.
|
||||||
*/
|
*/
|
||||||
bool ThreadImpl::isActive() {
|
bool ThreadImpl::isActive() {
|
||||||
|
|
||||||
Guard<Monitor> g(_monitor);
|
Guard<Monitor> g(_monitor);
|
||||||
return _state.isRunning();
|
return _state.isRunning();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a reference to an implmenetation that maps to the current thread.
|
* Get a reference to an implmenetation that maps to the current thread.
|
||||||
* Accomplished by checking the TLS map. This will always return a valid
|
* Accomplished by checking the TLS map. This will always return a valid
|
||||||
@@ -237,98 +237,98 @@ namespace ZThread {
|
|||||||
*
|
*
|
||||||
* @return ThreadImpl* current implementation that maps to the
|
* @return ThreadImpl* current implementation that maps to the
|
||||||
* executing thread.
|
* executing thread.
|
||||||
*/
|
*/
|
||||||
ThreadImpl* ThreadImpl::current() {
|
ThreadImpl* ThreadImpl::current() {
|
||||||
|
|
||||||
// Get the ThreadImpl previously mapped onto the executing thread.
|
// Get the ThreadImpl previously mapped onto the executing thread.
|
||||||
ThreadImpl* impl = _threadMap.get();
|
ThreadImpl* impl = _threadMap.get();
|
||||||
|
|
||||||
// Create a reference thread for any threads that have been 'discovered'
|
// Create a reference thread for any threads that have been 'discovered'
|
||||||
// because they are not created by ZThreads.
|
// because they are not created by ZThreads.
|
||||||
if(impl == 0) {
|
if(impl == 0) {
|
||||||
|
|
||||||
// Create a ThreadImpl to represent this thread.
|
// Create a ThreadImpl to represent this thread.
|
||||||
impl = new ThreadImpl();
|
impl = new ThreadImpl();
|
||||||
impl->_state.setReference();
|
impl->_state.setReference();
|
||||||
|
|
||||||
ThreadOps::activate(impl);
|
ThreadOps::activate(impl);
|
||||||
|
|
||||||
// Map a reference thread and insert it into the queue
|
// Map a reference thread and insert it into the queue
|
||||||
_threadMap.set(impl);
|
_threadMap.set(impl);
|
||||||
|
|
||||||
ThreadQueue::instance()->insertReferenceThread(impl);
|
ThreadQueue::instance()->insertReferenceThread(impl);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(impl != 0);
|
assert(impl != 0);
|
||||||
return impl;
|
return impl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make current thread sleep for the given number of milliseconds.
|
* Make current thread sleep for the given number of milliseconds.
|
||||||
* This sleep can be interrupt()ed.
|
* This sleep can be interrupt()ed.
|
||||||
*
|
*
|
||||||
* @param ms timeout for the sleep.
|
* @param ms timeout for the sleep.
|
||||||
*
|
*
|
||||||
* @post the calling thread is blocked by waiting on the internal condition
|
* @post the calling thread is blocked by waiting on the internal condition
|
||||||
* variable. This can be signaled in the monitor of an interrupt
|
* variable. This can be signaled in the monitor of an interrupt
|
||||||
*/
|
*/
|
||||||
void ThreadImpl::sleep(unsigned long ms) {
|
void ThreadImpl::sleep(unsigned long ms) {
|
||||||
|
|
||||||
// Make sleep()ing for 0 milliseconds equivalent to a yield.
|
// Make sleep()ing for 0 milliseconds equivalent to a yield.
|
||||||
if(ms == 0) {
|
if(ms == 0) {
|
||||||
|
|
||||||
yield();
|
yield();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the monitor for the current thread
|
// Get the monitor for the current thread
|
||||||
Monitor& monitor = current()->getMonitor();
|
Monitor& monitor = current()->getMonitor();
|
||||||
|
|
||||||
// Acquire that threads Monitor with a Guard
|
// Acquire that threads Monitor with a Guard
|
||||||
Guard<Monitor> g(monitor);
|
Guard<Monitor> g(monitor);
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
|
||||||
switch(monitor.wait(ms)) {
|
switch(monitor.wait(ms)) {
|
||||||
|
|
||||||
case Monitor::INTERRUPTED:
|
case Monitor::INTERRUPTED:
|
||||||
throw Interrupted_Exception();
|
throw Interrupted_Exception();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Yield the current timeslice to another thread.
|
* Yield the current timeslice to another thread.
|
||||||
* If sched_yield() is available it is used.
|
* If sched_yield() is available it is used.
|
||||||
* Otherwise, the state Monitor for this thread is used to simiulate a
|
* Otherwise, the state Monitor for this thread is used to simiulate a
|
||||||
* yield by blocking for 1 millisecond, which should give the
|
* yield by blocking for 1 millisecond, which should give the
|
||||||
* scheduler a chance to schedule another thread.
|
* scheduler a chance to schedule another thread.
|
||||||
*/
|
*/
|
||||||
void ThreadImpl::yield() {
|
void ThreadImpl::yield() {
|
||||||
|
|
||||||
// Try to yield with the native operation. If it fails, then
|
// Try to yield with the native operation. If it fails, then
|
||||||
// simulate with a short wait() on the monitor.
|
// simulate with a short wait() on the monitor.
|
||||||
if(!ThreadOps::yield()) {
|
if(!ThreadOps::yield()) {
|
||||||
|
|
||||||
// Get the monitor for the current thread
|
// Get the monitor for the current thread
|
||||||
Monitor& monitor = current()->getMonitor();
|
Monitor& monitor = current()->getMonitor();
|
||||||
|
|
||||||
// Attempt a wait().
|
// Attempt a wait().
|
||||||
Guard<Monitor> g(monitor);
|
Guard<Monitor> g(monitor);
|
||||||
monitor.wait(1);
|
monitor.wait(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadImpl::start(const Task& task) {
|
void ThreadImpl::start(const Task& task) {
|
||||||
@@ -338,9 +338,9 @@ namespace ZThread {
|
|||||||
// A Thread must be idle in order to be eligable to run a task.
|
// A Thread must be idle in order to be eligable to run a task.
|
||||||
if(!_state.isIdle())
|
if(!_state.isIdle())
|
||||||
throw InvalidOp_Exception("Thread is not idle.");
|
throw InvalidOp_Exception("Thread is not idle.");
|
||||||
|
|
||||||
_state.setRunning();
|
_state.setRunning();
|
||||||
|
|
||||||
// Spawn a new thread, blocking the parent (current) thread until
|
// Spawn a new thread, blocking the parent (current) thread until
|
||||||
// the child starts.
|
// the child starts.
|
||||||
|
|
||||||
@@ -353,14 +353,14 @@ namespace ZThread {
|
|||||||
if(!spawn(&launch)) {
|
if(!spawn(&launch)) {
|
||||||
|
|
||||||
// Return to the idle state & report the error if it doesn't work out.
|
// Return to the idle state & report the error if it doesn't work out.
|
||||||
_state.setIdle();
|
_state.setIdle();
|
||||||
throw Synchronization_Exception();
|
throw Synchronization_Exception();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait, uninterruptably, for the child's signal. The parent thread
|
// Wait, uninterruptably, for the child's signal. The parent thread
|
||||||
// still can be interrupted and killed; it just won't take effect
|
// still can be interrupted and killed; it just won't take effect
|
||||||
// until the child has started.
|
// until the child has started.
|
||||||
|
|
||||||
Guard<Monitor, DeferredInterruptionScope> g3(parent->_monitor);
|
Guard<Monitor, DeferredInterruptionScope> g3(parent->_monitor);
|
||||||
@@ -368,7 +368,7 @@ namespace ZThread {
|
|||||||
if(parent->_monitor.wait() != Monitor::SIGNALED) {
|
if(parent->_monitor.wait() != Monitor::SIGNALED) {
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,23 +378,23 @@ namespace ZThread {
|
|||||||
// Map the implementation object onto the running thread.
|
// Map the implementation object onto the running thread.
|
||||||
_threadMap.set(impl);
|
_threadMap.set(impl);
|
||||||
|
|
||||||
// Update the reference count on a ThreadImpl before the 'Thread'
|
// Update the reference count on a ThreadImpl before the 'Thread'
|
||||||
// that owns it can go out of scope (by signaling the parent)
|
// that owns it can go out of scope (by signaling the parent)
|
||||||
impl->addReference();
|
impl->addReference();
|
||||||
|
|
||||||
// Update the priority of the thread
|
// Update the priority of the thread
|
||||||
if(parent->_state.isReference())
|
if(parent->_state.isReference())
|
||||||
ThreadOps::setPriority(impl,
|
ThreadOps::setPriority(impl,
|
||||||
parent->_state.isReference() ? impl->_priority : parent->_priority);
|
parent->_state.isReference() ? impl->_priority : parent->_priority);
|
||||||
|
|
||||||
// Inherit ThreadLocal values from the parent
|
// Inherit ThreadLocal values from the parent
|
||||||
typedef ThreadLocalMap::const_iterator It;
|
typedef ThreadLocalMap::const_iterator It;
|
||||||
|
|
||||||
for(It i = parent->getThreadLocalMap().begin(); i != parent->getThreadLocalMap().end(); ++i)
|
for(It i = parent->getThreadLocalMap().begin(); i != parent->getThreadLocalMap().end(); ++i)
|
||||||
if( (i->second)->isInheritable() )
|
if( (i->second)->isInheritable() )
|
||||||
impl->getThreadLocalMap()[ i->first ] = (i->second)->clone();
|
impl->getThreadLocalMap()[ i->first ] = (i->second)->clone();
|
||||||
|
|
||||||
// Insert a user-thread mapping
|
// Insert a user-thread mapping
|
||||||
ThreadQueue::instance()->insertUserThread(impl);
|
ThreadQueue::instance()->insertUserThread(impl);
|
||||||
// Wake the parent once the thread is setup
|
// Wake the parent once the thread is setup
|
||||||
parent->_monitor.notify();
|
parent->_monitor.notify();
|
||||||
@@ -403,65 +403,65 @@ namespace ZThread {
|
|||||||
|
|
||||||
// not catch exceptions, let program terminate
|
// not catch exceptions, let program terminate
|
||||||
//try {
|
//try {
|
||||||
|
|
||||||
task->run();
|
task->run();
|
||||||
|
|
||||||
//} catch(...) {
|
//} catch(...) {
|
||||||
|
|
||||||
// Result of running a task that threw an exception.
|
// Result of running a task that threw an exception.
|
||||||
// ZTDEBUG("The task has thrown an unhandled exception\n");
|
// ZTDEBUG("The task has thrown an unhandled exception\n");
|
||||||
//assert(0); // UQ1: Go to debugger...
|
//assert(0); // UQ1: Go to debugger...
|
||||||
|
|
||||||
//}
|
//}
|
||||||
|
|
||||||
ZTDEBUG("Thread joining...\n");
|
ZTDEBUG("Thread joining...\n");
|
||||||
|
|
||||||
{ // Update the state of the thread
|
{ // Update the state of the thread
|
||||||
|
|
||||||
Guard<Monitor> g(impl->_monitor);
|
Guard<Monitor> g(impl->_monitor);
|
||||||
impl->_state.setJoined();
|
impl->_state.setJoined();
|
||||||
|
|
||||||
// Wake the joiners that will be easy to join first
|
// Wake the joiners that will be easy to join first
|
||||||
for(List::iterator i = impl->_joiners.begin(); i != impl->_joiners.end();) {
|
for(List::iterator i = impl->_joiners.begin(); i != impl->_joiners.end();) {
|
||||||
|
|
||||||
ThreadImpl* joiner = *i;
|
ThreadImpl* joiner = *i;
|
||||||
Monitor& m = joiner->getMonitor();
|
Monitor& m = joiner->getMonitor();
|
||||||
|
|
||||||
if(m.tryAcquire()) {
|
if(m.tryAcquire()) {
|
||||||
|
|
||||||
m.notify();
|
m.notify();
|
||||||
m.release();
|
m.release();
|
||||||
|
|
||||||
i = impl->_joiners.erase(i);
|
i = impl->_joiners.erase(i);
|
||||||
|
|
||||||
} else
|
} else
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wake the joiners that might take a while next
|
// Wake the joiners that might take a while next
|
||||||
for(List::iterator i = impl->_joiners.begin(); i != impl->_joiners.end(); ++i) {
|
for(List::iterator i = impl->_joiners.begin(); i != impl->_joiners.end(); ++i) {
|
||||||
|
|
||||||
ThreadImpl* joiner = *i;
|
ThreadImpl* joiner = *i;
|
||||||
Monitor& m = joiner->getMonitor();
|
Monitor& m = joiner->getMonitor();
|
||||||
|
|
||||||
m.acquire();
|
m.acquire();
|
||||||
m.notify();
|
m.notify();
|
||||||
m.release();
|
m.release();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ZTDEBUG("Thread exiting...\n");
|
ZTDEBUG("Thread exiting...\n");
|
||||||
|
|
||||||
// Insert a pending-thread mapping, allowing the resources to be reclaimed
|
// Insert a pending-thread mapping, allowing the resources to be reclaimed
|
||||||
ThreadQueue::instance()->insertPendingThread(impl);
|
ThreadQueue::instance()->insertPendingThread(impl);
|
||||||
|
|
||||||
// Cleanup ThreadLocal values
|
// Cleanup ThreadLocal values
|
||||||
impl->getThreadLocalMap().clear();
|
impl->getThreadLocalMap().clear();
|
||||||
|
|
||||||
// Update the reference count allowing it to be destroyed
|
// Update the reference count allowing it to be destroyed
|
||||||
impl->delReference();
|
impl->delReference();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,13 +27,13 @@ namespace ZThread {
|
|||||||
|
|
||||||
ThreadLocalImpl::ThreadLocalImpl() {}
|
ThreadLocalImpl::ThreadLocalImpl() {}
|
||||||
|
|
||||||
ThreadLocalImpl::~ThreadLocalImpl() {}
|
ThreadLocalImpl::~ThreadLocalImpl() {}
|
||||||
|
|
||||||
void ThreadLocalImpl::clearAll() {
|
void ThreadLocalImpl::clearAll() {
|
||||||
|
|
||||||
typedef ThreadImpl::ThreadLocalMap Map;
|
typedef ThreadImpl::ThreadLocalMap Map;
|
||||||
Map& m = ThreadImpl::current()->getThreadLocalMap();
|
Map& m = ThreadImpl::current()->getThreadLocalMap();
|
||||||
|
|
||||||
m.clear();
|
m.clear();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -42,25 +42,25 @@ namespace ZThread {
|
|||||||
|
|
||||||
typedef ThreadImpl::ThreadLocalMap Map;
|
typedef ThreadImpl::ThreadLocalMap Map;
|
||||||
Map& m = ThreadImpl::current()->getThreadLocalMap();
|
Map& m = ThreadImpl::current()->getThreadLocalMap();
|
||||||
|
|
||||||
Map::iterator i = m.find(this);
|
Map::iterator i = m.find(this);
|
||||||
if(i != m.end())
|
if(i != m.end())
|
||||||
m.erase(i);
|
m.erase(i);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadLocalImpl::ValuePtr ThreadLocalImpl::value( ValuePtr(*pfn)() ) const {
|
ThreadLocalImpl::ValuePtr ThreadLocalImpl::value( ValuePtr(*pfn)() ) const {
|
||||||
|
|
||||||
typedef ThreadImpl::ThreadLocalMap Map;
|
typedef ThreadImpl::ThreadLocalMap Map;
|
||||||
Map& m = ThreadImpl::current()->getThreadLocalMap();
|
Map& m = ThreadImpl::current()->getThreadLocalMap();
|
||||||
|
|
||||||
Map::iterator i = m.find(this);
|
Map::iterator i = m.find(this);
|
||||||
if(i != m.end())
|
if(i != m.end())
|
||||||
return i->second;
|
return i->second;
|
||||||
|
|
||||||
m[ this ] = ValuePtr( pfn() );
|
m[ this ] = ValuePtr( pfn() );
|
||||||
return m[ this ];
|
return m[ this ];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ZThread
|
} // namespace ZThread
|
||||||
|
|||||||
@@ -26,10 +26,10 @@
|
|||||||
#include "ThreadOps.h"
|
#include "ThreadOps.h"
|
||||||
|
|
||||||
// This file will select an implementation for a ThreadOps based on
|
// This file will select an implementation for a ThreadOps based on
|
||||||
// what ThreadOps.h selects. This method is for selecting the
|
// what ThreadOps.h selects. This method is for selecting the
|
||||||
// source files, to improve portability. Currently, the project is
|
// source files, to improve portability. Currently, the project is
|
||||||
// based on the autoconf tool-set, which doesn't support conditional
|
// based on the autoconf tool-set, which doesn't support conditional
|
||||||
// compilation well. Additionally, this should make the library
|
// compilation well. Additionally, this should make the library
|
||||||
// easier to port since its working around conditional compilation
|
// easier to port since its working around conditional compilation
|
||||||
// by using C++ features and people won't have to fiddle around with
|
// by using C++ features and people won't have to fiddle around with
|
||||||
// their make tool as much to compile the source
|
// their make tool as much to compile the source
|
||||||
|
|||||||
@@ -29,9 +29,9 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
namespace ZThread {
|
namespace ZThread {
|
||||||
|
|
||||||
ThreadQueue::ThreadQueue()
|
ThreadQueue::ThreadQueue()
|
||||||
: _waiter(0) {
|
: _waiter(0) {
|
||||||
|
|
||||||
ZTDEBUG("ThreadQueue created\n");
|
ZTDEBUG("ThreadQueue created\n");
|
||||||
|
|
||||||
@@ -52,36 +52,36 @@ namespace ZThread {
|
|||||||
TaskList shutdownTasks;
|
TaskList shutdownTasks;
|
||||||
|
|
||||||
{ // Check the queue to for pending user threads
|
{ // Check the queue to for pending user threads
|
||||||
|
|
||||||
Guard<FastLock> g(_lock);
|
Guard<FastLock> g(_lock);
|
||||||
|
|
||||||
waitRequired = (_waiter != (ThreadImpl*)1);
|
waitRequired = (_waiter != (ThreadImpl*)1);
|
||||||
_waiter = impl;
|
_waiter = impl;
|
||||||
|
|
||||||
threadsWaiting = !_userThreads.empty() || !_pendingThreads.empty();
|
threadsWaiting = !_userThreads.empty() || !_pendingThreads.empty();
|
||||||
|
|
||||||
//ZTDEBUG("Wait required: %d\n", waitRequired);
|
//ZTDEBUG("Wait required: %d\n", waitRequired);
|
||||||
//ZTDEBUG("Threads waiting: %d\n", threadsWaiting);
|
//ZTDEBUG("Threads waiting: %d\n", threadsWaiting);
|
||||||
|
|
||||||
// Auto-cancel any active threads at the time main() goes out of scope
|
// Auto-cancel any active threads at the time main() goes out of scope
|
||||||
// "force" a gentle exit from the executing tasks; eventually the user-
|
// "force" a gentle exit from the executing tasks; eventually the user-
|
||||||
// threads will transition into pending-threads
|
// threads will transition into pending-threads
|
||||||
pollUserThreads();
|
pollUserThreads();
|
||||||
|
|
||||||
// Remove all the tasks about to be run from the task list so an indication
|
// Remove all the tasks about to be run from the task list so an indication
|
||||||
// can be given to threads calling removeShutdownTask() too late.
|
// can be given to threads calling removeShutdownTask() too late.
|
||||||
std::remove_copy(_shutdownTasks.begin(),
|
std::remove_copy(_shutdownTasks.begin(),
|
||||||
_shutdownTasks.end(),
|
_shutdownTasks.end(),
|
||||||
std::back_inserter(shutdownTasks),
|
std::back_inserter(shutdownTasks),
|
||||||
Task((Runnable*)0));
|
Task((Runnable*)0));
|
||||||
|
|
||||||
//ZTDEBUG("Threads waiting: %d\n", threadsWaiting);
|
//ZTDEBUG("Threads waiting: %d\n", threadsWaiting);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the shutdown tasks
|
// Execute the shutdown tasks
|
||||||
for(TaskList::iterator i = shutdownTasks.begin(); i != shutdownTasks.end(); ++i) {
|
for(TaskList::iterator i = shutdownTasks.begin(); i != shutdownTasks.end(); ++i) {
|
||||||
try {
|
try {
|
||||||
(*i)->run();
|
(*i)->run();
|
||||||
} catch(...) { }
|
} catch(...) { }
|
||||||
}
|
}
|
||||||
@@ -93,20 +93,20 @@ namespace ZThread {
|
|||||||
|
|
||||||
|
|
||||||
Monitor& m = _waiter->getMonitor();
|
Monitor& m = _waiter->getMonitor();
|
||||||
|
|
||||||
// Defer interruption while this thread waits for a signal from
|
// Defer interruption while this thread waits for a signal from
|
||||||
// the last pending user thread
|
// the last pending user thread
|
||||||
Guard<Monitor, CompoundScope<DeferredInterruptionScope, LockedScope> > g(m);
|
Guard<Monitor, CompoundScope<DeferredInterruptionScope, LockedScope> > g(m);
|
||||||
//ZTDEBUG("Threads waiting: %d %d\n", _userThreads.size(), _pendingThreads.size());
|
//ZTDEBUG("Threads waiting: %d %d\n", _userThreads.size(), _pendingThreads.size());
|
||||||
|
|
||||||
// Avoid race-condition where the last threads are done with thier tasks, but
|
// 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
|
// 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
|
// 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
|
// into a pending state by the time execution reaches this point, then there is no
|
||||||
// need to wait.
|
// need to wait.
|
||||||
waitRequired = waitRequired && !(_userThreads.empty() && !_pendingThreads.empty());
|
waitRequired = waitRequired && !(_userThreads.empty() && !_pendingThreads.empty());
|
||||||
|
|
||||||
// Reference threads can't be interrupted or otherwise
|
// Reference threads can't be interrupted or otherwise
|
||||||
// manipulated. The only signal this monitor will receive
|
// manipulated. The only signal this monitor will receive
|
||||||
// at this point will be from the last pending thread.
|
// at this point will be from the last pending thread.
|
||||||
if(waitRequired && m.wait() != Monitor::SIGNALED) {
|
if(waitRequired && m.wait() != Monitor::SIGNALED) {
|
||||||
@@ -115,16 +115,16 @@ namespace ZThread {
|
|||||||
|
|
||||||
// Join those pending threads
|
// Join those pending threads
|
||||||
pollPendingThreads();
|
pollPendingThreads();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up the reference threads
|
// Clean up the reference threads
|
||||||
pollReferenceThreads();
|
pollReferenceThreads();
|
||||||
|
|
||||||
ZTDEBUG("ThreadQueue destroyed\n");
|
ZTDEBUG("ThreadQueue destroyed\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ThreadQueue::insertPendingThread(ThreadImpl* impl) {
|
void ThreadQueue::insertPendingThread(ThreadImpl* impl) {
|
||||||
ZTDEBUG("insertPendingThread()\n");
|
ZTDEBUG("insertPendingThread()\n");
|
||||||
@@ -136,7 +136,7 @@ namespace ZThread {
|
|||||||
_userThreads.erase(i);
|
_userThreads.erase(i);
|
||||||
|
|
||||||
_pendingThreads.push_back(impl);
|
_pendingThreads.push_back(impl);
|
||||||
|
|
||||||
// Wake the main thread,if its waiting, when the last pending-thread becomes available;
|
// 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
|
// Otherwise, take note that no wait for pending threads to finish is needed
|
||||||
if(_userThreads.empty())
|
if(_userThreads.empty())
|
||||||
@@ -171,7 +171,7 @@ namespace ZThread {
|
|||||||
impl->cancel(true);
|
impl->cancel(true);
|
||||||
|
|
||||||
ZTDEBUG("1 user-thread added.\n");
|
ZTDEBUG("1 user-thread added.\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -183,9 +183,9 @@ namespace ZThread {
|
|||||||
|
|
||||||
ThreadImpl* impl = (ThreadImpl*)*i;
|
ThreadImpl* impl = (ThreadImpl*)*i;
|
||||||
ThreadOps::join(impl);
|
ThreadOps::join(impl);
|
||||||
|
|
||||||
impl->delReference();
|
impl->delReference();
|
||||||
|
|
||||||
i = _pendingThreads.erase(i);
|
i = _pendingThreads.erase(i);
|
||||||
|
|
||||||
ZTDEBUG("1 pending-thread reclaimed.\n");
|
ZTDEBUG("1 pending-thread reclaimed.\n");
|
||||||
@@ -199,14 +199,14 @@ namespace ZThread {
|
|||||||
ZTDEBUG("pollReferenceThreads()\n");
|
ZTDEBUG("pollReferenceThreads()\n");
|
||||||
|
|
||||||
for(ThreadList::iterator i = _referenceThreads.begin(); i != _referenceThreads.end(); ++i) {
|
for(ThreadList::iterator i = _referenceThreads.begin(); i != _referenceThreads.end(); ++i) {
|
||||||
|
|
||||||
ThreadImpl* impl = (ThreadImpl*)*i;
|
ThreadImpl* impl = (ThreadImpl*)*i;
|
||||||
impl->delReference();
|
impl->delReference();
|
||||||
|
|
||||||
ZTDEBUG("1 reference-thread reclaimed.\n");
|
ZTDEBUG("1 reference-thread reclaimed.\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadQueue::pollUserThreads() {
|
void ThreadQueue::pollUserThreads() {
|
||||||
@@ -219,11 +219,11 @@ namespace ZThread {
|
|||||||
impl->cancel(true);
|
impl->cancel(true);
|
||||||
|
|
||||||
ZTDEBUG("1 user-thread reclaimed.\n");
|
ZTDEBUG("1 user-thread reclaimed.\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadQueue::insertShutdownTask(Task& task) {
|
void ThreadQueue::insertShutdownTask(Task& task) {
|
||||||
|
|
||||||
bool hasWaiter = false;
|
bool hasWaiter = false;
|
||||||
@@ -231,34 +231,34 @@ namespace ZThread {
|
|||||||
{
|
{
|
||||||
|
|
||||||
Guard<FastLock> g(_lock);
|
Guard<FastLock> g(_lock);
|
||||||
|
|
||||||
// Execute later when the ThreadQueue is destroyed
|
// Execute later when the ThreadQueue is destroyed
|
||||||
if( !(hasWaiter = (_waiter != 0)) ) {
|
if( !(hasWaiter = (_waiter != 0)) ) {
|
||||||
|
|
||||||
_shutdownTasks.push_back(task);
|
_shutdownTasks.push_back(task);
|
||||||
//ZTDEBUG("1 shutdown task added. %d\n", _shutdownTasks.size());
|
//ZTDEBUG("1 shutdown task added. %d\n", _shutdownTasks.size());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute immediately if things are shutting down
|
// Execute immediately if things are shutting down
|
||||||
if(hasWaiter)
|
if(hasWaiter)
|
||||||
task->run();
|
task->run();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThreadQueue::removeShutdownTask(const Task& task) {
|
bool ThreadQueue::removeShutdownTask(const Task& task) {
|
||||||
|
|
||||||
Guard<FastLock> g(_lock);
|
Guard<FastLock> g(_lock);
|
||||||
|
|
||||||
TaskList::iterator i = std::find(_shutdownTasks.begin(), _shutdownTasks.end(), task);
|
TaskList::iterator i = std::find(_shutdownTasks.begin(), _shutdownTasks.end(), task);
|
||||||
bool removed = (i != _shutdownTasks.end());
|
bool removed = (i != _shutdownTasks.end());
|
||||||
if(removed)
|
if(removed)
|
||||||
_shutdownTasks.erase(i);
|
_shutdownTasks.erase(i);
|
||||||
|
|
||||||
//ZTDEBUG("1 shutdown task removed (%d)-%d\n", removed, _shutdownTasks.size());
|
//ZTDEBUG("1 shutdown task removed (%d)-%d\n", removed, _shutdownTasks.size());
|
||||||
|
|
||||||
return removed;
|
return removed;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,11 +31,11 @@ namespace ZThread {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
//!
|
//!
|
||||||
class WaiterQueue {
|
class WaiterQueue {
|
||||||
|
|
||||||
typedef std::deque<ThreadImpl*> ThreadList;
|
typedef std::deque<ThreadImpl*> ThreadList;
|
||||||
|
|
||||||
typedef struct group_t {
|
typedef struct group_t {
|
||||||
size_t id;
|
size_t id;
|
||||||
size_t count;
|
size_t count;
|
||||||
@@ -61,14 +61,14 @@ namespace ZThread {
|
|||||||
void operator()(const Group& grp) { count += grp.count; }
|
void operator()(const Group& grp) { count += grp.count; }
|
||||||
operator size_t() { return count; }
|
operator size_t() { return count; }
|
||||||
};
|
};
|
||||||
|
|
||||||
FastMutex _lock;
|
FastMutex _lock;
|
||||||
GroupList _list;
|
GroupList _list;
|
||||||
size_t _id;
|
size_t _id;
|
||||||
size_t _generation;
|
size_t _generation;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
WaiterQueue() : _id(0), _generation(0) {
|
WaiterQueue() : _id(0), _generation(0) {
|
||||||
// At least one empty-group exists
|
// At least one empty-group exists
|
||||||
_list.push_back( Group(_id++) );
|
_list.push_back( Group(_id++) );
|
||||||
@@ -96,15 +96,15 @@ namespace ZThread {
|
|||||||
if((size_t)std::for_each(_list.begin(), _list.end(), counter()) < 1)
|
if((size_t)std::for_each(_list.begin(), _list.end(), counter()) < 1)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Update the waiter list for the active group
|
// Update the waiter list for the active group
|
||||||
_list.back().waiters.push_back(self);
|
_list.back().waiters.push_back(self);
|
||||||
size_t n = _list.back().id;
|
size_t n = _list.back().id;
|
||||||
|
|
||||||
m.acquire();
|
m.acquire();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
Guard<Lockable, UnlockedScope> g2(g1);
|
Guard<Lockable, UnlockedScope> g2(g1);
|
||||||
state = timeout == 0 ? m.wait() : m.wait(timeout);
|
state = timeout == 0 ? m.wait() : m.wait(timeout);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -135,22 +135,22 @@ namespace ZThread {
|
|||||||
throw Interrupted_Exception();
|
throw Interrupted_Exception();
|
||||||
default:
|
default:
|
||||||
throw Synchronization_Exception();
|
throw Synchronization_Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment the active group count
|
* Increment the active group count
|
||||||
*
|
*
|
||||||
* @pre at least 1 empty group exists
|
* @pre at least 1 empty group exists
|
||||||
* @post at least 1 non-empty group exists
|
* @post at least 1 non-empty group exists
|
||||||
*/
|
*/
|
||||||
std::pair<size_t, size_t> increment() {
|
std::pair<size_t, size_t> increment() {
|
||||||
|
|
||||||
Guard<FastMutex> g(_lock);
|
Guard<FastMutex> g(_lock);
|
||||||
|
|
||||||
// At least one empty-group exists
|
// At least one empty-group exists
|
||||||
assert(!_list.empty());
|
assert(!_list.empty());
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ namespace ZThread {
|
|||||||
|
|
||||||
// When the active group is being incremented, insert a new active group
|
// When the active group is being incremented, insert a new active group
|
||||||
// to replace it if there were waiting threads
|
// to replace it if there were waiting threads
|
||||||
if(i == --_list.end() && !i->waiters.empty())
|
if(i == --_list.end() && !i->waiters.empty())
|
||||||
_list.push_back(Group(_id++));
|
_list.push_back(Group(_id++));
|
||||||
|
|
||||||
// At least 1 non-empty group exists
|
// At least 1 non-empty group exists
|
||||||
@@ -178,13 +178,13 @@ namespace ZThread {
|
|||||||
return std::make_pair(n, _generation);
|
return std::make_pair(n, _generation);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrease the count for the group with the given id.
|
* Decrease the count for the group with the given id.
|
||||||
*
|
*
|
||||||
* @param n group id
|
* @param n group id
|
||||||
*
|
*
|
||||||
* @pre At least 1 non-empty group exists
|
* @pre At least 1 non-empty group exists
|
||||||
* @post At least 1 empty group exists
|
* @post At least 1 empty group exists
|
||||||
*/
|
*/
|
||||||
@@ -198,7 +198,7 @@ namespace ZThread {
|
|||||||
// Find the requested group
|
// Find the requested group
|
||||||
GroupList::iterator i = std::find_if(_list.begin(), _list.end(), by_id(n));
|
GroupList::iterator i = std::find_if(_list.begin(), _list.end(), by_id(n));
|
||||||
if(i == _list.end()) {
|
if(i == _list.end()) {
|
||||||
|
|
||||||
// A group should never have been removed until
|
// A group should never have been removed until
|
||||||
// the final task in that group completed
|
// the final task in that group completed
|
||||||
assert(0);
|
assert(0);
|
||||||
@@ -207,11 +207,11 @@ namespace ZThread {
|
|||||||
|
|
||||||
// Decrease the count for tasks in this group,
|
// Decrease the count for tasks in this group,
|
||||||
if(--i->count == 0 && i == _list.begin()) {
|
if(--i->count == 0 && i == _list.begin()) {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
||||||
// When the first group completes, wake all waiters for every
|
// When the first group completes, wake all waiters for every
|
||||||
// group, starting from the first until a group that is not
|
// group, starting from the first until a group that is not
|
||||||
// complete is reached
|
// complete is reached
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -219,29 +219,29 @@ namespace ZThread {
|
|||||||
if(i == --_list.end() && i->waiters.empty())
|
if(i == --_list.end() && i->waiters.empty())
|
||||||
break;
|
break;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if( awaken(*i) ) {
|
if( awaken(*i) ) {
|
||||||
|
|
||||||
// If all waiters were awakened, remove the group
|
// If all waiters were awakened, remove the group
|
||||||
i = _list.erase(i);
|
i = _list.erase(i);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
// Otherwise, unlock and yield allowing the waiter
|
// Otherwise, unlock and yield allowing the waiter
|
||||||
// lists to be updated if other threads are busy
|
// lists to be updated if other threads are busy
|
||||||
Guard<FastLock, UnlockedScope> g2(g1);
|
Guard<FastLock, UnlockedScope> g2(g1);
|
||||||
ThreadImpl::yield();
|
ThreadImpl::yield();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i = _list.begin();
|
i = _list.begin();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} while(i != _list.end() && i->count == 0);
|
} while(i != _list.end() && i->count == 0);
|
||||||
|
|
||||||
// Ensure that an active group exists
|
// Ensure that an active group exists
|
||||||
if(_list.empty())
|
if(_list.empty())
|
||||||
_list.push_back( Group(++_id) );
|
_list.push_back( Group(++_id) );
|
||||||
@@ -250,7 +250,7 @@ namespace ZThread {
|
|||||||
|
|
||||||
// At least one group exists
|
// At least one group exists
|
||||||
assert(!_list.empty());
|
assert(!_list.empty());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -261,74 +261,74 @@ namespace ZThread {
|
|||||||
return next ? _generation++ : _generation;
|
return next ? _generation++ : _generation;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Awaken all the waiters remaining in the given group
|
* Awaken all the waiters remaining in the given group
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - true if all the waiting threads were successfully awakened.
|
* - true if all the waiting threads were successfully awakened.
|
||||||
* - false if there were one or more threads that could not be awakened.
|
* - false if there were one or more threads that could not be awakened.
|
||||||
*/
|
*/
|
||||||
bool awaken(Group& grp) {
|
bool awaken(Group& grp) {
|
||||||
|
|
||||||
// Go through the waiter list in the given group;
|
// Go through the waiter list in the given group;
|
||||||
for(ThreadList::iterator i = grp.waiters.begin(); i != grp.waiters.end();) {
|
for(ThreadList::iterator i = grp.waiters.begin(); i != grp.waiters.end();) {
|
||||||
|
|
||||||
ThreadImpl* impl = *i;
|
ThreadImpl* impl = *i;
|
||||||
Monitor& m = impl->getMonitor();
|
Monitor& m = impl->getMonitor();
|
||||||
|
|
||||||
// Try the monitor lock, if it cant be locked skip to the next waiter
|
// Try the monitor lock, if it cant be locked skip to the next waiter
|
||||||
if(m.tryAcquire()) {
|
if(m.tryAcquire()) {
|
||||||
|
|
||||||
// Notify the monitor & remove from the waiter list so time isn't
|
// Notify the monitor & remove from the waiter list so time isn't
|
||||||
// wasted checking it again.
|
// wasted checking it again.
|
||||||
i = grp.waiters.erase(i);
|
i = grp.waiters.erase(i);
|
||||||
|
|
||||||
// Try to wake the waiter, it doesn't matter if this is successful
|
// 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).
|
// or not (only fails when the monitor is already going to stop waiting).
|
||||||
m.notify();
|
m.notify();
|
||||||
m.release();
|
m.release();
|
||||||
|
|
||||||
} else ++i;
|
} else ++i;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return grp.waiters.empty();
|
return grp.waiters.empty();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Synchronization point for the Executor
|
//! Synchronization point for the Executor
|
||||||
class ExecutorImpl {
|
class ExecutorImpl {
|
||||||
|
|
||||||
typedef std::deque<ThreadImpl*> ThreadList;
|
typedef std::deque<ThreadImpl*> ThreadList;
|
||||||
|
|
||||||
bool _canceled;
|
bool _canceled;
|
||||||
FastMutex _lock;
|
FastMutex _lock;
|
||||||
|
|
||||||
//! Worker threads
|
//! Worker threads
|
||||||
ThreadList _threads;
|
ThreadList _threads;
|
||||||
|
|
||||||
WaiterQueue _queue;
|
WaiterQueue _queue;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ExecutorImpl() : _canceled(false) {}
|
ExecutorImpl() : _canceled(false) {}
|
||||||
|
|
||||||
WaiterQueue& getWaiterQueue() {
|
WaiterQueue& getWaiterQueue() {
|
||||||
return _queue;
|
return _queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerThread(size_t generation) {
|
void registerThread(size_t generation) {
|
||||||
|
|
||||||
// Interrupt slow starting threads
|
// Interrupt slow starting threads
|
||||||
if(getWaiterQueue().generation() != generation)
|
if(getWaiterQueue().generation() != generation)
|
||||||
ThreadImpl::current()->interrupt();
|
ThreadImpl::current()->interrupt();
|
||||||
|
|
||||||
// Enqueue for possible future interrupt()
|
// Enqueue for possible future interrupt()
|
||||||
else {
|
else {
|
||||||
|
|
||||||
Guard<FastMutex> g(_lock);
|
Guard<FastMutex> g(_lock);
|
||||||
@@ -339,7 +339,7 @@ namespace ZThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void unregisterThread() {
|
void unregisterThread() {
|
||||||
|
|
||||||
Guard<FastMutex> g(_lock);
|
Guard<FastMutex> g(_lock);
|
||||||
std::remove(_threads.begin(), _threads.end(), ThreadImpl::current() );
|
std::remove(_threads.begin(), _threads.end(), ThreadImpl::current() );
|
||||||
|
|
||||||
@@ -369,11 +369,11 @@ namespace ZThread {
|
|||||||
// Interrupt all the registered threads
|
// Interrupt all the registered threads
|
||||||
for(ThreadList::iterator i = _threads.begin(); i != _threads.end(); ++i)
|
for(ThreadList::iterator i = _threads.begin(); i != _threads.end(); ++i)
|
||||||
(*i)->interrupt();
|
(*i)->interrupt();
|
||||||
|
|
||||||
// Bump the generation up, ensuring slow starting threads get this interrupt
|
// Bump the generation up, ensuring slow starting threads get this interrupt
|
||||||
getWaiterQueue().generation( true );
|
getWaiterQueue().generation( true );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}; /* ExecutorImpl */
|
}; /* ExecutorImpl */
|
||||||
|
|
||||||
@@ -392,7 +392,7 @@ namespace ZThread {
|
|||||||
: _impl(impl), _task(task) {
|
: _impl(impl), _task(task) {
|
||||||
|
|
||||||
std::pair<size_t, size_t> pr( _impl->getWaiterQueue().increment() );
|
std::pair<size_t, size_t> pr( _impl->getWaiterQueue().increment() );
|
||||||
|
|
||||||
_group = pr.first;
|
_group = pr.first;
|
||||||
_generation = pr.second;
|
_generation = pr.second;
|
||||||
|
|
||||||
@@ -405,20 +405,20 @@ namespace ZThread {
|
|||||||
size_t generation() const {
|
size_t generation() const {
|
||||||
return _generation;
|
return _generation;
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() {
|
void run() {
|
||||||
|
|
||||||
// Register this thread once its begun; the generation is used to ensure
|
// Register this thread once its begun; the generation is used to ensure
|
||||||
// threads that are slow starting are properly interrupted
|
// threads that are slow starting are properly interrupted
|
||||||
|
|
||||||
_impl->registerThread( generation() );
|
_impl->registerThread( generation() );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_task->run();
|
_task->run();
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
/* consume the exceptions the work propogates */
|
/* consume the exceptions the work propogates */
|
||||||
}
|
}
|
||||||
|
|
||||||
_impl->getWaiterQueue().decrement( group() );
|
_impl->getWaiterQueue().decrement( group() );
|
||||||
|
|
||||||
// Unregister this thread
|
// Unregister this thread
|
||||||
@@ -434,30 +434,30 @@ namespace ZThread {
|
|||||||
ThreadedExecutor::ThreadedExecutor() : _impl(new ExecutorImpl) {}
|
ThreadedExecutor::ThreadedExecutor() : _impl(new ExecutorImpl) {}
|
||||||
|
|
||||||
ThreadedExecutor::~ThreadedExecutor() {}
|
ThreadedExecutor::~ThreadedExecutor() {}
|
||||||
|
|
||||||
void ThreadedExecutor::execute(const Task& task) {
|
void ThreadedExecutor::execute(const Task& task) {
|
||||||
|
|
||||||
Thread t( new Worker(_impl, task) );
|
Thread t( new Worker(_impl, task) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadedExecutor::interrupt() {
|
void ThreadedExecutor::interrupt() {
|
||||||
_impl->interrupt();
|
_impl->interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadedExecutor::cancel() {
|
void ThreadedExecutor::cancel() {
|
||||||
_impl->cancel();
|
_impl->cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThreadedExecutor::isCanceled() {
|
bool ThreadedExecutor::isCanceled() {
|
||||||
return _impl->isCanceled();
|
return _impl->isCanceled();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadedExecutor::wait() {
|
void ThreadedExecutor::wait() {
|
||||||
_impl->getWaiterQueue().wait(0);
|
_impl->getWaiterQueue().wait(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThreadedExecutor::wait(unsigned long timeout) {
|
bool ThreadedExecutor::wait(unsigned long timeout) {
|
||||||
return _impl->getWaiterQueue().wait(timeout == 0 ? 1 : timeout);
|
return _impl->getWaiterQueue().wait(timeout == 0 ? 1 : timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
using namespace ZThread;
|
using namespace ZThread;
|
||||||
|
|
||||||
Time::Time() {
|
Time::Time() {
|
||||||
|
|
||||||
// System startup time
|
// System startup time
|
||||||
static TimeStrategy firstHelper;
|
static TimeStrategy firstHelper;
|
||||||
TimeStrategy helper;
|
TimeStrategy helper;
|
||||||
@@ -37,7 +37,7 @@ Time::Time() {
|
|||||||
|
|
||||||
now -= then;
|
now -= then;
|
||||||
|
|
||||||
_seconds = now.seconds();
|
_seconds = now.seconds();
|
||||||
_milliseconds = now.milliseconds();
|
_milliseconds = now.milliseconds();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ typedef struct atomic_count_t {
|
|||||||
AtomicCount::AtomicCount() {
|
AtomicCount::AtomicCount() {
|
||||||
|
|
||||||
_value = reinterpret_cast<void*>(new ATOMIC_COUNT);
|
_value = reinterpret_cast<void*>(new ATOMIC_COUNT);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomicCount::~AtomicCount() {
|
AtomicCount::~AtomicCount() {
|
||||||
@@ -55,19 +55,19 @@ AtomicCount::~AtomicCount() {
|
|||||||
delete reinterpret_cast<ATOMIC_COUNT*>(_value);
|
delete reinterpret_cast<ATOMIC_COUNT*>(_value);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtomicCount::increment() {
|
void AtomicCount::increment() {
|
||||||
|
|
||||||
atomic_inc(&reinterpret_cast<ATOMIC_COUNT*>(_value)->count);
|
atomic_inc(&reinterpret_cast<ATOMIC_COUNT*>(_value)->count);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AtomicCount::decrement() {
|
bool AtomicCount::decrement() {
|
||||||
|
|
||||||
return atomic_dec_and_test(&reinterpret_cast<ATOMIC_COUNT*>(_value)->count);
|
return atomic_dec_and_test(&reinterpret_cast<ATOMIC_COUNT*>(_value)->count);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __ZTATOMICCOUNTIMPL_H__
|
#endif // __ZTATOMICCOUNTIMPL_H__
|
||||||
|
|||||||
@@ -29,20 +29,20 @@
|
|||||||
using namespace ZThread;
|
using namespace ZThread;
|
||||||
|
|
||||||
Monitor::Monitor() : _owner(0), _waiting(false), _pending(false) {
|
Monitor::Monitor() : _owner(0), _waiting(false), _pending(false) {
|
||||||
|
|
||||||
if(MPCreateSemaphore(1, 0, &_sema) != noErr) {
|
if(MPCreateSemaphore(1, 0, &_sema) != noErr) {
|
||||||
assert(0);
|
assert(0);
|
||||||
throw Initialization_Exception();
|
throw Initialization_Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Monitor::~Monitor() throw() {
|
Monitor::~Monitor() throw() {
|
||||||
|
|
||||||
assert(!_waiting);
|
assert(!_waiting);
|
||||||
|
|
||||||
OSStatus status = MPDeleteSemaphore(_sema);
|
OSStatus status = MPDeleteSemaphore(_sema);
|
||||||
if(status != noErr)
|
if(status != noErr)
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -53,9 +53,9 @@ Monitor::STATE Monitor::wait(unsigned long timeout) {
|
|||||||
// 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
|
// 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;
|
AbsoluteTime tTarget;
|
||||||
Duration waitDuration =
|
Duration waitDuration =
|
||||||
(timeout == 0) ? kDurationForever : (kDurationMillisecond * timeout);
|
(timeout == 0) ? kDurationForever : (kDurationMillisecond * timeout);
|
||||||
|
|
||||||
if(waitDuration != kDurationForever)
|
if(waitDuration != kDurationForever)
|
||||||
tTarget = AddDurationToAbsolute(waitDuration, UpTime());
|
tTarget = AddDurationToAbsolute(waitDuration, UpTime());
|
||||||
|
|
||||||
@@ -66,13 +66,13 @@ Monitor::STATE Monitor::wait(unsigned long timeout) {
|
|||||||
_owner = MPCurrentTaskID();
|
_owner = MPCurrentTaskID();
|
||||||
|
|
||||||
STATE state(INVALID);
|
STATE state(INVALID);
|
||||||
|
|
||||||
// Serialize access to the state of the Monitor
|
// Serialize access to the state of the Monitor
|
||||||
// and test the state to determine if a wait is needed.
|
// and test the state to determine if a wait is needed.
|
||||||
_waitLock.acquire();
|
_waitLock.acquire();
|
||||||
|
|
||||||
if(pending(ANYTHING)) {
|
if(pending(ANYTHING)) {
|
||||||
|
|
||||||
// Return without waiting when possible
|
// Return without waiting when possible
|
||||||
state = next();
|
state = next();
|
||||||
|
|
||||||
@@ -80,57 +80,57 @@ Monitor::STATE Monitor::wait(unsigned long timeout) {
|
|||||||
return state;
|
return state;
|
||||||
|
|
||||||
}
|
}
|
||||||
// Unlock the external lock if a wait() is probably needed.
|
// Unlock the external lock if a wait() is probably needed.
|
||||||
// Access to the state is still serial.
|
// Access to the state is still serial.
|
||||||
_lock.release();
|
_lock.release();
|
||||||
|
|
||||||
// Wait for a transition in the state that is of interest, this
|
// Wait for a transition in the state that is of interest, this
|
||||||
// allows waits to exclude certain flags (e.g. INTERRUPTED)
|
// allows waits to exclude certain flags (e.g. INTERRUPTED)
|
||||||
// for a single wait() w/o actually discarding those flags -
|
// for a single wait() w/o actually discarding those flags -
|
||||||
// they will remain set until a wait interested in those flags
|
// they will remain set until a wait interested in those flags
|
||||||
// occurs.
|
// occurs.
|
||||||
|
|
||||||
// Wait, ignoring signals
|
// Wait, ignoring signals
|
||||||
_waiting = true;
|
_waiting = true;
|
||||||
|
|
||||||
_waitLock.release();
|
_waitLock.release();
|
||||||
|
|
||||||
// Update the wait time
|
// Update the wait time
|
||||||
if(waitDuration != kDurationForever)
|
if(waitDuration != kDurationForever)
|
||||||
waitDuration = AbsoluteDeltaToDuration(tTarget, UpTime());
|
waitDuration = AbsoluteDeltaToDuration(tTarget, UpTime());
|
||||||
|
|
||||||
// Sleep until a signal arrives or a timeout occurs
|
// Sleep until a signal arrives or a timeout occurs
|
||||||
OSStatus status = MPWaitOnSemaphore(_sema, waitDuration);
|
OSStatus status = MPWaitOnSemaphore(_sema, waitDuration);
|
||||||
|
|
||||||
// Reacquire serialized access to the state
|
// Reacquire serialized access to the state
|
||||||
_waitLock.acquire();
|
_waitLock.acquire();
|
||||||
|
|
||||||
// Awaken only when the event is set or the timeout expired
|
// Awaken only when the event is set or the timeout expired
|
||||||
assert(status == kMPTimeoutErr || status == noErr);
|
assert(status == kMPTimeoutErr || status == noErr);
|
||||||
|
|
||||||
if(status == kMPTimeoutErr)
|
if(status == kMPTimeoutErr)
|
||||||
push(TIMEDOUT);
|
push(TIMEDOUT);
|
||||||
|
|
||||||
// Get the next available STATE
|
// Get the next available STATE
|
||||||
state = next();
|
state = next();
|
||||||
|
|
||||||
_waiting = false;
|
_waiting = false;
|
||||||
|
|
||||||
// Its possible that a timeout will wake the thread before a signal is
|
// 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
|
// delivered. Absorb that leftover so the next wait isn't aborted right away
|
||||||
if(status == kMPTimeoutErr && _pending) {
|
if(status == kMPTimeoutErr && _pending) {
|
||||||
|
|
||||||
status = MPWaitOnSemaphore(_sema, kDurationForever);
|
status = MPWaitOnSemaphore(_sema, kDurationForever);
|
||||||
assert(status == noErr);
|
assert(status == noErr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_pending = false;
|
_pending = false;
|
||||||
|
|
||||||
// Acquire the internal lock & release the external lock
|
// Acquire the internal lock & release the external lock
|
||||||
_waitLock.release();
|
_waitLock.release();
|
||||||
|
|
||||||
// Reaquire the external lock, keep from deadlocking threads calling
|
// Reaquire the external lock, keep from deadlocking threads calling
|
||||||
// notify(), interrupt(), etc.
|
// notify(), interrupt(), etc.
|
||||||
_lock.acquire();
|
_lock.acquire();
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ bool Monitor::interrupt() {
|
|||||||
|
|
||||||
// Serialize access to the state
|
// Serialize access to the state
|
||||||
_waitLock.acquire();
|
_waitLock.acquire();
|
||||||
|
|
||||||
bool wasInterruptable = !pending(INTERRUPTED);
|
bool wasInterruptable = !pending(INTERRUPTED);
|
||||||
bool hasWaiter = false;
|
bool hasWaiter = false;
|
||||||
|
|
||||||
@@ -151,7 +151,7 @@ bool Monitor::interrupt() {
|
|||||||
if(wasInterruptable) {
|
if(wasInterruptable) {
|
||||||
|
|
||||||
push(INTERRUPTED);
|
push(INTERRUPTED);
|
||||||
|
|
||||||
wasInterruptable = false;
|
wasInterruptable = false;
|
||||||
|
|
||||||
if(_waiting && !_pending) {
|
if(_waiting && !_pending) {
|
||||||
@@ -159,7 +159,7 @@ bool Monitor::interrupt() {
|
|||||||
_pending = true;
|
_pending = true;
|
||||||
hasWaiter = true;
|
hasWaiter = true;
|
||||||
|
|
||||||
} else
|
} else
|
||||||
wasInterruptable = !(_owner == MPCurrentTaskID());
|
wasInterruptable = !(_owner == MPCurrentTaskID());
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -180,7 +180,7 @@ bool Monitor::isInterrupted() {
|
|||||||
|
|
||||||
bool wasInterrupted = pending(INTERRUPTED);
|
bool wasInterrupted = pending(INTERRUPTED);
|
||||||
clear(INTERRUPTED);
|
clear(INTERRUPTED);
|
||||||
|
|
||||||
_waitLock.release();
|
_waitLock.release();
|
||||||
|
|
||||||
return wasInterrupted;
|
return wasInterrupted;
|
||||||
@@ -227,12 +227,12 @@ bool Monitor::cancel() {
|
|||||||
|
|
||||||
bool wasInterrupted = !pending(INTERRUPTED);
|
bool wasInterrupted = !pending(INTERRUPTED);
|
||||||
bool hasWaiter = false;
|
bool hasWaiter = false;
|
||||||
|
|
||||||
push(CANCELED);
|
push(CANCELED);
|
||||||
|
|
||||||
// Update the state if theres a waiter
|
// Update the state if theres a waiter
|
||||||
if(wasInterrupted) {
|
if(wasInterrupted) {
|
||||||
|
|
||||||
push(INTERRUPTED);
|
push(INTERRUPTED);
|
||||||
|
|
||||||
if(_waiting && !_pending) {
|
if(_waiting && !_pending) {
|
||||||
@@ -243,9 +243,9 @@ bool Monitor::cancel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_waitLock.release();
|
_waitLock.release();
|
||||||
|
|
||||||
if(hasWaiter && !masked(Monitor::INTERRUPTED))
|
if(hasWaiter && !masked(Monitor::INTERRUPTED))
|
||||||
MPSignalSemaphore(_sema);
|
MPSignalSemaphore(_sema);
|
||||||
|
|
||||||
@@ -254,12 +254,12 @@ bool Monitor::cancel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Monitor::isCanceled() {
|
bool Monitor::isCanceled() {
|
||||||
|
|
||||||
// Serialize access to the state
|
// Serialize access to the state
|
||||||
_waitLock.acquire();
|
_waitLock.acquire();
|
||||||
|
|
||||||
bool wasCanceled = Status::examine(CANCELED);
|
bool wasCanceled = Status::examine(CANCELED);
|
||||||
|
|
||||||
if(_owner == MPCurrentTaskID())
|
if(_owner == MPCurrentTaskID())
|
||||||
clear(INTERRUPTED);
|
clear(INTERRUPTED);
|
||||||
|
|
||||||
|
|||||||
@@ -27,25 +27,25 @@
|
|||||||
|
|
||||||
namespace ZThread {
|
namespace ZThread {
|
||||||
|
|
||||||
const ThreadOps ThreadOps::INVALID(0);
|
const ThreadOps ThreadOps::INVALID(0);
|
||||||
|
|
||||||
|
ThreadOps::ThreadOps() : _queue(0), _tid(0) {
|
||||||
|
|
||||||
ThreadOps::ThreadOps() : _queue(0), _tid(0) {
|
|
||||||
|
|
||||||
if(MPCreateQueue(&_queue) != noErr)
|
if(MPCreateQueue(&_queue) != noErr)
|
||||||
throw Initialization_Exception();
|
throw Initialization_Exception();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadOps::~ThreadOps() throw() {
|
ThreadOps::~ThreadOps() throw() {
|
||||||
|
|
||||||
if(_queue != 0) {
|
if(_queue != 0) {
|
||||||
|
|
||||||
OSStatus status = MPDeleteQueue(_queue);
|
OSStatus status = MPDeleteQueue(_queue);
|
||||||
if(status != noErr)
|
if(status != noErr)
|
||||||
assert(0);
|
assert(0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThreadOps::join(ThreadOps* ops) {
|
bool ThreadOps::join(ThreadOps* ops) {
|
||||||
@@ -56,7 +56,7 @@ bool ThreadOps::join(ThreadOps* ops) {
|
|||||||
OSStatus status = MPWaitOnQueue(ops->_queue, NULL, NULL, NULL, kDurationForever);
|
OSStatus status = MPWaitOnQueue(ops->_queue, NULL, NULL, NULL, kDurationForever);
|
||||||
|
|
||||||
return status == noErr;
|
return status == noErr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThreadOps::yield() {
|
bool ThreadOps::yield() {
|
||||||
@@ -91,13 +91,13 @@ OSStatus ThreadOps::_dispatch(void *arg) {
|
|||||||
|
|
||||||
// Run the task from the correct context
|
// Run the task from the correct context
|
||||||
task->run();
|
task->run();
|
||||||
|
|
||||||
// Exit the thread
|
// Exit the thread
|
||||||
MPExit(noErr);
|
MPExit(noErr);
|
||||||
return noErr;
|
return noErr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ZThread
|
} // namespace ZThread
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,19 +31,19 @@
|
|||||||
namespace ZThread {
|
namespace ZThread {
|
||||||
|
|
||||||
Monitor::Monitor() : _owner(0), _waiting(false) {
|
Monitor::Monitor() : _owner(0), _waiting(false) {
|
||||||
|
|
||||||
pthread_cond_init(&_waitCond, 0);
|
pthread_cond_init(&_waitCond, 0);
|
||||||
pthread_mutex_init(&_waitLock, 0);
|
pthread_mutex_init(&_waitLock, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Monitor::~Monitor() {
|
Monitor::~Monitor() {
|
||||||
|
|
||||||
assert(!_waiting);
|
assert(!_waiting);
|
||||||
|
|
||||||
pthread_cond_destroy(&_waitCond);
|
pthread_cond_destroy(&_waitCond);
|
||||||
pthread_mutex_destroy(&_waitLock);
|
pthread_mutex_destroy(&_waitLock);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Monitor::STATE Monitor::wait(unsigned long ms) {
|
Monitor::STATE Monitor::wait(unsigned long ms) {
|
||||||
@@ -55,14 +55,14 @@ Monitor::STATE Monitor::wait(unsigned long ms) {
|
|||||||
_owner = pthread_self();
|
_owner = pthread_self();
|
||||||
|
|
||||||
STATE state(INVALID);
|
STATE state(INVALID);
|
||||||
|
|
||||||
// Serialize access to the state of the Monitor
|
// Serialize access to the state of the Monitor
|
||||||
// and test the state to determine if a wait is needed.
|
// and test the state to determine if a wait is needed.
|
||||||
|
|
||||||
pthread_mutex_lock(&_waitLock);
|
pthread_mutex_lock(&_waitLock);
|
||||||
|
|
||||||
if(pending(ANYTHING)) {
|
if(pending(ANYTHING)) {
|
||||||
|
|
||||||
// Return without waiting when possible
|
// Return without waiting when possible
|
||||||
state = next();
|
state = next();
|
||||||
|
|
||||||
@@ -70,13 +70,13 @@ Monitor::STATE Monitor::wait(unsigned long ms) {
|
|||||||
return state;
|
return state;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlock the external lock if a wait() is probably needed.
|
// Unlock the external lock if a wait() is probably needed.
|
||||||
// Access to the state is still serial.
|
// Access to the state is still serial.
|
||||||
_lock.release();
|
_lock.release();
|
||||||
|
|
||||||
// Wait for a transition in the state that is of interest, this
|
// Wait for a transition in the state that is of interest, this
|
||||||
// allows waits to exclude certain flags (e.g. INTERRUPTED)
|
// allows waits to exclude certain flags (e.g. INTERRUPTED)
|
||||||
// for a single wait() w/o actually discarding those flags -
|
// for a single wait() w/o actually discarding those flags -
|
||||||
// they will remain set until a wait interested in those flags
|
// they will remain set until a wait interested in those flags
|
||||||
// occurs.
|
// occurs.
|
||||||
@@ -85,20 +85,20 @@ Monitor::STATE Monitor::wait(unsigned long ms) {
|
|||||||
// Wait, ignoring signals
|
// Wait, ignoring signals
|
||||||
_waiting = true;
|
_waiting = true;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
if(ms == 0) { // Wait forever
|
if(ms == 0) { // Wait forever
|
||||||
|
|
||||||
do { // ignore signals unless the state is interesting
|
do { // ignore signals unless the state is interesting
|
||||||
status = pthread_cond_wait(&_waitCond, &_waitLock);
|
status = pthread_cond_wait(&_waitCond, &_waitLock);
|
||||||
} while(status == EINTR && !pending(ANYTHING));
|
} while(status == EINTR && !pending(ANYTHING));
|
||||||
|
|
||||||
// Akwaken only when a state is pending
|
// Akwaken only when a state is pending
|
||||||
assert(status == 0);
|
assert(status == 0);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Find the target time
|
// Find the target time
|
||||||
TimeStrategy t;
|
TimeStrategy t;
|
||||||
|
|
||||||
ms += t.milliseconds();
|
ms += t.milliseconds();
|
||||||
|
|
||||||
@@ -106,34 +106,34 @@ Monitor::STATE Monitor::wait(unsigned long ms) {
|
|||||||
ms %= 1000;
|
ms %= 1000;
|
||||||
|
|
||||||
// Convert to a timespec
|
// Convert to a timespec
|
||||||
struct ::timespec timeout;
|
struct ::timespec timeout;
|
||||||
|
|
||||||
timeout.tv_sec = s;
|
timeout.tv_sec = s;
|
||||||
timeout.tv_nsec = ms*1000000;
|
timeout.tv_nsec = ms*1000000;
|
||||||
|
|
||||||
// Wait ignoring signals until the state is interesting
|
// Wait ignoring signals until the state is interesting
|
||||||
do {
|
do {
|
||||||
|
|
||||||
// When a timeout occurs, update the state to reflect that.
|
// When a timeout occurs, update the state to reflect that.
|
||||||
status = pthread_cond_timedwait(&_waitCond, &_waitLock, &timeout);
|
status = pthread_cond_timedwait(&_waitCond, &_waitLock, &timeout);
|
||||||
|
|
||||||
} while(status == EINTR && !pending(ANYTHING));
|
} while(status == EINTR && !pending(ANYTHING));
|
||||||
|
|
||||||
// Akwaken only when a state is pending or when the timeout expired
|
// Akwaken only when a state is pending or when the timeout expired
|
||||||
assert(status == 0 || status == ETIMEDOUT);
|
assert(status == 0 || status == ETIMEDOUT);
|
||||||
|
|
||||||
if(status == ETIMEDOUT)
|
if(status == ETIMEDOUT)
|
||||||
push(TIMEDOUT);
|
push(TIMEDOUT);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the next available STATE
|
// Get the next available STATE
|
||||||
state = next();
|
state = next();
|
||||||
_waiting = false;
|
_waiting = false;
|
||||||
|
|
||||||
pthread_mutex_unlock(&_waitLock);
|
pthread_mutex_unlock(&_waitLock);
|
||||||
|
|
||||||
// Reaquire the external lock, keep from deadlocking threads calling
|
// Reaquire the external lock, keep from deadlocking threads calling
|
||||||
// notify(), interrupt(), etc.
|
// notify(), interrupt(), etc.
|
||||||
|
|
||||||
_lock.acquire();
|
_lock.acquire();
|
||||||
@@ -147,17 +147,17 @@ bool Monitor::interrupt() {
|
|||||||
|
|
||||||
// Serialize access to the state
|
// Serialize access to the state
|
||||||
pthread_mutex_lock(&_waitLock);
|
pthread_mutex_lock(&_waitLock);
|
||||||
|
|
||||||
bool wasInterruptable = !pending(INTERRUPTED);
|
bool wasInterruptable = !pending(INTERRUPTED);
|
||||||
bool hadWaiter = _waiting;
|
bool hadWaiter = _waiting;
|
||||||
|
|
||||||
if(wasInterruptable) {
|
if(wasInterruptable) {
|
||||||
|
|
||||||
// Update the state & wake the waiter if there is one
|
// Update the state & wake the waiter if there is one
|
||||||
push(INTERRUPTED);
|
push(INTERRUPTED);
|
||||||
|
|
||||||
wasInterruptable = false;
|
wasInterruptable = false;
|
||||||
|
|
||||||
if(hadWaiter && !masked(Monitor::INTERRUPTED))
|
if(hadWaiter && !masked(Monitor::INTERRUPTED))
|
||||||
pthread_cond_signal(&_waitCond);
|
pthread_cond_signal(&_waitCond);
|
||||||
else
|
else
|
||||||
@@ -180,7 +180,7 @@ bool Monitor::isInterrupted() {
|
|||||||
bool wasInterrupted = pending(INTERRUPTED);
|
bool wasInterrupted = pending(INTERRUPTED);
|
||||||
|
|
||||||
clear(INTERRUPTED);
|
clear(INTERRUPTED);
|
||||||
|
|
||||||
pthread_mutex_unlock(&_waitLock);
|
pthread_mutex_unlock(&_waitLock);
|
||||||
|
|
||||||
return wasInterrupted;
|
return wasInterrupted;
|
||||||
@@ -193,7 +193,7 @@ bool Monitor::isCanceled() {
|
|||||||
pthread_mutex_lock(&_waitLock);
|
pthread_mutex_lock(&_waitLock);
|
||||||
|
|
||||||
bool wasCanceled = examine(CANCELED);
|
bool wasCanceled = examine(CANCELED);
|
||||||
|
|
||||||
if(pthread_equal(_owner, pthread_self()))
|
if(pthread_equal(_owner, pthread_self()))
|
||||||
clear(INTERRUPTED);
|
clear(INTERRUPTED);
|
||||||
|
|
||||||
@@ -210,17 +210,17 @@ bool Monitor::cancel() {
|
|||||||
|
|
||||||
bool wasInterrupted = !pending(INTERRUPTED);
|
bool wasInterrupted = !pending(INTERRUPTED);
|
||||||
bool hadWaiter = _waiting;
|
bool hadWaiter = _waiting;
|
||||||
|
|
||||||
push(CANCELED);
|
push(CANCELED);
|
||||||
|
|
||||||
if(wasInterrupted) {
|
if(wasInterrupted) {
|
||||||
|
|
||||||
// Update the state & wake the waiter if there is one
|
// Update the state & wake the waiter if there is one
|
||||||
push(INTERRUPTED);
|
push(INTERRUPTED);
|
||||||
|
|
||||||
if(hadWaiter && !masked(Monitor::INTERRUPTED))
|
if(hadWaiter && !masked(Monitor::INTERRUPTED))
|
||||||
pthread_cond_signal(&_waitCond);
|
pthread_cond_signal(&_waitCond);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&_waitLock);
|
pthread_mutex_unlock(&_waitLock);
|
||||||
@@ -235,16 +235,16 @@ bool Monitor::notify() {
|
|||||||
pthread_mutex_lock(&_waitLock);
|
pthread_mutex_lock(&_waitLock);
|
||||||
|
|
||||||
bool wasNotifyable = !pending(INTERRUPTED);
|
bool wasNotifyable = !pending(INTERRUPTED);
|
||||||
|
|
||||||
if(wasNotifyable) {
|
if(wasNotifyable) {
|
||||||
|
|
||||||
// Set the flag and wake the waiter if there
|
// Set the flag and wake the waiter if there
|
||||||
// is one
|
// is one
|
||||||
push(SIGNALED);
|
push(SIGNALED);
|
||||||
|
|
||||||
if(_waiting)
|
if(_waiting)
|
||||||
pthread_cond_signal(&_waitCond);
|
pthread_cond_signal(&_waitCond);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&_waitLock);
|
pthread_mutex_unlock(&_waitLock);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
namespace ZThread {
|
namespace ZThread {
|
||||||
|
|
||||||
const ThreadOps ThreadOps::INVALID(0);
|
const ThreadOps ThreadOps::INVALID(0);
|
||||||
|
|
||||||
bool ThreadOps::join(ThreadOps* ops) {
|
bool ThreadOps::join(ThreadOps* ops) {
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ bool ThreadOps::yield() {
|
|||||||
#if defined(HAVE_SCHED_YIELD)
|
#if defined(HAVE_SCHED_YIELD)
|
||||||
result = sched_yield() == 0;
|
result = sched_yield() == 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -67,11 +67,11 @@ bool ThreadOps::setPriority(ThreadOps* impl, Priority p) {
|
|||||||
assert(impl);
|
assert(impl);
|
||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
#if !defined(ZTHREAD_DISABLE_PRIORITY)
|
#if !defined(ZTHREAD_DISABLE_PRIORITY)
|
||||||
|
|
||||||
struct sched_param param;
|
struct sched_param param;
|
||||||
|
|
||||||
switch(p) {
|
switch(p) {
|
||||||
case Low:
|
case Low:
|
||||||
param.sched_priority = 0;
|
param.sched_priority = 0;
|
||||||
@@ -83,7 +83,7 @@ bool ThreadOps::setPriority(ThreadOps* impl, Priority p) {
|
|||||||
default:
|
default:
|
||||||
param.sched_priority = 5;
|
param.sched_priority = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = pthread_setschedparam(impl->_tid, SCHED_OTHER, ¶m) == 0;
|
result = pthread_setschedparam(impl->_tid, SCHED_OTHER, ¶m) == 0;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -97,14 +97,14 @@ bool ThreadOps::getPriority(ThreadOps* impl, Priority& p) {
|
|||||||
assert(impl);
|
assert(impl);
|
||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
#if !defined(ZTHREAD_DISABLE_PRIORITY)
|
#if !defined(ZTHREAD_DISABLE_PRIORITY)
|
||||||
|
|
||||||
struct sched_param param;
|
struct sched_param param;
|
||||||
int policy = SCHED_OTHER;
|
int policy = SCHED_OTHER;
|
||||||
|
|
||||||
if(result = (pthread_getschedparam(impl->_tid, &policy, ¶m) == 0)) {
|
if(result = (pthread_getschedparam(impl->_tid, &policy, ¶m) == 0)) {
|
||||||
|
|
||||||
// Convert to one of the PRIORITY values
|
// Convert to one of the PRIORITY values
|
||||||
if(param.sched_priority < 10)
|
if(param.sched_priority < 10)
|
||||||
p = Low;
|
p = Low;
|
||||||
@@ -112,9 +112,9 @@ bool ThreadOps::getPriority(ThreadOps* impl, Priority& p) {
|
|||||||
p = Medium;
|
p = Medium;
|
||||||
else
|
else
|
||||||
p = High;
|
p = High;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -132,16 +132,16 @@ extern "C" void *_dispatch(void *arg) {
|
|||||||
|
|
||||||
Runnable* task = reinterpret_cast<Runnable*>(arg);
|
Runnable* task = reinterpret_cast<Runnable*>(arg);
|
||||||
assert(task);
|
assert(task);
|
||||||
|
|
||||||
// Run the task from the correct context
|
// Run the task from the correct context
|
||||||
task->run();
|
task->run();
|
||||||
|
|
||||||
// Exit the thread
|
// Exit the thread
|
||||||
pthread_exit((void**)0);
|
pthread_exit((void**)0);
|
||||||
return (void*)0;
|
return (void*)0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ZThread
|
} // namespace ZThread
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ typedef struct atomic_count_t {
|
|||||||
|
|
||||||
FastLock lock;
|
FastLock lock;
|
||||||
unsigned long count;
|
unsigned long count;
|
||||||
|
|
||||||
atomic_count_t() : count(0) {}
|
atomic_count_t() : count(0) {}
|
||||||
|
|
||||||
} ATOMIC_COUNT;
|
} ATOMIC_COUNT;
|
||||||
@@ -43,7 +43,7 @@ AtomicCount::AtomicCount() {
|
|||||||
|
|
||||||
ATOMIC_COUNT* c = new ATOMIC_COUNT;
|
ATOMIC_COUNT* c = new ATOMIC_COUNT;
|
||||||
_value = reinterpret_cast<void*>(c);
|
_value = reinterpret_cast<void*>(c);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomicCount::~AtomicCount() {
|
AtomicCount::~AtomicCount() {
|
||||||
@@ -54,22 +54,22 @@ AtomicCount::~AtomicCount() {
|
|||||||
delete c;
|
delete c;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Postfix decrement and return the current value
|
//! Postfix decrement and return the current value
|
||||||
size_t AtomicCount::operator--(int) {
|
size_t AtomicCount::operator--(int) {
|
||||||
|
|
||||||
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
||||||
|
|
||||||
Guard<FastLock> g(c->lock);
|
Guard<FastLock> g(c->lock);
|
||||||
return c->count--;
|
return c->count--;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Postfix increment and return the current value
|
//! Postfix increment and return the current value
|
||||||
size_t AtomicCount::operator++(int) {
|
size_t AtomicCount::operator++(int) {
|
||||||
|
|
||||||
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
||||||
|
|
||||||
Guard<FastLock> g(c->lock);
|
Guard<FastLock> g(c->lock);
|
||||||
return c->count++;
|
return c->count++;
|
||||||
|
|
||||||
@@ -79,17 +79,17 @@ size_t AtomicCount::operator++(int) {
|
|||||||
size_t AtomicCount::operator--() {
|
size_t AtomicCount::operator--() {
|
||||||
|
|
||||||
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
||||||
|
|
||||||
Guard<FastLock> g(c->lock);
|
Guard<FastLock> g(c->lock);
|
||||||
return --c->count;
|
return --c->count;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Prefix increment and return the current value
|
//! Prefix increment and return the current value
|
||||||
size_t AtomicCount::operator++() {
|
size_t AtomicCount::operator++() {
|
||||||
|
|
||||||
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
||||||
|
|
||||||
Guard<FastLock> g(c->lock);
|
Guard<FastLock> g(c->lock);
|
||||||
return ++c->count;
|
return ++c->count;
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace ZThread {
|
|||||||
AtomicCount::AtomicCount() {
|
AtomicCount::AtomicCount() {
|
||||||
|
|
||||||
_value = reinterpret_cast<void*>(new LONG(0));
|
_value = reinterpret_cast<void*>(new LONG(0));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomicCount::~AtomicCount() {
|
AtomicCount::~AtomicCount() {
|
||||||
@@ -41,20 +41,20 @@ AtomicCount::~AtomicCount() {
|
|||||||
delete reinterpret_cast<LPLONG>(_value);
|
delete reinterpret_cast<LPLONG>(_value);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtomicCount::increment() {
|
void AtomicCount::increment() {
|
||||||
|
|
||||||
::InterlockedIncrement(reinterpret_cast<LPLONG>(_value));
|
::InterlockedIncrement(reinterpret_cast<LPLONG>(_value));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AtomicCount::decrement() {
|
bool AtomicCount::decrement() {
|
||||||
|
|
||||||
LONG v = ::InterlockedDecrement(reinterpret_cast<LPLONG>(_value));
|
LONG v = ::InterlockedDecrement(reinterpret_cast<LPLONG>(_value));
|
||||||
return static_cast<unsigned long>(v) == 0;
|
return static_cast<unsigned long>(v) == 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __ZTATOMICCOUNTIMPL_H__
|
#endif // __ZTATOMICCOUNTIMPL_H__
|
||||||
|
|||||||
@@ -29,24 +29,24 @@
|
|||||||
using namespace ZThread;
|
using namespace ZThread;
|
||||||
|
|
||||||
Monitor::Monitor() : _owner(0), _waiting(false) {
|
Monitor::Monitor() : _owner(0), _waiting(false) {
|
||||||
|
|
||||||
_handle = ::CreateEvent(0, TRUE, FALSE, 0);
|
_handle = ::CreateEvent(0, TRUE, FALSE, 0);
|
||||||
if(_handle == NULL) {
|
if(_handle == NULL) {
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Monitor::~Monitor() {
|
Monitor::~Monitor() {
|
||||||
|
|
||||||
assert(!_waiting);
|
assert(!_waiting);
|
||||||
|
|
||||||
::CloseHandle(_handle);
|
::CloseHandle(_handle);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Monitor::STATE Monitor::wait(unsigned long ms) {
|
Monitor::STATE Monitor::wait(unsigned long ms) {
|
||||||
|
|
||||||
// Update the owner on first use. The owner will not change, each
|
// Update the owner on first use. The owner will not change, each
|
||||||
// thread waits only on a single Monitor and a Monitor is never
|
// thread waits only on a single Monitor and a Monitor is never
|
||||||
// shared
|
// shared
|
||||||
@@ -54,13 +54,13 @@ Monitor::STATE Monitor::wait(unsigned long ms) {
|
|||||||
_owner = ::GetCurrentThreadId();
|
_owner = ::GetCurrentThreadId();
|
||||||
|
|
||||||
STATE state; //(INVALID);
|
STATE state; //(INVALID);
|
||||||
|
|
||||||
// Serialize access to the state of the Monitor
|
// Serialize access to the state of the Monitor
|
||||||
// and test the state to determine if a wait is needed.
|
// and test the state to determine if a wait is needed.
|
||||||
_waitLock.acquire();
|
_waitLock.acquire();
|
||||||
|
|
||||||
if(pending(ANYTHING)) {
|
if(pending(ANYTHING)) {
|
||||||
|
|
||||||
// Return without waiting when possible
|
// Return without waiting when possible
|
||||||
state = next();
|
state = next();
|
||||||
|
|
||||||
@@ -68,12 +68,12 @@ Monitor::STATE Monitor::wait(unsigned long ms) {
|
|||||||
return state;
|
return state;
|
||||||
|
|
||||||
}
|
}
|
||||||
// Unlock the external lock if a wait() is probably needed.
|
// Unlock the external lock if a wait() is probably needed.
|
||||||
// Access to the state is still serial.
|
// Access to the state is still serial.
|
||||||
_lock.release();
|
_lock.release();
|
||||||
|
|
||||||
// Wait for a transition in the state that is of interest, this
|
// Wait for a transition in the state that is of interest, this
|
||||||
// allows waits to exclude certain flags (e.g. INTERRUPTED)
|
// allows waits to exclude certain flags (e.g. INTERRUPTED)
|
||||||
// for a single wait() w/o actually discarding those flags -
|
// for a single wait() w/o actually discarding those flags -
|
||||||
// they will remain set until a wait interested in those flags
|
// they will remain set until a wait interested in those flags
|
||||||
// occurs.
|
// occurs.
|
||||||
@@ -82,13 +82,13 @@ Monitor::STATE Monitor::wait(unsigned long ms) {
|
|||||||
// Wait, ignoring signals
|
// Wait, ignoring signals
|
||||||
_waiting = true;
|
_waiting = true;
|
||||||
|
|
||||||
// Block until the event is set.
|
// Block until the event is set.
|
||||||
_waitLock.release();
|
_waitLock.release();
|
||||||
|
|
||||||
// The event is manual reset so this lack of atmoicity will not
|
// The event is manual reset so this lack of atmoicity will not
|
||||||
// be an issue
|
// be an issue
|
||||||
|
|
||||||
DWORD dwResult =
|
DWORD dwResult =
|
||||||
::WaitForSingleObject(_handle, ((ms == 0) ? INFINITE : (DWORD)ms));
|
::WaitForSingleObject(_handle, ((ms == 0) ? INFINITE : (DWORD)ms));
|
||||||
|
|
||||||
// Reacquire serialized access to the state
|
// Reacquire serialized access to the state
|
||||||
@@ -99,20 +99,20 @@ Monitor::STATE Monitor::wait(unsigned long ms) {
|
|||||||
|
|
||||||
if(dwResult == WAIT_TIMEOUT)
|
if(dwResult == WAIT_TIMEOUT)
|
||||||
push(TIMEDOUT);
|
push(TIMEDOUT);
|
||||||
|
|
||||||
// Get the next available STATE
|
// Get the next available STATE
|
||||||
state = next();
|
state = next();
|
||||||
_waiting = false;
|
_waiting = false;
|
||||||
|
|
||||||
::ResetEvent(_handle);
|
::ResetEvent(_handle);
|
||||||
|
|
||||||
// Acquire the internal lock & release the external lock
|
// Acquire the internal lock & release the external lock
|
||||||
_waitLock.release();
|
_waitLock.release();
|
||||||
|
|
||||||
// Reaquire the external lock, keep from deadlocking threads calling
|
// Reaquire the external lock, keep from deadlocking threads calling
|
||||||
// notify(), interrupt(), etc.
|
// notify(), interrupt(), etc.
|
||||||
_lock.acquire();
|
_lock.acquire();
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -122,12 +122,12 @@ bool Monitor::interrupt() {
|
|||||||
|
|
||||||
// Serialize access to the state
|
// Serialize access to the state
|
||||||
_waitLock.acquire();
|
_waitLock.acquire();
|
||||||
|
|
||||||
bool wasInterruptable = !pending(INTERRUPTED);
|
bool wasInterruptable = !pending(INTERRUPTED);
|
||||||
bool hadWaiter = _waiting;
|
bool hadWaiter = _waiting;
|
||||||
|
|
||||||
if(wasInterruptable) {
|
if(wasInterruptable) {
|
||||||
|
|
||||||
// Update the state & wake the waiter if there is one
|
// Update the state & wake the waiter if there is one
|
||||||
push(INTERRUPTED);
|
push(INTERRUPTED);
|
||||||
|
|
||||||
@@ -140,9 +140,9 @@ bool Monitor::interrupt() {
|
|||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else
|
} else
|
||||||
wasInterruptable = !(_owner == ::GetCurrentThreadId());
|
wasInterruptable = !(_owner == ::GetCurrentThreadId());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_waitLock.release();
|
_waitLock.release();
|
||||||
@@ -159,7 +159,7 @@ bool Monitor::isInterrupted() {
|
|||||||
|
|
||||||
bool wasInterrupted = pending(INTERRUPTED);
|
bool wasInterrupted = pending(INTERRUPTED);
|
||||||
clear(INTERRUPTED);
|
clear(INTERRUPTED);
|
||||||
|
|
||||||
_waitLock.release();
|
_waitLock.release();
|
||||||
|
|
||||||
return wasInterrupted;
|
return wasInterrupted;
|
||||||
@@ -173,15 +173,15 @@ bool Monitor::notify() {
|
|||||||
_waitLock.acquire();
|
_waitLock.acquire();
|
||||||
|
|
||||||
bool wasNotifyable = !pending(INTERRUPTED);
|
bool wasNotifyable = !pending(INTERRUPTED);
|
||||||
|
|
||||||
if(wasNotifyable) {
|
if(wasNotifyable) {
|
||||||
|
|
||||||
// Set the flag and wake the waiter if there
|
// Set the flag and wake the waiter if there
|
||||||
// is one
|
// is one
|
||||||
push(SIGNALED);
|
push(SIGNALED);
|
||||||
|
|
||||||
// If there is a waiter then send the signal.
|
// If there is a waiter then send the signal.
|
||||||
if(_waiting)
|
if(_waiting)
|
||||||
if(::SetEvent(_handle) == FALSE) {
|
if(::SetEvent(_handle) == FALSE) {
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
@@ -202,20 +202,20 @@ bool Monitor::cancel() {
|
|||||||
|
|
||||||
bool wasInterrupted = !pending(INTERRUPTED);
|
bool wasInterrupted = !pending(INTERRUPTED);
|
||||||
bool hadWaiter = _waiting;
|
bool hadWaiter = _waiting;
|
||||||
|
|
||||||
push(CANCELED);
|
push(CANCELED);
|
||||||
|
|
||||||
if(wasInterrupted) {
|
if(wasInterrupted) {
|
||||||
|
|
||||||
// Update the state & wake the waiter if there is one
|
// Update the state & wake the waiter if there is one
|
||||||
push(INTERRUPTED);
|
push(INTERRUPTED);
|
||||||
|
|
||||||
// If there is a waiter then send the signal.
|
// If there is a waiter then send the signal.
|
||||||
if(hadWaiter && !masked(Monitor::INTERRUPTED))
|
if(hadWaiter && !masked(Monitor::INTERRUPTED))
|
||||||
if(::SetEvent(_handle) == FALSE) {
|
if(::SetEvent(_handle) == FALSE) {
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_waitLock.release();
|
_waitLock.release();
|
||||||
@@ -230,7 +230,7 @@ bool Monitor::isCanceled() {
|
|||||||
_waitLock.acquire();
|
_waitLock.acquire();
|
||||||
|
|
||||||
bool wasCanceled = examine(CANCELED);
|
bool wasCanceled = examine(CANCELED);
|
||||||
|
|
||||||
if(_owner == ::GetCurrentThreadId())
|
if(_owner == ::GetCurrentThreadId())
|
||||||
clear(INTERRUPTED);
|
clear(INTERRUPTED);
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
namespace ZThread {
|
namespace ZThread {
|
||||||
|
|
||||||
const ThreadOps ThreadOps::INVALID(0);
|
const ThreadOps ThreadOps::INVALID(0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect OS at runtime and attempt to locate the SwitchToThread
|
* Detect OS at runtime and attempt to locate the SwitchToThread
|
||||||
@@ -46,10 +46,10 @@ public:
|
|||||||
v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||||
|
|
||||||
if(::GetVersionEx(&v) && (v.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
|
if(::GetVersionEx(&v) && (v.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
|
||||||
|
|
||||||
// Uses GetModuleHandle() so the reference count on the dll is
|
// Uses GetModuleHandle() so the reference count on the dll is
|
||||||
// not affected. There is a warning about race conditions involving
|
// not affected. There is a warning about race conditions involving
|
||||||
// this function being called as FreeLibrary() completes; however
|
// this function being called as FreeLibrary() completes; however
|
||||||
// nearly all win32 applications load this particular and will keep it
|
// nearly all win32 applications load this particular and will keep it
|
||||||
// in memory until the process exits.
|
// in memory until the process exits.
|
||||||
HINSTANCE hInst = ::GetModuleHandle("Kernel32.dll");
|
HINSTANCE hInst = ::GetModuleHandle("Kernel32.dll");
|
||||||
@@ -62,10 +62,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool operator()() {
|
bool operator()() {
|
||||||
|
|
||||||
// Attempt to yield using the best function available
|
// Attempt to yield using the best function available
|
||||||
if(!_fnYield || !_fnYield())
|
if(!_fnYield || !_fnYield())
|
||||||
::Sleep(0);
|
::Sleep(0);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -78,8 +78,8 @@ bool ThreadOps::join(ThreadOps* ops) {
|
|||||||
assert(ops);
|
assert(ops);
|
||||||
assert(ops->_tid != 0);
|
assert(ops->_tid != 0);
|
||||||
assert(ops->_hThread != NULL);
|
assert(ops->_hThread != NULL);
|
||||||
|
|
||||||
if(::WaitForSingleObjectEx(ops->_hThread, INFINITE, FALSE) != WAIT_OBJECT_0)
|
if(::WaitForSingleObjectEx(ops->_hThread, INFINITE, FALSE) != WAIT_OBJECT_0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
::CloseHandle(ops->_hThread);
|
::CloseHandle(ops->_hThread);
|
||||||
@@ -102,11 +102,11 @@ bool ThreadOps::yield() {
|
|||||||
bool ThreadOps::setPriority(ThreadOps* impl, Priority p) {
|
bool ThreadOps::setPriority(ThreadOps* impl, Priority p) {
|
||||||
|
|
||||||
assert(impl);
|
assert(impl);
|
||||||
|
|
||||||
#if !defined(ZTHREAD_DISABLE_PRIORITY)
|
#if !defined(ZTHREAD_DISABLE_PRIORITY)
|
||||||
|
|
||||||
bool result;
|
bool result;
|
||||||
|
|
||||||
// Convert
|
// Convert
|
||||||
int n;
|
int n;
|
||||||
switch(p) {
|
switch(p) {
|
||||||
@@ -121,7 +121,7 @@ bool ThreadOps::setPriority(ThreadOps* impl, Priority p) {
|
|||||||
n = THREAD_PRIORITY_NORMAL;
|
n = THREAD_PRIORITY_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
result = (::SetThreadPriority(impl->_hThread, n) != THREAD_PRIORITY_ERROR_RETURN);
|
result = (::SetThreadPriority(impl->_hThread, n) != THREAD_PRIORITY_ERROR_RETURN);
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ bool ThreadOps::getPriority(ThreadOps* impl, Priority& p) {
|
|||||||
|
|
||||||
assert(impl);
|
assert(impl);
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
#if !defined(ZTHREAD_DISABLE_PRIORITY)
|
#if !defined(ZTHREAD_DISABLE_PRIORITY)
|
||||||
|
|
||||||
// Convert to one of the PRIORITY values
|
// Convert to one of the PRIORITY values
|
||||||
@@ -154,7 +154,7 @@ bool ThreadOps::getPriority(ThreadOps* impl, Priority& p) {
|
|||||||
default:
|
default:
|
||||||
p = Medium;
|
p = Medium;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -191,7 +191,7 @@ unsigned int __stdcall ThreadOps::_dispatch(void *arg) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,12 +29,12 @@
|
|||||||
namespace ZThread {
|
namespace ZThread {
|
||||||
|
|
||||||
typedef struct atomic_count_t {
|
typedef struct atomic_count_t {
|
||||||
|
|
||||||
CRITICAL_SECTION cs;
|
CRITICAL_SECTION cs;
|
||||||
size_t count;
|
size_t count;
|
||||||
|
|
||||||
atomic_count_t() : count(0) {}
|
atomic_count_t() : count(0) {}
|
||||||
|
|
||||||
} ATOMIC_COUNT;
|
} ATOMIC_COUNT;
|
||||||
|
|
||||||
AtomicCount::AtomicCount() {
|
AtomicCount::AtomicCount() {
|
||||||
@@ -42,13 +42,13 @@ AtomicCount::AtomicCount() {
|
|||||||
ATOMIC_COUNT* c = new ATOMIC_COUNT;
|
ATOMIC_COUNT* c = new ATOMIC_COUNT;
|
||||||
_value = reinterpret_cast<void*>(c);
|
_value = reinterpret_cast<void*>(c);
|
||||||
::InitializeCriticalSection(&c->cs);
|
::InitializeCriticalSection(&c->cs);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomicCount::~AtomicCount() {
|
AtomicCount::~AtomicCount() {
|
||||||
|
|
||||||
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
||||||
assert(c->count == 0);
|
assert(c->count == 0);
|
||||||
::DeleteCriticalSection(&c->cs);
|
::DeleteCriticalSection(&c->cs);
|
||||||
delete c;
|
delete c;
|
||||||
|
|
||||||
@@ -58,8 +58,8 @@ AtomicCount::~AtomicCount() {
|
|||||||
size_t AtomicCount::operator--(int) {
|
size_t AtomicCount::operator--(int) {
|
||||||
|
|
||||||
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
||||||
size_t value;
|
size_t value;
|
||||||
|
|
||||||
::EnterCriticalSection(&c->cs);
|
::EnterCriticalSection(&c->cs);
|
||||||
value = c->count--;
|
value = c->count--;
|
||||||
::LeaveCriticalSection(&c->cs);
|
::LeaveCriticalSection(&c->cs);
|
||||||
@@ -67,13 +67,13 @@ size_t AtomicCount::operator--(int) {
|
|||||||
return value;
|
return value;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Postfix increment and return the current value
|
//! Postfix increment and return the current value
|
||||||
size_t AtomicCount::operator++(int) {
|
size_t AtomicCount::operator++(int) {
|
||||||
|
|
||||||
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
||||||
size_t value;
|
size_t value;
|
||||||
|
|
||||||
::EnterCriticalSection(&c->cs);
|
::EnterCriticalSection(&c->cs);
|
||||||
value = c->count++;
|
value = c->count++;
|
||||||
::LeaveCriticalSection(&c->cs);
|
::LeaveCriticalSection(&c->cs);
|
||||||
@@ -86,8 +86,8 @@ size_t AtomicCount::operator++(int) {
|
|||||||
size_t AtomicCount::operator--() {
|
size_t AtomicCount::operator--() {
|
||||||
|
|
||||||
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
||||||
size_t value;
|
size_t value;
|
||||||
|
|
||||||
::EnterCriticalSection(&c->cs);
|
::EnterCriticalSection(&c->cs);
|
||||||
value = --c->count;
|
value = --c->count;
|
||||||
::LeaveCriticalSection(&c->cs);
|
::LeaveCriticalSection(&c->cs);
|
||||||
@@ -95,13 +95,13 @@ size_t AtomicCount::operator--() {
|
|||||||
return value;
|
return value;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Prefix increment and return the current value
|
//! Prefix increment and return the current value
|
||||||
size_t AtomicCount::operator++() {
|
size_t AtomicCount::operator++() {
|
||||||
|
|
||||||
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
ATOMIC_COUNT* c = reinterpret_cast<ATOMIC_COUNT*>(_value);
|
||||||
size_t value;
|
size_t value;
|
||||||
|
|
||||||
::EnterCriticalSection(&c->cs);
|
::EnterCriticalSection(&c->cs);
|
||||||
value = ++c->count;
|
value = ++c->count;
|
||||||
::LeaveCriticalSection(&c->cs);
|
::LeaveCriticalSection(&c->cs);
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ struct TRINITY_DLL_DECL boss_sapphironAI : public ScriptedAI
|
|||||||
m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||||
m_creature->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING + MOVEMENTFLAG_ONTRANSPORT);
|
m_creature->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING + MOVEMENTFLAG_ONTRANSPORT);
|
||||||
m_creature->GetMotionMaster()->Clear(false);
|
m_creature->GetMotionMaster()->Clear(false);
|
||||||
m_creature->GetMotionMaster()->MoveIdle();
|
m_creature->GetMotionMaster()->MoveIdle();
|
||||||
m_creature->SetHover(true);
|
m_creature->SetHover(true);
|
||||||
Icebolt_Timer = 4000;
|
Icebolt_Timer = 4000;
|
||||||
Icebolt_Count = 0;
|
Icebolt_Count = 0;
|
||||||
@@ -132,16 +132,16 @@ struct TRINITY_DLL_DECL boss_sapphironAI : public ScriptedAI
|
|||||||
}else Icebolt_Timer -= diff;
|
}else Icebolt_Timer -= diff;
|
||||||
|
|
||||||
if(Icebolt_Count == 5 && IsInFly && FrostBreath_Timer < diff )
|
if(Icebolt_Count == 5 && IsInFly && FrostBreath_Timer < diff )
|
||||||
{
|
{
|
||||||
DoScriptText(EMOTE_BREATH, m_creature);
|
DoScriptText(EMOTE_BREATH, m_creature);
|
||||||
DoCast(m_creature->getVictim(),SPELL_FROST_BREATH);
|
DoCast(m_creature->getVictim(),SPELL_FROST_BREATH);
|
||||||
land_Timer = 2000;
|
land_Timer = 2000;
|
||||||
IsInFly = false;
|
IsInFly = false;
|
||||||
FrostBreath_Timer = 6000;
|
FrostBreath_Timer = 6000;
|
||||||
}else FrostBreath_Timer -= diff;
|
}else FrostBreath_Timer -= diff;
|
||||||
|
|
||||||
if(!IsInFly && land_Timer < diff)
|
if(!IsInFly && land_Timer < diff)
|
||||||
{
|
{
|
||||||
phase = 1;
|
phase = 1;
|
||||||
m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
||||||
m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING + MOVEMENTFLAG_ONTRANSPORT);
|
m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING + MOVEMENTFLAG_ONTRANSPORT);
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ struct TRINITY_DLL_DECL boss_kalecgosAI : public ScriptedAI
|
|||||||
TalkSequence = 0;
|
TalkSequence = 0;
|
||||||
isFriendly = false;
|
isFriendly = false;
|
||||||
isEnraged = false;
|
isEnraged = false;
|
||||||
isBanished = false;
|
isBanished = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DamageTaken(Unit *done_by, uint32 &damage)
|
void DamageTaken(Unit *done_by, uint32 &damage)
|
||||||
@@ -191,7 +191,7 @@ struct TRINITY_DLL_DECL boss_kalecgosAI : public ScriptedAI
|
|||||||
switch(TalkSequence)
|
switch(TalkSequence)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
m_creature->setFaction(35);
|
m_creature->setFaction(35);
|
||||||
TalkTimer = 1000;
|
TalkTimer = 1000;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
@@ -276,7 +276,7 @@ struct TRINITY_DLL_DECL boss_sathrovarrAI : public ScriptedAI
|
|||||||
CheckTimer = 1000;
|
CheckTimer = 1000;
|
||||||
ResetThreat = 1000;
|
ResetThreat = 1000;
|
||||||
isEnraged = false;
|
isEnraged = false;
|
||||||
isBanished = false;
|
isBanished = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Aggro(Unit* who)
|
void Aggro(Unit* who)
|
||||||
@@ -339,7 +339,7 @@ struct TRINITY_DLL_DECL boss_sathrovarrAI : public ScriptedAI
|
|||||||
if(Player* i_pl = i->getSource())
|
if(Player* i_pl = i->getSource())
|
||||||
if(i_pl->HasAura(AURA_SPECTRAL_REALM,0))
|
if(i_pl->HasAura(AURA_SPECTRAL_REALM,0))
|
||||||
i_pl->RemoveAurasDueToSpell(AURA_SPECTRAL_REALM);
|
i_pl->RemoveAurasDueToSpell(AURA_SPECTRAL_REALM);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateAI(const uint32 diff)
|
void UpdateAI(const uint32 diff)
|
||||||
{
|
{
|
||||||
@@ -471,7 +471,7 @@ struct TRINITY_DLL_DECL boss_kalecAI : public ScriptedAI
|
|||||||
void UpdateAI(const uint32 diff)
|
void UpdateAI(const uint32 diff)
|
||||||
{
|
{
|
||||||
if (!UpdateVictim())
|
if (!UpdateVictim())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(YellTimer < diff)
|
if(YellTimer < diff)
|
||||||
{
|
{
|
||||||
@@ -559,7 +559,7 @@ void boss_kalecgosAI::UpdateAI(const uint32 diff)
|
|||||||
DoCast(m_creature, SPELL_ENRAGE, true);
|
DoCast(m_creature, SPELL_ENRAGE, true);
|
||||||
isEnraged = true;
|
isEnraged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isBanished && (m_creature->GetHealth()*100)/m_creature->GetMaxHealth() < 1)
|
if(!isBanished && (m_creature->GetHealth()*100)/m_creature->GetMaxHealth() < 1)
|
||||||
{
|
{
|
||||||
if(Unit *Sath = Unit::GetUnit(*m_creature, SathGUID))
|
if(Unit *Sath = Unit::GetUnit(*m_creature, SathGUID))
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ EndScriptData */
|
|||||||
#define SPELL_FEAR 29321
|
#define SPELL_FEAR 29321
|
||||||
#define SPELL_VOID_BOLT 39329
|
#define SPELL_VOID_BOLT 39329
|
||||||
#define SPELL_SPOTLIGHT 25824
|
#define SPELL_SPOTLIGHT 25824
|
||||||
|
|
||||||
#define CENTER_X 432.909f
|
#define CENTER_X 432.909f
|
||||||
#define CENTER_Y -373.424f
|
#define CENTER_Y -373.424f
|
||||||
#define CENTER_Z 17.9608f
|
#define CENTER_Z 17.9608f
|
||||||
@@ -100,7 +100,7 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI
|
|||||||
float Portals[3][3];
|
float Portals[3][3];
|
||||||
|
|
||||||
bool AppearDelay;
|
bool AppearDelay;
|
||||||
bool BlindingLight;
|
bool BlindingLight;
|
||||||
|
|
||||||
void Reset()
|
void Reset()
|
||||||
{
|
{
|
||||||
@@ -134,7 +134,7 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI
|
|||||||
void StartEvent()
|
void StartEvent()
|
||||||
{
|
{
|
||||||
DoScriptText(SAY_AGGRO, m_creature);
|
DoScriptText(SAY_AGGRO, m_creature);
|
||||||
|
|
||||||
if(pInstance)
|
if(pInstance)
|
||||||
pInstance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, IN_PROGRESS);
|
pInstance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, IN_PROGRESS);
|
||||||
}
|
}
|
||||||
@@ -171,7 +171,7 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI
|
|||||||
{
|
{
|
||||||
if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0))
|
if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0))
|
||||||
Summoned->AI()->AttackStart(target);
|
Summoned->AI()->AttackStart(target);
|
||||||
|
|
||||||
Summons.Summon(Summoned);
|
Summons.Summon(Summoned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,7 +215,7 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI
|
|||||||
}
|
}
|
||||||
AppearDelay_Timer = 2000;
|
AppearDelay_Timer = 2000;
|
||||||
}else AppearDelay_Timer -= diff;
|
}else AppearDelay_Timer -= diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Phase == 1)
|
if (Phase == 1)
|
||||||
{
|
{
|
||||||
@@ -236,12 +236,12 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI
|
|||||||
if(!m_creature->HasInArc(2.5f, target))
|
if(!m_creature->HasInArc(2.5f, target))
|
||||||
target = m_creature->getVictim();
|
target = m_creature->getVictim();
|
||||||
|
|
||||||
if(target)
|
if(target)
|
||||||
DoCast(target, SPELL_ARCANE_MISSILES);
|
DoCast(target, SPELL_ARCANE_MISSILES);
|
||||||
}
|
}
|
||||||
ArcaneMissiles_Timer = 3000;
|
ArcaneMissiles_Timer = 3000;
|
||||||
}else ArcaneMissiles_Timer -= diff;
|
}else ArcaneMissiles_Timer -= diff;
|
||||||
|
|
||||||
if (MarkOfTheSolarian_Timer < diff)
|
if (MarkOfTheSolarian_Timer < diff)
|
||||||
{
|
{
|
||||||
DoCast(m_creature->getVictim(), MARK_OF_SOLARIAN);
|
DoCast(m_creature->getVictim(), MARK_OF_SOLARIAN);
|
||||||
|
|||||||
@@ -5680,7 +5680,7 @@ void Aura::PeriodicTick()
|
|||||||
int32 gain = pCaster->ModifyPower(power,gain_amount);
|
int32 gain = pCaster->ModifyPower(power,gain_amount);
|
||||||
m_target->AddThreat(pCaster, float(gain) * 0.5f, GetSpellSchoolMask(GetSpellProto()), GetSpellProto());
|
m_target->AddThreat(pCaster, float(gain) * 0.5f, GetSpellSchoolMask(GetSpellProto()), GetSpellProto());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark of Kaz'rogal
|
// Mark of Kaz'rogal
|
||||||
if(GetId() == 31447 && m_target->GetPower(power) == 0)
|
if(GetId() == 31447 && m_target->GetPower(power) == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -653,7 +653,7 @@ void Spell::EffectDummy(uint32 i)
|
|||||||
if(ihit->effectMask & (1<<i))
|
if(ihit->effectMask & (1<<i))
|
||||||
{
|
{
|
||||||
Unit* casttarget = Unit::GetUnit((*unitTarget), ihit->targetGUID);
|
Unit* casttarget = Unit::GetUnit((*unitTarget), ihit->targetGUID);
|
||||||
if(casttarget)
|
if(casttarget)
|
||||||
m_caster->DealDamage(casttarget, damage, NULL, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_ARCANE, spellInfo, false);
|
m_caster->DealDamage(casttarget, damage, NULL, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_ARCANE, spellInfo, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4978,7 +4978,7 @@ void Spell::EffectScriptEffect(uint32 effIndex)
|
|||||||
}
|
}
|
||||||
case 48025: // Headless Horseman's Mount
|
case 48025: // Headless Horseman's Mount
|
||||||
{
|
{
|
||||||
if(!unitTarget)
|
if(!unitTarget)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(unitTarget)
|
if(unitTarget)
|
||||||
@@ -4987,7 +4987,7 @@ void Spell::EffectScriptEffect(uint32 effIndex)
|
|||||||
{
|
{
|
||||||
case 75: unitTarget->CastSpell(unitTarget, 51621, true); break;;
|
case 75: unitTarget->CastSpell(unitTarget, 51621, true); break;;
|
||||||
case 150: unitTarget->CastSpell(unitTarget, 48024, true); break;
|
case 150: unitTarget->CastSpell(unitTarget, 48024, true); break;
|
||||||
case 225: unitTarget->CastSpell(unitTarget, 51617, true); break;
|
case 225: unitTarget->CastSpell(unitTarget, 51617, true); break;
|
||||||
case 300: unitTarget->CastSpell(unitTarget, 48023, true); break;
|
case 300: unitTarget->CastSpell(unitTarget, 48023, true); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user