diff options
Diffstat (limited to 'src/uscxml/concurrency')
-rw-r--r-- | src/uscxml/concurrency/BlockingQueue.h | 79 | ||||
-rw-r--r-- | src/uscxml/concurrency/DelayedEventQueue.cpp | 166 | ||||
-rw-r--r-- | src/uscxml/concurrency/DelayedEventQueue.h | 86 | ||||
-rw-r--r-- | src/uscxml/concurrency/EventBase.cpp | 74 | ||||
-rw-r--r-- | src/uscxml/concurrency/EventBase.h | 61 | ||||
-rw-r--r-- | src/uscxml/concurrency/Timer.cpp | 115 | ||||
-rw-r--r-- | src/uscxml/concurrency/Timer.h | 74 | ||||
-rw-r--r-- | src/uscxml/concurrency/tinythread.cpp | 335 | ||||
-rw-r--r-- | src/uscxml/concurrency/tinythread.h | 726 |
9 files changed, 0 insertions, 1716 deletions
diff --git a/src/uscxml/concurrency/BlockingQueue.h b/src/uscxml/concurrency/BlockingQueue.h deleted file mode 100644 index e53de25..0000000 --- a/src/uscxml/concurrency/BlockingQueue.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @file - * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) - * @copyright Simplified BSD - * - * @cond - * This program is free software: you can redistribute it and/or modify - * it under the terms of the FreeBSD license as published by the FreeBSD - * project. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the FreeBSD license along with this - * program. If not, see <http://www.opensource.org/licenses/bsd-license>. - * @endcond - */ - -#ifndef BLOCKINGQUEUE_H_4LEVMY0N -#define BLOCKINGQUEUE_H_4LEVMY0N - -#include "uscxml/Common.h" -#include "uscxml/concurrency/tinythread.h" -#include <list> - -namespace uscxml { -namespace concurrency { - -template <class T> -class BlockingQueue { -public: - BlockingQueue() {} - virtual ~BlockingQueue() { - } - - virtual void push(const T& elem) { - tthread::lock_guard<tthread::mutex> lock(_mutex); - _queue.push_back(elem); - _cond.notify_all(); - } - - virtual void push_front(const T& elem) { - tthread::lock_guard<tthread::mutex> lock(_mutex); - _queue.push_front(elem); - _cond.notify_all(); - } - - virtual T pop() { - tthread::lock_guard<tthread::mutex> lock(_mutex); -// std::cout << "Popping from " << this << std::endl; - while (_queue.empty()) { - _cond.wait(_mutex); - } - T ret = _queue.front(); - _queue.pop_front(); - return ret; - } - - virtual void clear() { - tthread::lock_guard<tthread::mutex> lock(_mutex); - _queue.clear(); - } - - virtual bool isEmpty() { - tthread::lock_guard<tthread::mutex> lock(_mutex); - return _queue.empty(); - } - -protected: - tthread::mutex _mutex; - tthread::condition_variable _cond; - std::list<T> _queue; -}; - -} -} - -#endif /* end of include guard: BLOCKINGQUEUE_H_4LEVMY0N */ diff --git a/src/uscxml/concurrency/DelayedEventQueue.cpp b/src/uscxml/concurrency/DelayedEventQueue.cpp deleted file mode 100644 index 897e99d..0000000 --- a/src/uscxml/concurrency/DelayedEventQueue.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/** - * @file - * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) - * @copyright Simplified BSD - * - * @cond - * This program is free software: you can redistribute it and/or modify - * it under the terms of the FreeBSD license as published by the FreeBSD - * project. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the FreeBSD license along with this - * program. If not, see <http://www.opensource.org/licenses/bsd-license>. - * @endcond - */ - -#include "DelayedEventQueue.h" -#include "uscxml/messages/Event.h" - -#include <glog/logging.h> - -#include <event2/event.h> -#include "event2/thread.h" - -namespace uscxml { - -DelayedEventQueue::DelayedEventQueue() { -#ifndef _WIN32 - evthread_use_pthreads(); -#else - evthread_use_windows_threads(); -#endif - _eventLoop = event_base_new(); - _thread = NULL; - _isStarted = false; -} - -DelayedEventQueue::~DelayedEventQueue() { -// std::cout << "Deleting DelayedEventQueue" << std::endl; - stop(); - if (_thread && _isStarted) - _thread->join(); - if(_eventLoop) - event_base_free(_eventLoop); -} - -void DelayedEventQueue::run(void* instance) { - DelayedEventQueue* INSTANCE = (DelayedEventQueue*)instance; - int result; - while(INSTANCE->_isStarted) { -// #ifndef EVLOOP_NO_EXIT_ON_EMPTY -// result = event_base_dispatch(INSTANCE->_eventLoop); -// #else - result = event_base_loop(INSTANCE->_eventLoop, EVLOOP_NO_EXIT_ON_EMPTY); -//#endif - (void)result; - } -} - -void DelayedEventQueue::addEvent(std::string eventId, int fd, short opMask, void (*callback)(void*, const std::string eventId), void* userData, bool persist) { - if(_callbackData.find(eventId) != _callbackData.end()) { - cancelEvent(eventId); - } - - if (persist) - opMask |= EV_PERSIST; - - struct event* event = event_new(_eventLoop, fd, opMask, DelayedEventQueue::fileCallback, &_callbackData[eventId]); - - _callbackData[eventId].eventId = eventId; - _callbackData[eventId].userData = userData; - _callbackData[eventId].eventQueue = this; - _callbackData[eventId].callback = callback; - _callbackData[eventId].event = event; - _callbackData[eventId].persist = false; - - event_add(event, NULL); - -} - -void DelayedEventQueue::addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData, bool persist) { - if(_callbackData.find(eventId) != _callbackData.end()) { - cancelEvent(eventId); - } - - struct timeval delay = {delayMs / 1000, (delayMs % 1000) * 1000}; - struct event* event = event_new(_eventLoop, -1, (persist ? EV_PERSIST : 0), DelayedEventQueue::timerCallback, &_callbackData[eventId]); - - _callbackData[eventId].eventId = eventId; - _callbackData[eventId].userData = userData; - _callbackData[eventId].eventQueue = this; - _callbackData[eventId].callback = callback; - _callbackData[eventId].event = event; - _callbackData[eventId].persist = persist; - - event_add(event, &delay); -} - -void DelayedEventQueue::cancelAllEvents() { - tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); - while(_callbackData.size() > 0) { - event_del(_callbackData[_callbackData.begin()->first].event); - event_free(_callbackData[_callbackData.begin()->first].event); - _callbackData.erase(_callbackData.begin()); - } -} - -void DelayedEventQueue::cancelEvent(std::string eventId) { - tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); - - if(_callbackData.find(eventId) != _callbackData.end()) { - event_del(_callbackData[eventId].event); - event_free(_callbackData[eventId].event); - _callbackData.erase(eventId); - } -} - -void DelayedEventQueue::start() { - _isStarted = true; - _thread = new tthread::thread(DelayedEventQueue::run, this); -} - -void DelayedEventQueue::stop() { - if (_isStarted) { - _isStarted = false; - event_base_loopbreak(_eventLoop); - } - if (_thread) { - _thread->join(); - delete _thread; - _thread = NULL; - } -} - -void DelayedEventQueue::dummyCallback(evutil_socket_t fd, short what, void *arg) { -} - -void DelayedEventQueue::fileCallback(evutil_socket_t fd, short what, void *arg) { - struct callbackData *data = (struct callbackData*)arg; - tthread::lock_guard<tthread::recursive_mutex> lock(data->eventQueue->_mutex); - std::string eventId = data->eventId; // copy eventId - data->callback(data->userData, eventId); -} - -void DelayedEventQueue::timerCallback(evutil_socket_t fd, short what, void *arg) { - struct callbackData *data = (struct callbackData*)arg; - tthread::lock_guard<tthread::recursive_mutex> lock(data->eventQueue->_mutex); - - std::string eventId = data->eventId; // copy eventId - try { - data->callback(data->userData, eventId); - } catch (Event e) { - LOG(ERROR) << "Exception thrown when executing delayed event:" << std::endl << e << std::endl; - } catch (...) { - LOG(ERROR) << "Exception thrown when executing delayed event" << std::endl; - } - if (!data->persist) { - event_free(data->event); - data->eventQueue->_callbackData.erase(data->eventId); - } -} - -}
\ No newline at end of file diff --git a/src/uscxml/concurrency/DelayedEventQueue.h b/src/uscxml/concurrency/DelayedEventQueue.h deleted file mode 100644 index 7c2789f..0000000 --- a/src/uscxml/concurrency/DelayedEventQueue.h +++ /dev/null @@ -1,86 +0,0 @@ -/** - * @file - * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) - * @copyright Simplified BSD - * - * @cond - * This program is free software: you can redistribute it and/or modify - * it under the terms of the FreeBSD license as published by the FreeBSD - * project. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the FreeBSD license along with this - * program. If not, see <http://www.opensource.org/licenses/bsd-license>. - * @endcond - */ - -#ifndef DELAYEDEVENTQUEUE_H_JA6WRBVP -#define DELAYEDEVENTQUEUE_H_JA6WRBVP - -#include "uscxml/concurrency/tinythread.h" - - -#include "uscxml/Common.h" -#include "event2/util.h" // for evutil_socket_t -#include <event2/event.h> - -#include <inttypes.h> - -#include <map> -#include <string> - -namespace uscxml { - -class USCXML_API DelayedEventQueue { -public: - - enum OpMask { - DEQ_READ = EV_READ, - DEQ_WRITE = EV_WRITE, - DEQ_SIGNAL = EV_SIGNAL - }; - - struct callbackData { - void *userData; - void (*callback)(void*, const std::string eventId); - std::string eventId; - bool persist; - struct event *event; - DelayedEventQueue* eventQueue; - }; - - DelayedEventQueue(); - virtual ~DelayedEventQueue(); - - void addEvent(std::string eventId, int fd, short opMask, void (*callback)(void*, const std::string eventId), void* userData, bool persist = true); - void addEvent(std::string eventId, void (*callback)(void*, const std::string eventId), uint32_t delayMs, void* userData, bool persist = false); - void cancelEvent(std::string eventId); - void cancelAllEvents(); - - void start(); - void stop(); - static void run(void*); - - bool isEmpty() { - return _callbackData.empty(); - } - - static void timerCallback(evutil_socket_t fd, short what, void *arg); - static void fileCallback(evutil_socket_t fd, short what, void *arg); - static void dummyCallback(evutil_socket_t fd, short what, void *arg); - - bool _isStarted; - tthread::thread* _thread; - tthread::recursive_mutex _mutex; - - std::map<std::string, callbackData> _callbackData; - struct event_base* _eventLoop; -}; - -} - - -#endif /* end of include guard: DELAYEDEVENTQUEUE_H_JA6WRBVP */ diff --git a/src/uscxml/concurrency/EventBase.cpp b/src/uscxml/concurrency/EventBase.cpp deleted file mode 100644 index ec25181..0000000 --- a/src/uscxml/concurrency/EventBase.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file - * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) - * @copyright Simplified BSD - * - * @cond - * This program is free software: you can redistribute it and/or modify - * it under the terms of the FreeBSD license as published by the FreeBSD - * project. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the FreeBSD license along with this - * program. If not, see <http://www.opensource.org/licenses/bsd-license>. - * @endcond - */ - -#include "EventBase.h" - -namespace uscxml { - -std::map<std::string, boost::weak_ptr<EventBase> > EventBase::_eventBases; -tthread::recursive_mutex EventBase::_instanceMutex; - -boost::shared_ptr<EventBase> EventBase::get(const std::string& name) { - tthread::lock_guard<tthread::recursive_mutex> lock(_instanceMutex); - - std::map<std::string, boost::weak_ptr<EventBase> >::iterator instIter = _eventBases.begin(); - while(instIter != _eventBases.end()) { - if (!instIter->second.lock()) { - _eventBases.erase(instIter++); - } else { - instIter++; - } - } - - instIter = _eventBases.find(name); - boost::shared_ptr<EventBase> instance = instIter->second.lock(); - if (instance) - return instance; - - instance = boost::shared_ptr<EventBase>(new EventBase()); - _eventBases.insert(std::make_pair(name, instance)); - - return instance; -} - -EventBase::EventBase() { - base = event_base_new(); - _isStarted = true; - _thread = new tthread::thread(EventBase::run, this); -} - -void EventBase::run(void* arg) { - EventBase* INSTANCE = (EventBase*)arg; - int result; - - while(INSTANCE->_isStarted) { - result = event_base_loop(INSTANCE->base, EVLOOP_NO_EXIT_ON_EMPTY); - (void)result; - } -} - -EventBase::~EventBase() { - _isStarted = false; - event_base_loopbreak(base); - _thread->join(); - event_base_free(base); - delete _thread; -} - -}
\ No newline at end of file diff --git a/src/uscxml/concurrency/EventBase.h b/src/uscxml/concurrency/EventBase.h deleted file mode 100644 index 22bd664..0000000 --- a/src/uscxml/concurrency/EventBase.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * @file - * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) - * @copyright Simplified BSD - * - * @cond - * This program is free software: you can redistribute it and/or modify - * it under the terms of the FreeBSD license as published by the FreeBSD - * project. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the FreeBSD license along with this - * program. If not, see <http://www.opensource.org/licenses/bsd-license>. - * @endcond - */ - -#ifndef EVENTBASE_H_C479DA74 -#define EVENTBASE_H_C479DA74 - -#include "uscxml/Common.h" -#include "uscxml/concurrency/tinythread.h" - -extern "C" { -#include <event2/event.h> -#include <event2/buffer.h> -#include <event2/bufferevent.h> -} - -#include <boost/shared_ptr.hpp> -#include <boost/weak_ptr.hpp> -#include <map> -#include <string> - -namespace uscxml { - -class USCXML_API EventBase { -public: - EventBase(); - virtual ~EventBase(); - - static boost::shared_ptr<EventBase> get(const std::string& name); - struct event_base* base; - -protected: - - static void run(void*); - - tthread::thread* _thread; - bool _isStarted; - - static std::map<std::string, boost::weak_ptr<EventBase> > _eventBases; - static tthread::recursive_mutex _instanceMutex; - -}; - -} - -#endif /* end of include guard: EVENTBASE_H_C479DA74 */ diff --git a/src/uscxml/concurrency/Timer.cpp b/src/uscxml/concurrency/Timer.cpp deleted file mode 100644 index 77b712f..0000000 --- a/src/uscxml/concurrency/Timer.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2013 Alex Reece. -// -// A cross platform monotonic timer. - -// see https://github.com/awreece/monotonic_timer - -#include "uscxml/config.h" -#ifdef HAS_UNISTD_H -#include <unistd.h> -#endif -#include "Timer.h" - -#define NANOS_PER_SECF 1000000000.0 -#define USECS_PER_SEC 1000000 - -#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) -// If we have it, use clock_gettime and CLOCK_MONOTONIC. - -#include <time.h> - -double uscxml::Timer::monotonic_seconds() { - struct timespec time; - // Note: Make sure to link with -lrt to define clock_gettime. - clock_gettime(CLOCK_MONOTONIC, &time); - return ((double) time.tv_sec) + ((double) time.tv_nsec / (NANOS_PER_SECF)); -} - -#elif defined(__APPLE__) -// If we don't have CLOCK_MONOTONIC, we might be on a Mac. There we instead -// use mach_absolute_time(). - -#include <mach/mach_time.h> - -static mach_timebase_info_data_t info; -static void __attribute__((constructor)) init_info() { - mach_timebase_info(&info); -} - -double uscxml::Timer::monotonic_seconds() { - uint64_t time = mach_absolute_time(); - double dtime = (double) time; - dtime *= (double) info.numer; - dtime /= (double) info.denom; - return dtime / NANOS_PER_SECF; -} - -#elif defined(_MSC_VER) -// On Windows, use QueryPerformanceCounter and QueryPerformanceFrequency. - -#define NOMINMAX -#include <windows.h> - -static double PCFreq = 0.0; -__int64 CounterStart = 0; - -double uscxml::Timer::monotonic_seconds() { - if (CounterStart == 0) { - // Accoring to http://stackoverflow.com/a/1739265/447288, this will - // properly initialize the QueryPerformanceCounter. - - LARGE_INTEGER li; - int has_qpc = QueryPerformanceFrequency(&li); - - PCFreq = ((double) li.QuadPart) / 1000.0; - } - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - return double(li.QuadPart - CounterStart)/PCFreq; -} - -#else -// Fall back to rdtsc. The reason we don't use clock() is this scary message -// from the man page: -// "On several other implementations, the value returned by clock() also -// includes the times of any children whose status has been collected via -// wait(2) (or another wait-type call)." -// -// Also, clock() only has microsecond accuracy. -// -// This whitepaper offered excellent advice on how to use rdtscp for -// profiling: http://download.intel.com/embedded/software/IA/324264.pdf -// -// Unfortunately, we can't follow its advice exactly with our semantics, -// so we're just going to use rdtscp with cpuid. -// -// Note that rdtscp will only be available on new processors. - -#include <stdint.h> - -static inline uint64_t rdtsc() { - uint32_t hi, lo; - asm volatile("rdtscp\n" - "movl %%edx, %0\n" - "movl %%eax, %1\n" - "cpuid" - : "=r" (hi), "=r" (lo) : : "%rax", "%rbx", "%rcx", "%rdx"); - return (((uint64_t)hi) << 32) | (uint64_t)lo; -} - -static uint64_t rdtsc_per_sec = 0; -static void __attribute__((constructor)) init_rdtsc_per_sec() { - uint64_t before, after; - - before = rdtsc(); - usleep(USECS_PER_SEC); - after = rdtsc(); - - rdtsc_per_sec = after - before; -} - -double uscxml::Timer::monotonic_seconds() { - return (double) rdtsc() / (double) rdtsc_per_sec; -} - -#endif diff --git a/src/uscxml/concurrency/Timer.h b/src/uscxml/concurrency/Timer.h deleted file mode 100644 index 1ecfeb2..0000000 --- a/src/uscxml/concurrency/Timer.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2013 Alex Reece. -// -// A cross platform monotonic timer. - -// see https://github.com/awreece/monotonic_timer - -#ifndef MONOTONIC_TIMER_H_ -#define MONOTONIC_TIMER_H_ - -#include "uscxml/Common.h" - -// Returns seconds since some unspecified start time (guaranteed to be -// monotonicly increasing). - -// Copyright 2015 Stefan Radomski. - -namespace uscxml { - -class USCXML_API Timer { -public: - - static double monotonic_seconds(); - - Timer() { - invocations = 0; - elapsed = 0; - } - - void start() { - if (invocations == 0) { - started = monotonic_seconds(); - } - invocations++; - } - - void reset() { - elapsed = 0; - } - - void stop() { - if (invocations == 0) - return; - - invocations--; - if (invocations == 0) { - elapsed += monotonic_seconds() - started; - } - } - - ~Timer() { - } - double elapsed; - -protected: - size_t invocations; - double started; -}; - -class USCXML_API Measurement { -public: - Measurement(Timer* timer) : timer(timer) { - timer->start(); - } - - ~Measurement() { - timer->stop(); - } - -protected: - Timer* timer; -}; - -} -#endif // MONOTONIC_TIMER_H_ diff --git a/src/uscxml/concurrency/tinythread.cpp b/src/uscxml/concurrency/tinythread.cpp deleted file mode 100644 index d46cda3..0000000 --- a/src/uscxml/concurrency/tinythread.cpp +++ /dev/null @@ -1,335 +0,0 @@ -/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- -Copyright (c) 2010-2012 Marcus Geelnard - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. This version was altered! - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#include <exception> -#include "tinythread.h" - -#if defined(_TTHREAD_POSIX_) -#include <unistd.h> -#include <map> -#elif defined(_TTHREAD_WIN32_) -#include <process.h> -#endif - -namespace tthread { - -unsigned long long int timeStamp() { - unsigned long long int time = 0; -#ifdef WIN32 - FILETIME tv; - GetSystemTimeAsFileTime(&tv); - time = (((unsigned long long int) tv.dwHighDateTime) << 32) + tv.dwLowDateTime; - time /= 10000; -#else - struct timeval tv; - gettimeofday(&tv, NULL); - time += tv.tv_sec * 1000; - time += tv.tv_usec / 1000; -#endif - return time; -} - -//------------------------------------------------------------------------------ -// condition_variable -//------------------------------------------------------------------------------ -// NOTE 1: The Win32 implementation of the condition_variable class is based on -// the corresponding implementation in GLFW, which in turn is based on a -// description by Douglas C. Schmidt and Irfan Pyarali: -// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html -// -// NOTE 2: Windows Vista actually has native support for condition variables -// (InitializeConditionVariable, WakeConditionVariable, etc), but we want to -// be portable with pre-Vista Windows versions, so TinyThread++ does not use -// Vista condition variables. -//------------------------------------------------------------------------------ - -#if defined(_TTHREAD_WIN32_) -#define _CONDITION_EVENT_ONE 0 -#define _CONDITION_EVENT_ALL 1 -#endif - -#if defined(_TTHREAD_WIN32_) -condition_variable::condition_variable() : mWaitersCount(0) { - mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); - mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); - InitializeCriticalSection(&mWaitersCountLock); -} -#endif - -#if defined(_TTHREAD_WIN32_) -condition_variable::~condition_variable() { - CloseHandle(mEvents[_CONDITION_EVENT_ONE]); - CloseHandle(mEvents[_CONDITION_EVENT_ALL]); - DeleteCriticalSection(&mWaitersCountLock); -} -#endif - -#if defined(_TTHREAD_WIN32_) -void condition_variable::_wait(unsigned int ms) { - if (ms <= 0) - ms = INFINITE; - // Wait for either event to become signaled due to notify_one() or - // notify_all() being called - int result = WaitForMultipleObjects(2, mEvents, FALSE, ms); - if (result == WAIT_FAILED) { - LPVOID lpMsgBuf; - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL); -// UM_LOG_ERR("%s", lpMsgBuf); - LocalFree(lpMsgBuf); - - } - - // Check if we are the last waiter - EnterCriticalSection(&mWaitersCountLock); - -- mWaitersCount; - bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && - (mWaitersCount == 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we are the last waiter to be notified to stop waiting, reset the event - if(lastWaiter) - ResetEvent(mEvents[_CONDITION_EVENT_ALL]); -} -#endif - -#if defined(_TTHREAD_WIN32_) -void condition_variable::notify_one() { - // Are there any waiters? - EnterCriticalSection(&mWaitersCountLock); - bool haveWaiters = (mWaitersCount > 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we have any waiting threads, send them a signal - if(haveWaiters) - SetEvent(mEvents[_CONDITION_EVENT_ONE]); -} -#endif - -#if defined(_TTHREAD_WIN32_) -void condition_variable::notify_all() { - // Are there any waiters? - EnterCriticalSection(&mWaitersCountLock); - bool haveWaiters = (mWaitersCount > 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we have any waiting threads, send them a signal - if(haveWaiters) - SetEvent(mEvents[_CONDITION_EVENT_ALL]); -} -#endif - - -//------------------------------------------------------------------------------ -// POSIX pthread_t to unique thread::id mapping logic. -// Note: Here we use a global thread safe std::map to convert instances of -// pthread_t to small thread identifier numbers (unique within one process). -// This method should be portable across different POSIX implementations. -//------------------------------------------------------------------------------ - -#if defined(_TTHREAD_POSIX_) -static thread::id _pthread_t_to_ID(const pthread_t &aHandle) { - static mutex idMapLock; - static std::map<pthread_t, unsigned long int> idMap; - static unsigned long int idCount(1); - - lock_guard<mutex> guard(idMapLock); - if(idMap.find(aHandle) == idMap.end()) - idMap[aHandle] = idCount ++; - return thread::id(idMap[aHandle]); -} -#endif // _TTHREAD_POSIX_ - - -//------------------------------------------------------------------------------ -// thread -//------------------------------------------------------------------------------ - -/// Information to pass to the new thread (what to run). -struct _thread_start_info { - void (*mFunction)(void *); ///< Pointer to the function to be executed. - void * mArg; ///< Function argument for the thread function. - thread * mThread; ///< Pointer to the thread object. -}; - -// Thread wrapper function. -#if defined(_TTHREAD_WIN32_) -unsigned WINAPI thread::wrapper_function(void * aArg) -#elif defined(_TTHREAD_POSIX_) -void * thread::wrapper_function(void * aArg) -#endif -{ - // Get thread startup information - _thread_start_info * ti = (_thread_start_info *) aArg; - - try { - // Call the actual client thread function - ti->mFunction(ti->mArg); - } catch(...) { - // Uncaught exceptions will terminate the application (default behavior - // according to C++11) - std::terminate(); - } - - // The thread is no longer executing - lock_guard<mutex> guard(ti->mThread->mDataMutex); - ti->mThread->mNotAThread = true; - - // The thread is responsible for freeing the startup information - delete ti; - - return 0; -} - -thread::thread(void (*aFunction)(void *), void * aArg) { - // Serialize access to this thread structure - lock_guard<mutex> guard(mDataMutex); - - // Fill out the thread startup information (passed to the thread wrapper, - // which will eventually free it) - _thread_start_info * ti = new _thread_start_info; - ti->mFunction = aFunction; - ti->mArg = aArg; - ti->mThread = this; - - // The thread is now alive - mNotAThread = false; - - // Create the thread -#if defined(_TTHREAD_WIN32_) - mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID); -#elif defined(_TTHREAD_POSIX_) - if(pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0) - mHandle = 0; -#endif - - // Did we fail to create the thread? - if(!mHandle) { - mNotAThread = true; - delete ti; - } -} - -thread::~thread() { - if(joinable()) - std::terminate(); -} - -void thread::join() { - if(joinable()) { -#if defined(_TTHREAD_WIN32_) - WaitForSingleObject(mHandle, INFINITE); - CloseHandle(mHandle); -#elif defined(_TTHREAD_POSIX_) - pthread_join(mHandle, NULL); -#endif - } -} - -bool thread::joinable() const { - mDataMutex.lock(); - bool result = !mNotAThread; - mDataMutex.unlock(); - return result; -} - -void thread::detach() { - mDataMutex.lock(); - if(!mNotAThread) { -#if defined(_TTHREAD_WIN32_) - CloseHandle(mHandle); -#elif defined(_TTHREAD_POSIX_) - pthread_detach(mHandle); -#endif - mNotAThread = true; - } - mDataMutex.unlock(); -} - -thread::id thread::get_id() const { - if(!joinable()) - return id(); -#if defined(_TTHREAD_WIN32_) - return id((unsigned long int) mWin32ThreadID); -#elif defined(_TTHREAD_POSIX_) - return _pthread_t_to_ID(mHandle); -#endif -} - -unsigned thread::hardware_concurrency() { -#if defined(_TTHREAD_WIN32_) - SYSTEM_INFO si; - GetSystemInfo(&si); - return (int) si.dwNumberOfProcessors; -#elif defined(_SC_NPROCESSORS_ONLN) - return (int) sysconf(_SC_NPROCESSORS_ONLN); -#elif defined(_SC_NPROC_ONLN) - return (int) sysconf(_SC_NPROC_ONLN); -#else - // The standard requires this function to return zero if the number of - // hardware cores could not be determined. - return 0; -#endif -} - - -//------------------------------------------------------------------------------ -// this_thread -//------------------------------------------------------------------------------ - -thread::id this_thread::get_id() { -#if defined(_TTHREAD_WIN32_) - return thread::id((unsigned long int) GetCurrentThreadId()); -#elif defined(_TTHREAD_POSIX_) - return _pthread_t_to_ID(pthread_self()); -#endif -} - -namespace chrono { -namespace system_clock { -uint64_t now() { - uint64_t time = 0; -#ifdef _WIN32 - FILETIME tv; - GetSystemTimeAsFileTime(&tv); - time = (((uint64_t) tv.dwHighDateTime) << 32) + tv.dwLowDateTime; - time /= 10000; -#else - struct timeval tv; - gettimeofday(&tv, NULL); - time += tv.tv_sec * 1000; - time += tv.tv_usec / 1000; -#endif - return time; -} -} -} - -} diff --git a/src/uscxml/concurrency/tinythread.h b/src/uscxml/concurrency/tinythread.h deleted file mode 100644 index e5e5e25..0000000 --- a/src/uscxml/concurrency/tinythread.h +++ /dev/null @@ -1,726 +0,0 @@ -/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- -Copyright (c) 2010-2012 Marcus Geelnard - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. This version was altered! - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#ifndef _TINYTHREAD_H_ -#define _TINYTHREAD_H_ - -#include "uscxml/Common.h" -//#include <ostream> - -/// @file -/// @mainpage TinyThread++ API Reference -/// -/// @section intro_sec Introduction -/// TinyThread++ is a minimal, portable implementation of basic threading -/// classes for C++. -/// -/// They closely mimic the functionality and naming of the C++11 standard, and -/// should be easily replaceable with the corresponding std:: variants. -/// -/// @section port_sec Portability -/// The Win32 variant uses the native Win32 API for implementing the thread -/// classes, while for other systems, the POSIX threads API (pthread) is used. -/// -/// @section class_sec Classes -/// In order to mimic the threading API of the C++11 standard, subsets of -/// several classes are provided. The fundamental classes are: -/// @li tthread::thread -/// @li tthread::mutex -/// @li tthread::recursive_mutex -/// @li tthread::condition_variable -/// @li tthread::lock_guard -/// @li tthread::fast_mutex -/// -/// @section misc_sec Miscellaneous -/// The following special keywords are available: #thread_local. -/// -/// For more detailed information (including additional classes), browse the -/// different sections of this documentation. A good place to start is: -/// tinythread.h. - -// Which platform are we on? -#if !defined(_TTHREAD_PLATFORM_DEFINED_) -#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) -#define _TTHREAD_WIN32_ -#include <boost/cstdint.hpp> -#else -#define _TTHREAD_POSIX_ -#endif -#define _TTHREAD_PLATFORM_DEFINED_ -#endif - -// Platform specific includes -#if defined(_TTHREAD_WIN32_) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#define __UNDEF_LEAN_AND_MEAN -#endif -#include <windows.h> -#ifdef __UNDEF_LEAN_AND_MEAN -#undef WIN32_LEAN_AND_MEAN -#undef __UNDEF_LEAN_AND_MEAN -#endif -#else -#include <pthread.h> -#include <signal.h> -#include <sched.h> -#include <unistd.h> -#include <sys/time.h> -#include <inttypes.h> -#endif - -// Generic includes -#include <ostream> - -/// TinyThread++ version (major number). -#define TINYTHREAD_VERSION_MAJOR 1 -/// TinyThread++ version (minor number). -#define TINYTHREAD_VERSION_MINOR 1 -/// TinyThread++ version (full version). -#define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR) - -// Do we have a fully featured C++11 compiler? -#if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L)) -#define _TTHREAD_CPP11_ -#endif - -// ...at least partial C++11? -#if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__) -#define _TTHREAD_CPP11_PARTIAL_ -#endif - -// Macro for disabling assignments of objects. -#ifdef _TTHREAD_CPP11_PARTIAL_ -#define _TTHREAD_DISABLE_ASSIGNMENT(name) \ - name(const name&) = delete; \ - name& operator=(const name&) = delete; -#else -#define _TTHREAD_DISABLE_ASSIGNMENT(name) \ - name(const name&); \ - name& operator=(const name&); -#endif - -/// @def thread_local -/// Thread local storage keyword. -/// A variable that is declared with the @c thread_local keyword makes the -/// value of the variable local to each thread (known as thread-local storage, -/// or TLS). Example usage: -/// @code -/// // This variable is local to each thread. -/// thread_local int variable; -/// @endcode -/// @note The @c thread_local keyword is a macro that maps to the corresponding -/// compiler directive (e.g. @c __declspec(thread)). While the C++11 standard -/// allows for non-trivial types (e.g. classes with constructors and -/// destructors) to be declared with the @c thread_local keyword, most pre-C++11 -/// compilers only allow for trivial types (e.g. @c int). So, to guarantee -/// portable code, only use trivial types for thread local storage. -/// @note This directive is currently not supported on Mac OS X (it will give -/// a compiler error), since compile-time TLS is not supported in the Mac OS X -/// executable format. Also, some older versions of MinGW (before GCC 4.x) do -/// not support this directive. -/// @hideinitializer - -#if !defined(_TTHREAD_CPP11_) && !defined(thread_local) -#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) -#define thread_local __thread -#else -#define thread_local __declspec(thread) -#endif -#endif - - -/// Main name space for TinyThread++. -/// This namespace is more or less equivalent to the @c std namespace for the -/// C++11 thread classes. For instance, the tthread::mutex class corresponds to -/// the std::mutex class. -namespace tthread { - -unsigned long long int timeStamp(); - -/// Mutex class. -/// This is a mutual exclusion object for synchronizing access to shared -/// memory areas for several threads. The mutex is non-recursive (i.e. a -/// program may deadlock if the thread that owns a mutex object calls lock() -/// on that object). -/// @see recursive_mutex - -class USCXML_API mutex { -public: - /// Constructor. - mutex() -#if defined(_TTHREAD_WIN32_) - : mAlreadyLocked(false) -#endif - { -#if defined(_TTHREAD_WIN32_) - InitializeCriticalSection(&mHandle); -#else - pthread_mutex_init(&mHandle, NULL); -#endif - } - - /// Destructor. - ~mutex() { -#if defined(_TTHREAD_WIN32_) - DeleteCriticalSection(&mHandle); -#else - pthread_mutex_destroy(&mHandle); -#endif - } - - /// Lock the mutex. - /// The method will block the calling thread until a lock on the mutex can - /// be obtained. The mutex remains locked until @c unlock() is called. - /// @see lock_guard - inline void lock() { -#if defined(_TTHREAD_WIN32_) - EnterCriticalSection(&mHandle); - while(mAlreadyLocked) Sleep(1000); // Simulate deadlock... - mAlreadyLocked = true; -#else - pthread_mutex_lock(&mHandle); -#endif - } - - /// Try to lock the mutex. - /// The method will try to lock the mutex. If it fails, the function will - /// return immediately (non-blocking). - /// @return @c true if the lock was acquired, or @c false if the lock could - /// not be acquired. - inline bool try_lock() { -#if defined(_TTHREAD_WIN32_) - bool ret = (TryEnterCriticalSection(&mHandle) ? true : false); - if(ret && mAlreadyLocked) { - LeaveCriticalSection(&mHandle); - ret = false; - } - return ret; -#else - return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; -#endif - } - - /// Unlock the mutex. - /// If any threads are waiting for the lock on this mutex, one of them will - /// be unblocked. - inline void unlock() { -#if defined(_TTHREAD_WIN32_) - mAlreadyLocked = false; - LeaveCriticalSection(&mHandle); -#else - pthread_mutex_unlock(&mHandle); -#endif - } - - //_TTHREAD_DISABLE_ASSIGNMENT(mutex) - -private: -#if defined(_TTHREAD_WIN32_) - CRITICAL_SECTION mHandle; - bool mAlreadyLocked; -#else - pthread_mutex_t mHandle; -#endif - - friend class condition_variable; -}; - -/// Recursive mutex class. -/// This is a mutual exclusion object for synchronizing access to shared -/// memory areas for several threads. The mutex is recursive (i.e. a thread -/// may lock the mutex several times, as long as it unlocks the mutex the same -/// number of times). -/// @see mutex -class USCXML_API recursive_mutex { -public: - /// Constructor. - recursive_mutex() { -#if defined(_TTHREAD_WIN32_) - InitializeCriticalSection(&mHandle); -#else - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&mHandle, &attr); -#endif - } - - /// Destructor. - ~recursive_mutex() { -#if defined(_TTHREAD_WIN32_) - DeleteCriticalSection(&mHandle); -#else - pthread_mutex_destroy(&mHandle); -#endif - } - - /// Lock the mutex. - /// The method will block the calling thread until a lock on the mutex can - /// be obtained. The mutex remains locked until @c unlock() is called. - /// @see lock_guard - inline void lock() { -#if defined(_TTHREAD_WIN32_) - EnterCriticalSection(&mHandle); -#else - pthread_mutex_lock(&mHandle); -#endif - } - - /// Try to lock the mutex. - /// The method will try to lock the mutex. If it fails, the function will - /// return immediately (non-blocking). - /// @return @c true if the lock was acquired, or @c false if the lock could - /// not be acquired. - inline bool try_lock() { -#if defined(_TTHREAD_WIN32_) - return TryEnterCriticalSection(&mHandle) ? true : false; -#else - return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; -#endif - } - - /// Unlock the mutex. - /// If any threads are waiting for the lock on this mutex, one of them will - /// be unblocked. - inline void unlock() { -#if defined(_TTHREAD_WIN32_) - LeaveCriticalSection(&mHandle); -#else - pthread_mutex_unlock(&mHandle); -#endif - } - - //_TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex) - -private: -#if defined(_TTHREAD_WIN32_) - CRITICAL_SECTION mHandle; -#else - pthread_mutex_t mHandle; -#endif - - friend class condition_variable; -}; - -/// Lock guard class. -/// The constructor locks the mutex, and the destructor unlocks the mutex, so -/// the mutex will automatically be unlocked when the lock guard goes out of -/// scope. Example usage: -/// @code -/// mutex m; -/// int counter; -/// -/// void increment() -/// { -/// lock_guard<mutex> guard(m); -/// ++ counter; -/// } -/// @endcode - -template <class T> -class USCXML_API lock_guard { -public: - typedef T mutex_type; - - lock_guard() : mMutex(0) {} - - /// The constructor locks the mutex. - explicit lock_guard(mutex_type &aMutex) { - mMutex = &aMutex; - mMutex->lock(); - } - - /// The destructor unlocks the mutex. - ~lock_guard() { - if(mMutex) - mMutex->unlock(); - } - -private: - mutex_type * mMutex; -}; - -/// Condition variable class. -/// This is a signalling object for synchronizing the execution flow for -/// several threads. Example usage: -/// @code -/// // Shared data and associated mutex and condition variable objects -/// int count; -/// mutex m; -/// condition_variable cond; -/// -/// // Wait for the counter to reach a certain number -/// void wait_counter(int targetCount) -/// { -/// lock_guard<mutex> guard(m); -/// while(count < targetCount) -/// cond.wait(m); -/// } -/// -/// // Increment the counter, and notify waiting threads -/// void increment() -/// { -/// lock_guard<mutex> guard(m); -/// ++ count; -/// cond.notify_all(); -/// } -/// @endcode -class USCXML_API condition_variable { -public: - /// Constructor. -#if defined(_TTHREAD_WIN32_) - condition_variable(); -#else - condition_variable() { - pthread_cond_init(&mHandle, NULL); - } -#endif - - /// Destructor. -#if defined(_TTHREAD_WIN32_) - ~condition_variable(); -#else - ~condition_variable() { - pthread_cond_destroy(&mHandle); - } -#endif - - /// Wait for the condition. - /// The function will block the calling thread until the condition variable - /// is woken by @c notify_one(), @c notify_all() or a spurious wake up. - /// @param[in] aMutex A mutex that will be unlocked when the wait operation - /// starts, an locked again as soon as the wait operation is finished. - template <class _mutexT> - inline void wait(_mutexT &aMutex) { -#if defined(_TTHREAD_WIN32_) - // Increment number of waiters - EnterCriticalSection(&mWaitersCountLock); - ++ mWaitersCount; - LeaveCriticalSection(&mWaitersCountLock); - - // Release the mutex while waiting for the condition (will decrease - // the number of waiters when done)... - aMutex.unlock(); - _wait(0); - aMutex.lock(); -#else - pthread_cond_wait(&mHandle, &aMutex.mHandle); -#endif - } - - template <class _mutexT> - inline void wait_for(_mutexT &aMutex, unsigned int ms) { -#if defined(_TTHREAD_WIN32_) - // Increment number of waiters - EnterCriticalSection(&mWaitersCountLock); - ++ mWaitersCount; - LeaveCriticalSection(&mWaitersCountLock); - - // Release the mutex while waiting for the condition (will decrease - // the number of waiters when done)... - aMutex.unlock(); - _wait(ms); - aMutex.lock(); -#else - struct timeval tv; - gettimeofday(&tv, NULL); - - struct timespec ts; - ts.tv_sec = tv.tv_sec + (ms / 1000); - ts.tv_nsec = (tv.tv_usec * 1000); // convert tv microseconds to nanoseconds - ts.tv_nsec += (ms % 1000) * 1000000; // add millisecond part of wait time - pthread_cond_timedwait(&mHandle, &aMutex.mHandle, &ts); -#endif - } - - /// Notify one thread that is waiting for the condition. - /// If at least one thread is blocked waiting for this condition variable, - /// one will be woken up. - /// @note Only threads that started waiting prior to this call will be - /// woken up. -#if defined(_TTHREAD_WIN32_) - void notify_one(); -#else - inline void notify_one() { - pthread_cond_signal(&mHandle); - } -#endif - - /// Notify all threads that are waiting for the condition. - /// All threads that are blocked waiting for this condition variable will - /// be woken up. - /// @note Only threads that started waiting prior to this call will be - /// woken up. -#if defined(_TTHREAD_WIN32_) - void notify_all(); -#else - inline void notify_all() { - pthread_cond_broadcast(&mHandle); - } -#endif - - //_TTHREAD_DISABLE_ASSIGNMENT(condition_variable) - -private: -#if defined(_TTHREAD_WIN32_) - void _wait(unsigned int ms); - HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs. - unsigned int mWaitersCount; ///< Count of the number of waiters. - CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount. -#else - pthread_cond_t mHandle; -#endif -}; - - -/// Thread class. -class USCXML_API thread { -public: -#if defined(_TTHREAD_WIN32_) - typedef HANDLE native_handle_type; -#else - typedef pthread_t native_handle_type; -#endif - - class id; - - /// Default constructor. - /// Construct a @c thread object without an associated thread of execution - /// (i.e. non-joinable). - thread() : mHandle(0), mNotAThread(true) -#if defined(_TTHREAD_WIN32_) - , mWin32ThreadID(0) -#endif - {} - - /// Thread starting constructor. - /// Construct a @c thread object with a new thread of execution. - /// @param[in] aFunction A function pointer to a function of type: - /// <tt>void fun(void * arg)</tt> - /// @param[in] aArg Argument to the thread function. - /// @note This constructor is not fully compatible with the standard C++ - /// thread class. It is more similar to the pthread_create() (POSIX) and - /// CreateThread() (Windows) functions. - thread(void (*aFunction)(void *), void * aArg); - - /// Destructor. - /// @note If the thread is joinable upon destruction, @c std::terminate() - /// will be called, which terminates the process. It is always wise to do - /// @c join() before deleting a thread object. - ~thread(); - - /// Wait for the thread to finish (join execution flows). - /// After calling @c join(), the thread object is no longer associated with - /// a thread of execution (i.e. it is not joinable, and you may not join - /// with it nor detach from it). - void join(); - - /// Check if the thread is joinable. - /// A thread object is joinable if it has an associated thread of execution. - bool joinable() const; - - /// Detach from the thread. - /// After calling @c detach(), the thread object is no longer assicated with - /// a thread of execution (i.e. it is not joinable). The thread continues - /// execution without the calling thread blocking, and when the thread - /// ends execution, any owned resources are released. - void detach(); - - /// Return the thread ID of a thread object. - id get_id() const; - - /// Get the native handle for this thread. - /// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this - /// is a @c pthread_t. - inline native_handle_type native_handle() { - return mHandle; - } - - /// Determine the number of threads which can possibly execute concurrently. - /// This function is useful for determining the optimal number of threads to - /// use for a task. - /// @return The number of hardware thread contexts in the system. - /// @note If this value is not defined, the function returns zero (0). - static unsigned hardware_concurrency(); - - //_TTHREAD_DISABLE_ASSIGNMENT(thread) - -private: - native_handle_type mHandle; ///< Thread handle. - mutable mutex mDataMutex; ///< Serializer for access to the thread private data. - bool mNotAThread; ///< True if this object is not a thread of execution. -#if defined(_TTHREAD_WIN32_) - unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex). -#endif - - // This is the internal thread wrapper function. -#if defined(_TTHREAD_WIN32_) - static unsigned WINAPI wrapper_function(void * aArg); -#else - static void * wrapper_function(void * aArg); -#endif -}; - -/// Thread ID. -/// The thread ID is a unique identifier for each thread. -/// @see thread::get_id() -class USCXML_API thread::id { -public: - /// Default constructor. - /// The default constructed ID is that of thread without a thread of - /// execution. - id() : mId(0) {}; - - id(unsigned long int aId) : mId(aId) {}; - - id(const id& aId) : mId(aId.mId) {}; - - inline id & operator=(const id &aId) { - mId = aId.mId; - return *this; - } - - inline friend bool operator==(const id &aId1, const id &aId2) { - return (aId1.mId == aId2.mId); - } - - inline friend bool operator!=(const id &aId1, const id &aId2) { - return (aId1.mId != aId2.mId); - } - - inline friend bool operator<=(const id &aId1, const id &aId2) { - return (aId1.mId <= aId2.mId); - } - - inline friend bool operator<(const id &aId1, const id &aId2) { - return (aId1.mId < aId2.mId); - } - - inline friend bool operator>=(const id &aId1, const id &aId2) { - return (aId1.mId >= aId2.mId); - } - - inline friend bool operator>(const id &aId1, const id &aId2) { - return (aId1.mId > aId2.mId); - } - - inline friend std::ostream& operator <<(std::ostream &os, const id &obj) { - os << obj.mId; - return os; - } - -private: - unsigned long int mId; -}; - - -// Related to <ratio> - minimal to be able to support chrono. -typedef long long __intmax_t; - -/// Minimal implementation of the @c ratio class. This class provides enough -/// functionality to implement some basic @c chrono classes. -template <__intmax_t N, __intmax_t D = 1> class ratio { -public: - static double _as_double() { - return double(N) / double(D); - } -}; - -/// Minimal implementation of the @c chrono namespace. -/// The @c chrono namespace provides types for specifying time intervals. -namespace chrono { -/// Duration template class. This class provides enough functionality to -/// implement @c this_thread::sleep_for(). -template <class _Rep, class _Period = ratio<1> > class USCXML_API duration { -private: - _Rep rep_; -public: - typedef _Rep rep; - typedef _Period period; - - /// Construct a duration object with the given duration. - template <class _Rep2> - explicit duration(const _Rep2& r) : rep_(r) {}; - - /// Return the value of the duration object. - rep count() const { - return rep_; - } -}; - -// Standard duration types. -typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds. -typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds. -typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds. -typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds. -typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes. -typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours. - -namespace system_clock { -uint64_t now(); -} - -} - -/// The namespace @c this_thread provides methods for dealing with the -/// calling thread. -namespace this_thread { -/// Return the thread ID of the calling thread. -thread::id get_id(); - -/// Yield execution to another thread. -/// Offers the operating system the opportunity to schedule another thread -/// that is ready to run on the current processor. -inline void yield() { -#if defined(_TTHREAD_WIN32_) - Sleep(0); -#else - sched_yield(); -#endif -} - -/// Blocks the calling thread for a period of time. -/// @param[in] aTime Minimum time to put the thread to sleep. -/// Example usage: -/// @code -/// // Sleep for 100 milliseconds -/// this_thread::sleep_for(chrono::milliseconds(100)); -/// @endcode -/// @note Supported duration types are: nanoseconds, microseconds, -/// milliseconds, seconds, minutes and hours. -template <class _Rep, class _Period> void sleep_for(const chrono::duration<_Rep, _Period>& aTime) { -#if defined(_TTHREAD_WIN32_) - Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5)); -#else - usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5)); -#endif -} -} - -} - -// Define/macro cleanup -#undef _TTHREAD_DISABLE_ASSIGNMENT - -#endif // _TINYTHREAD_H_ |