Move sw::Event to System/Synchronization.hpp

Simplify to a single implementation across all platforms.
Document the class and members.
Also add:
• Constructor with event type and initial state
• clear() method.
• wait() method with timeout.
• operator bool().

Bug: b/133127573
Change-Id: I612dc8a1011aaa2cfa50f40c59849323348b3054
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/31679
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/System/Synchronization.hpp b/src/System/Synchronization.hpp
index ac9b652..0015442 100644
--- a/src/System/Synchronization.hpp
+++ b/src/System/Synchronization.hpp
@@ -15,6 +15,7 @@
 #ifndef sw_Synchronization_hpp
 #define sw_Synchronization_hpp
 
+#include <chrono>
 #include <condition_variable>
 #include <mutex>
 #include <queue>
@@ -22,6 +23,101 @@
 namespace sw
 {
 
+// Event is a synchronization mechanism used to indicate to waiting threads
+// when a boolean condition has become true.
+class Event
+{
+public:
+	enum class ClearMode
+	{
+		// The event signal will be automatically reset when a call to wait()
+		// returns.
+		// A single call to signal() will only unblock a single (possibly
+		// pending) call to wait().
+		Auto,
+
+		// The event will remain in the signaled state when calling signal().
+		// While the event is in the signaled state, any calls to wait() will
+		// unblock without automatically reseting the signaled state.
+		// The signaled state can be reset with a call to clear().
+		Manual
+	};
+
+
+	Event(ClearMode mode = ClearMode::Auto, bool initialState = false)
+			: mode(mode), signaled(initialState) {}
+
+	// signal() signals the event, unblocking any calls to wait().
+	void signal()
+	{
+		std::unique_lock<std::mutex> lock(mutex);
+		signaled = true;
+		if (mode == ClearMode::Auto)
+		{
+			condition.notify_one();
+		}
+		else
+		{
+			condition.notify_all();
+		}
+	}
+
+	// clear() sets the event signal to false.
+	void clear()
+	{
+		std::unique_lock<std::mutex> lock(mutex);
+		signaled = false;
+	}
+
+	// wait() blocks until all the event signal is set to true.
+	// If the event was constructed with the Auto ClearMode, then the signal
+	// is cleared before returning.
+	void wait()
+	{
+		std::unique_lock<std::mutex> lock(mutex);
+		condition.wait(lock, [this] { return signaled; });
+		if (mode == ClearMode::Auto)
+		{
+			signaled = false;
+		}
+	}
+
+	// wait() blocks until the event signal is set to true or the timeout
+	// has been reached, returning true if signal was raised, or false if the
+	// timeout has been reached.
+	// If the event was constructed with the Auto ClearMode and the wait did
+	// not time out, then the signal is cleared before returning.
+	template <class CLOCK, class DURATION>
+	bool wait(const std::chrono::time_point<CLOCK, DURATION>& timeout)
+	{
+		std::unique_lock<std::mutex> lock(mutex);
+		if (!condition.wait_until(lock, timeout, [this] { return signaled; }))
+		{
+			return false;
+		}
+		if (mode == ClearMode::Auto)
+		{
+			signaled = false;
+		}
+		return true;
+	}
+
+	// bool() returns true if the event is signaled, otherwise false.
+	// Note: No lock is held after bool() returns, so the event state may
+	// immediately change after returning.
+	operator bool()
+	{
+		std::unique_lock<std::mutex> lock(mutex);
+		return signaled;
+	}
+
+public:
+	const ClearMode mode;
+	bool signaled; // guarded by mutex
+	std::mutex mutex;
+	std::condition_variable condition;
+};
+
 // Chan is a thread-safe FIFO queue of type T.
 // Chan takes its name after Golang's chan.
 template <typename T>
diff --git a/src/System/Thread.cpp b/src/System/Thread.cpp
index df9a0b7..b50efe4 100644
--- a/src/System/Thread.cpp
+++ b/src/System/Thread.cpp
@@ -67,25 +67,4 @@
 			return nullptr;
 		}
 	#endif
-
-	Event::Event()
-	{
-		#if defined(_WIN32)
-			handle = CreateEvent(NULL, FALSE, FALSE, NULL);
-		#else
-			pthread_cond_init(&handle, NULL);
-			pthread_mutex_init(&mutex, NULL);
-			signaled = false;
-		#endif
-	}
-
-	Event::~Event()
-	{
-		#if defined(_WIN32)
-			CloseHandle(handle);
-		#else
-			pthread_cond_destroy(&handle);
-			pthread_mutex_destroy(&mutex);
-		#endif
-	}
 }
diff --git a/src/System/Thread.hpp b/src/System/Thread.hpp
index b8280f1..bd737ba 100644
--- a/src/System/Thread.hpp
+++ b/src/System/Thread.hpp
@@ -15,6 +15,8 @@
 #ifndef sw_Thread_hpp
 #define sw_Thread_hpp
 
+#include "Synchronization.hpp"
+
 #if defined(_WIN32)
 	#ifndef WIN32_LEAN_AND_MEAN
 		#define WIN32_LEAN_AND_MEAN
@@ -45,8 +47,6 @@
 
 namespace sw
 {
-	class Event;
-
 	class Thread
 	{
 	public:
@@ -90,28 +90,6 @@
 		bool hasJoined = false;
 	};
 
-	class Event
-	{
-		friend class Thread;
-
-	public:
-		Event();
-
-		~Event();
-
-		void signal();
-		void wait();
-
-	private:
-		#if defined(_WIN32)
-			HANDLE handle;
-		#else
-			pthread_cond_t handle;
-			pthread_mutex_t mutex;
-			volatile bool signaled;
-		#endif
-	};
-
 	#if PERF_PROFILE
 	int64_t atomicExchange(int64_t volatile *target, int64_t value);
 	int atomicExchange(int volatile *target, int value);
@@ -210,30 +188,6 @@
 		#endif
 	}
 
-	inline void Event::signal()
-	{
-		#if defined(_WIN32)
-			SetEvent(handle);
-		#else
-			pthread_mutex_lock(&mutex);
-			signaled = true;
-			pthread_cond_signal(&handle);
-			pthread_mutex_unlock(&mutex);
-		#endif
-	}
-
-	inline void Event::wait()
-	{
-		#if defined(_WIN32)
-			WaitForSingleObject(handle, INFINITE);
-		#else
-			pthread_mutex_lock(&mutex);
-			while(!signaled) pthread_cond_wait(&handle, &mutex);
-			signaled = false;
-			pthread_mutex_unlock(&mutex);
-		#endif
-	}
-
 	#if PERF_PROFILE
 	inline int64_t atomicExchange(volatile int64_t *target, int64_t value)
 	{