diff options
Diffstat (limited to 'src/common/std_condition_variable.h')
-rw-r--r-- | src/common/std_condition_variable.h | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/src/common/std_condition_variable.h b/src/common/std_condition_variable.h new file mode 100644 index 000000000..cee7a9dcd --- /dev/null +++ b/src/common/std_condition_variable.h @@ -0,0 +1,170 @@ + +#ifndef CONDITION_VARIABLE_H_ +#define CONDITION_VARIABLE_H_ + +#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z)) +#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) + +#ifndef __has_include +#define __has_include(s) 0 +#endif + +#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ + +// GCC 4.4 provides <condition_variable> +#include <condition_variable> + +#elif __has_include(<condition_variable>) && !ANDROID + +// clang and libc++ provide <condition_variable> on OSX. However, the version +// of libc++ bundled with OSX 10.7 and 10.8 is buggy: it uses _ as a variable. +// +// We work around this issue by undefining and redefining _. + +#undef _ +#include <condition_variable> +#define _(s) wxGetTranslation((s)) + +#else + +// partial std::condition_variable implementation for win32/pthread + +#include "std_mutex.h" + +#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__) +#define USE_RVALUE_REFERENCES +#endif + +#if defined(_WIN32) && defined(_M_X64) +#define USE_CONDITION_VARIABLES +#elif defined(_WIN32) +#define USE_EVENTS +#endif + +namespace std +{ + +class condition_variable +{ +#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES) + typedef CONDITION_VARIABLE native_type; +#elif defined(_WIN32) + typedef HANDLE native_type; +#else + typedef pthread_cond_t native_type; +#endif + +public: + +#ifdef USE_EVENTS + typedef native_type native_handle_type; +#else + typedef native_type* native_handle_type; +#endif + + condition_variable() + { +#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES) + InitializeConditionVariable(&m_handle); +#elif defined(_WIN32) + m_handle = CreateEvent(NULL, false, false, NULL); +#else + pthread_cond_init(&m_handle, NULL); +#endif + } + + ~condition_variable() + { +#if defined(_WIN32) && !defined(USE_CONDITION_VARIABLES) + CloseHandle(m_handle); +#elif !defined(_WIN32) + pthread_cond_destroy(&m_handle); +#endif + } + + condition_variable(const condition_variable&) /*= delete*/; + condition_variable& operator=(const condition_variable&) /*= delete*/; + + void notify_one() + { +#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES) + WakeConditionVariable(&m_handle); +#elif defined(_WIN32) + SetEvent(m_handle); +#else + pthread_cond_signal(&m_handle); +#endif + } + + void notify_all() + { +#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES) + WakeAllConditionVariable(&m_handle); +#elif defined(_WIN32) + // TODO: broken + SetEvent(m_handle); +#else + pthread_cond_broadcast(&m_handle); +#endif + } + + void wait(unique_lock<mutex>& lock) + { +#ifdef _WIN32 + #ifdef USE_SRWLOCKS + SleepConditionVariableSRW(&m_handle, lock.mutex()->native_handle(), INFINITE, 0); + #elif defined(USE_CONDITION_VARIABLES) + SleepConditionVariableCS(&m_handle, lock.mutex()->native_handle(), INFINITE); + #else + // TODO: broken, the unlock and wait need to be atomic + lock.unlock(); + WaitForSingleObject(m_handle, INFINITE); + lock.lock(); + #endif +#else + pthread_cond_wait(&m_handle, lock.mutex()->native_handle()); +#endif + } + + template <class Predicate> + void wait(unique_lock<mutex>& lock, Predicate pred) + { + while (!pred()) + wait(lock); + } + + //template <class Clock, class Duration> + //cv_status wait_until(unique_lock<mutex>& lock, + // const chrono::time_point<Clock, Duration>& abs_time); + + //template <class Clock, class Duration, class Predicate> + // bool wait_until(unique_lock<mutex>& lock, + // const chrono::time_point<Clock, Duration>& abs_time, + // Predicate pred); + + //template <class Rep, class Period> + //cv_status wait_for(unique_lock<mutex>& lock, + // const chrono::duration<Rep, Period>& rel_time); + + //template <class Rep, class Period, class Predicate> + // bool wait_for(unique_lock<mutex>& lock, + // const chrono::duration<Rep, Period>& rel_time, + // Predicate pred); + + native_handle_type native_handle() + { +#ifdef USE_EVENTS + return m_handle; +#else + return &m_handle; +#endif + } + +private: + native_type m_handle; +}; + +} + +#endif +#endif |