forked from dolphin-emu/dolphin
		
	
		
			
				
	
	
		
			176 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
 | |
| #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))
 | |
| 
 | |
| #elif _MSC_VER >= 1700
 | |
| 
 | |
| // The standard implementation is included since VS2012
 | |
| #include <condition_variable>
 | |
| 
 | |
| #else
 | |
| 
 | |
| // partial std::condition_variable implementation for win32/pthread
 | |
| 
 | |
| #include "StdMutex.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
 |