| 
									
										
										
										
											2014-04-14 01:15:23 +02:00
										 |  |  | // Copyright 2014 Dolphin Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Multithreaded event class. This allows waiting in a thread for an event to
 | 
					
						
							|  |  |  | // be triggered in another thread. While waiting, the CPU will be available for
 | 
					
						
							|  |  |  | // other tasks.
 | 
					
						
							|  |  |  | // * Set(): triggers the event and wakes up the waiting thread.
 | 
					
						
							|  |  |  | // * Wait(): waits for the event to be triggered.
 | 
					
						
							|  |  |  | // * Reset(): tries to reset the event before the waiting thread sees it was
 | 
					
						
							|  |  |  | //            triggered. Usually a bad idea.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-14 02:30:40 +02:00
										 |  |  | #ifdef _WIN32
 | 
					
						
							|  |  |  | #include <concrt.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-12 22:53:17 -07:00
										 |  |  | #include <chrono>
 | 
					
						
							| 
									
										
										
										
											2014-08-14 01:14:35 -04:00
										 |  |  | #include <condition_variable>
 | 
					
						
							|  |  |  | #include <mutex>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-14 01:42:03 +02:00
										 |  |  | #include "Common/Flag.h"
 | 
					
						
							| 
									
										
										
										
											2014-04-14 01:15:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Common { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-14 02:30:40 +02:00
										 |  |  | // Windows uses a specific implementation because std::condition_variable has
 | 
					
						
							|  |  |  | // terrible performance for this kind of workload with MSVC++ 2013.
 | 
					
						
							|  |  |  | #ifndef _WIN32
 | 
					
						
							|  |  |  | class Event final | 
					
						
							| 
									
										
										
										
											2014-04-14 01:15:23 +02:00
										 |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | 	void Set() | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-04-14 01:42:03 +02:00
										 |  |  | 		if (m_flag.TestAndSet()) | 
					
						
							| 
									
										
										
										
											2014-04-14 01:15:23 +02:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2014-04-14 01:42:03 +02:00
										 |  |  | 			std::lock_guard<std::mutex> lk(m_mutex); | 
					
						
							| 
									
										
										
										
											2014-04-14 01:15:23 +02:00
										 |  |  | 			m_condvar.notify_one(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void Wait() | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-04-14 01:42:03 +02:00
										 |  |  | 		if (m_flag.TestAndClear()) | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-14 01:15:23 +02:00
										 |  |  | 		std::unique_lock<std::mutex> lk(m_mutex); | 
					
						
							| 
									
										
										
										
											2014-04-14 01:42:03 +02:00
										 |  |  | 		m_condvar.wait(lk, [&]{ return m_flag.IsSet(); }); | 
					
						
							|  |  |  | 		m_flag.Clear(); | 
					
						
							| 
									
										
										
										
											2014-04-14 01:15:23 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-12 22:53:17 -07:00
										 |  |  | 	template<class Rep, class Period> | 
					
						
							|  |  |  | 	bool WaitFor(const std::chrono::duration<Rep, Period>& rel_time) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (m_flag.TestAndClear()) | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		std::unique_lock<std::mutex> lk(m_mutex); | 
					
						
							|  |  |  | 		bool signaled = m_condvar.wait_for(lk, rel_time, | 
					
						
							|  |  |  | 			[&]{ return m_flag.IsSet(); }); | 
					
						
							|  |  |  | 		m_flag.Clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return signaled; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-14 01:15:23 +02:00
										 |  |  | 	void Reset() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// no other action required, since wait loops on
 | 
					
						
							|  |  |  | 		// the predicate and any lingering signal will get
 | 
					
						
							|  |  |  | 		// cleared on the first iteration
 | 
					
						
							| 
									
										
										
										
											2014-04-14 01:42:03 +02:00
										 |  |  | 		m_flag.Clear(); | 
					
						
							| 
									
										
										
										
											2014-04-14 01:15:23 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2014-04-14 01:42:03 +02:00
										 |  |  | 	Flag m_flag; | 
					
						
							| 
									
										
										
										
											2014-04-14 01:15:23 +02:00
										 |  |  | 	std::condition_variable m_condvar; | 
					
						
							|  |  |  | 	std::mutex m_mutex; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2014-04-14 02:30:40 +02:00
										 |  |  | #else
 | 
					
						
							|  |  |  | class Event final | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2014-08-12 22:53:17 -07:00
										 |  |  | 	void Set() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_event.set(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void Wait() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_event.wait(); | 
					
						
							|  |  |  | 		m_event.reset(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	template<class Rep, class Period> | 
					
						
							|  |  |  | 	bool WaitFor(const std::chrono::duration<Rep, Period>& rel_time) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		bool signaled = m_event.wait( | 
					
						
							|  |  |  | 			(u32)std::chrono::duration_cast<std::chrono::milliseconds>(rel_time).count() | 
					
						
							|  |  |  | 			) == 0; | 
					
						
							|  |  |  | 		m_event.reset(); | 
					
						
							|  |  |  | 		return signaled; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void Reset() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_event.reset(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-04-14 02:30:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  | 	concurrency::event m_event; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-04-14 01:15:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | }  // namespace Common
 |