diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 64416c592..e0f111d84 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -19,6 +19,8 @@ add_library(common
cpu_detect.h
cubeb_audio_stream.cpp
cubeb_audio_stream.h
+ event.cpp
+ event.h
fifo_queue.h
file_system.cpp
file_system.h
diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj
index 5c958f25d..9e59e7caa 100644
--- a/src/common/common.vcxproj
+++ b/src/common/common.vcxproj
@@ -48,6 +48,7 @@
+
@@ -87,6 +88,7 @@
+
diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters
index bc01bd681..a741709c2 100644
--- a/src/common/common.vcxproj.filters
+++ b/src/common/common.vcxproj.filters
@@ -56,6 +56,7 @@
gl
+
@@ -108,6 +109,7 @@
gl
+
diff --git a/src/common/event.cpp b/src/common/event.cpp
new file mode 100644
index 000000000..aad3b3a81
--- /dev/null
+++ b/src/common/event.cpp
@@ -0,0 +1,138 @@
+#include "event.h"
+#include "assert.h"
+
+#if defined(WIN32)
+#include
+#include "windows_headers.h"
+#elif defined(__linux__) || defined(__APPLE__)
+#include
+#include
+#include
+#ifdef __APPLE__
+#include
+#else
+#include
+#endif
+#endif
+
+namespace Common {
+
+#if defined(WIN32)
+
+Event::Event(bool auto_reset /* = false */)
+{
+ m_event_handle = reinterpret_cast(CreateEvent(nullptr, auto_reset ? FALSE : TRUE, FALSE, nullptr));
+ Assert(m_event_handle != nullptr);
+}
+
+Event::~Event()
+{
+ CloseHandle(reinterpret_cast(m_event_handle));
+}
+
+void Event::Signal()
+{
+ SetEvent(reinterpret_cast(m_event_handle));
+}
+
+void Event::Wait()
+{
+ WaitForSingleObject(reinterpret_cast(m_event_handle), INFINITE);
+}
+
+bool Event::TryWait(u32 timeout_in_ms)
+{
+ return (WaitForSingleObject(reinterpret_cast(m_event_handle), timeout_in_ms) == WAIT_OBJECT_0);
+}
+
+void Event::Reset()
+{
+ ResetEvent(reinterpret_cast(m_event_handle));
+}
+
+void Event::WaitForMultipleEvents(Event** events, u32 num_events)
+{
+ DebugAssert(num_events > 0);
+
+ HANDLE* event_handles = (HANDLE*)alloca(sizeof(HANDLE) * num_events);
+ for (u32 i = 0; i < num_events; i++)
+ event_handles[i] = reinterpret_cast(events[i]->m_event_handle);
+
+ WaitForMultipleObjects(num_events, event_handles, TRUE, INFINITE);
+}
+
+#elif defined(__linux__) || defined(__APPLE__)
+
+Event::Event(bool auto_reset /*= false*/) : m_auto_reset(auto_reset)
+{
+ m_pipe_fds[0] = m_pipe_fds[1] = -1;
+#if defined(__linux__)
+ pipe2(m_pipe_fds, O_NONBLOCK);
+#else
+ pipe(m_pipe_fds);
+ fcntl(m_pipe_fds[0], F_SETFL, fcntl(m_pipe_fds[0], F_GETFL) | O_NONBLOCK);
+ fcntl(m_pipe_fds[1], F_SETFL, fcntl(m_pipe_fds[1], F_GETFL) | O_NONBLOCK);
+#endif
+ Assert(m_pipe_fds[0] >= 0 && m_pipe_fds[1] >= 0);
+}
+
+Event::~Event()
+{
+ close(m_pipe_fds[0]);
+ close(m_pipe_fds[1]);
+}
+
+void Event::Signal()
+{
+ char buf[1] = {0};
+ write(m_pipe_fds[1], buf, sizeof(buf));
+}
+
+void Event::Wait()
+{
+ pollfd pd = {};
+ pd.fd = m_pipe_fds[0];
+ pd.events = POLLRDNORM;
+ poll(&pd, 1, -1);
+
+ if (m_auto_reset)
+ Reset();
+}
+
+bool Event::TryWait(u32 timeout_in_ms)
+{
+ pollfd pd;
+ pd.fd = m_pipe_fds[0];
+ pd.events = POLLRDNORM;
+ if (poll(&pd, 1, timeout_in_ms) == 0)
+ return false;
+
+ if (m_auto_reset)
+ Reset();
+
+ return true;
+}
+
+void Event::Reset()
+{
+ char buf[1];
+ while (read(m_pipe_fds[0], buf, sizeof(buf)) > 0)
+ ;
+}
+
+void Event::WaitForMultipleEvents(Event** events, u32 num_events)
+{
+ DebugAssert(num_events > 0);
+
+ pollfd pd = {};
+ pd.events = POLLRDNORM;
+ for (u32 i = 0; i < num_events; i++)
+ {
+ pd.fd = events[i]->m_pipe_fds[0];
+ poll(&pd, 1, -1);
+ }
+}
+
+#endif
+
+} // namespace Common
diff --git a/src/common/event.h b/src/common/event.h
new file mode 100644
index 000000000..b975ea0c0
--- /dev/null
+++ b/src/common/event.h
@@ -0,0 +1,30 @@
+#pragma once
+#include "types.h"
+
+namespace Common {
+
+class Event
+{
+public:
+ Event(bool auto_reset = false);
+ ~Event();
+
+ void Reset();
+ void Signal();
+ void Wait();
+ bool TryWait(u32 timeout_in_ms);
+
+ static void WaitForMultipleEvents(Event** events, u32 num_events);
+
+private:
+#ifdef WIN32
+ void* m_event_handle;
+#elif defined(__linux__) || defined(__APPLE__)
+ int m_pipe_fds[2];
+ bool m_auto_reset;
+#else
+#error Unknown platform.
+#endif
+};
+
+} // namespace Common
\ No newline at end of file