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)
{