Commit 50c66902 by Ben Clayton

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: 's avatarAntonio Maiorano <amaiorano@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com>
parent 84586399
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#ifndef sw_Synchronization_hpp #ifndef sw_Synchronization_hpp
#define sw_Synchronization_hpp #define sw_Synchronization_hpp
#include <chrono>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
#include <queue> #include <queue>
...@@ -22,6 +23,101 @@ ...@@ -22,6 +23,101 @@
namespace sw 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 is a thread-safe FIFO queue of type T.
// Chan takes its name after Golang's chan. // Chan takes its name after Golang's chan.
template <typename T> template <typename T>
......
...@@ -67,25 +67,4 @@ namespace sw ...@@ -67,25 +67,4 @@ namespace sw
return nullptr; return nullptr;
} }
#endif #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
}
} }
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#ifndef sw_Thread_hpp #ifndef sw_Thread_hpp
#define sw_Thread_hpp #define sw_Thread_hpp
#include "Synchronization.hpp"
#if defined(_WIN32) #if defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
...@@ -45,8 +47,6 @@ ...@@ -45,8 +47,6 @@
namespace sw namespace sw
{ {
class Event;
class Thread class Thread
{ {
public: public:
...@@ -90,28 +90,6 @@ namespace sw ...@@ -90,28 +90,6 @@ namespace sw
bool hasJoined = false; 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 #if PERF_PROFILE
int64_t atomicExchange(int64_t volatile *target, int64_t value); int64_t atomicExchange(int64_t volatile *target, int64_t value);
int atomicExchange(int volatile *target, int value); int atomicExchange(int volatile *target, int value);
...@@ -210,30 +188,6 @@ namespace sw ...@@ -210,30 +188,6 @@ namespace sw
#endif #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 #if PERF_PROFILE
inline int64_t atomicExchange(volatile int64_t *target, int64_t value) inline int64_t atomicExchange(volatile int64_t *target, int64_t value)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment