Reimplement event objects with condition variables

This matches the intended semantics more closely. Every separate opened
copy is awakened once when the object is signaled. If the object is
opened another time, the new copy is awakened once if the object has
ever been signaled.

The previous version never cleared the event, which caused some issues
with the watchdog timer, among other things.

Change-Id: I95626557e184681abcc596d576392f7d272294af
diff --git a/services/server/env/fuchsia/osfunc.cc b/services/server/env/fuchsia/osfunc.cc
index e09f8a0..61df3fb 100644
--- a/services/server/env/fuchsia/osfunc.cc
+++ b/services/server/env/fuchsia/osfunc.cc
@@ -28,6 +28,8 @@
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */ /**************************************************************************/
 
+#include <condition_variable>
+#include <mutex>
 #include <shared_mutex>
 #include <thread>
 #include <vector>
@@ -60,16 +62,45 @@
 {
 struct EventObject
 {
+	std::mutex mutex;
+	std::condition_variable condition_variable;
+	// wake_count is guarded by mutex, but clang's thread safety analysis
+	// doesn't understand that.
+	uint32_t wake_count = 0;
+};
+
+struct EventObjectHandle
+{
 	static constexpr uint32_t kMagic = 'hEVT';
 
-	uint32_t magic = kMagic;
-	zx::event event;
-	static EventObject *FromHandle(IMG_HANDLE img_event_object)
+	static EventObjectHandle *FromHandle(IMG_HANDLE img_event_object)
 	{
-		auto event_object = reinterpret_cast<EventObject *>(img_event_object);
+		auto event_object = reinterpret_cast<EventObjectHandle *>(img_event_object);
 		assert(event_object->magic == kMagic);
 		return event_object;
 	}
+
+	uint32_t magic = kMagic;
+	std::shared_ptr<EventObject> object;
+};
+
+// This struct is used by a single thread to wait for a signal to happen.
+struct EventObjectOpenHandle
+{
+	static constexpr uint32_t kMagic = 'hEVO';
+
+	static EventObjectOpenHandle *FromHandle(IMG_HANDLE img_event_object)
+	{
+		auto event_object = reinterpret_cast<EventObjectOpenHandle *>(img_event_object);
+		assert(event_object->magic == kMagic);
+		return event_object;
+	}
+
+	uint32_t magic = kMagic;
+	std::shared_ptr<EventObject> object;
+	// last_seen_wake_count is set to 0 on the new object, so the first wait
+	// will succeed instantly if the object was ever signaled.
+	uint32_t last_seen_wake_count = 0;
 };
 
 struct Thread
@@ -633,13 +664,9 @@
 PVRSRV_ERROR
 OSEventObjectCreate(const IMG_CHAR *pszName, IMG_HANDLE *hEventObject)
 {
-	std::unique_ptr<msd_img::EventObject> event_object = std::make_unique<msd_img::EventObject>();
-	zx_status_t status = zx::event::create(0, &event_object->event);
-	if (status != ZX_OK)
-	{
-		return ZxStatusToError(status);
-	}
-	*hEventObject = event_object.release();
+	auto handle = std::make_unique<msd_img::EventObjectHandle>();
+	handle->object = std::make_shared<msd_img::EventObject>();
+	*hEventObject = handle.release();
 	return PVRSRV_OK;
 }
 
@@ -647,16 +674,19 @@
 PVRSRV_ERROR
 OSEventObjectDestroy(IMG_HANDLE hEventObject)
 {
-	auto event_object = std::unique_ptr<msd_img::EventObject>(msd_img::EventObject::FromHandle(hEventObject));
+	delete msd_img::EventObjectHandle::FromHandle(hEventObject);
 	return PVRSRV_OK;
 }
 
 PVRSRV_ERROR
 OSEventObjectWait(IMG_HANDLE hOSEventKM)
 {
-	auto event_object = msd_img::EventObject::FromHandle(hOSEventKM);
-	zx_status_t status = event_object->event.wait_one(ZX_EVENT_SIGNALED, zx::time::infinite(), nullptr);
-	return ZxStatusToError(status);
+	auto handle = msd_img::EventObjectOpenHandle::FromHandle(hOSEventKM);
+	std::unique_lock<std::mutex> lock(handle->object->mutex);
+	handle->object->condition_variable.wait(
+		lock, [&handle]() { return handle->object->wake_count != handle->last_seen_wake_count; });
+	handle->last_seen_wake_count = handle->object->wake_count;
+	return PVRSRV_OK;
 }
 
 PVRSRV_ERROR
@@ -680,39 +710,44 @@
 PVRSRV_ERROR
 OSEventObjectWaitKernel(IMG_HANDLE hOSEventKM, IMG_UINT64 uiTimeoutus)
 {
-	auto event_object = msd_img::EventObject::FromHandle(hOSEventKM);
-	zx_status_t status =
-		event_object->event.wait_one(ZX_EVENT_SIGNALED, zx::deadline_after(zx::usec(uiTimeoutus)), nullptr);
-	return ZxStatusToError(status);
+	auto handle = msd_img::EventObjectOpenHandle::FromHandle(hOSEventKM);
+	std::unique_lock<std::mutex> lock(handle->object->mutex);
+	auto timeout_time = std::chrono::steady_clock::now() + std::chrono::microseconds(uiTimeoutus);
+	if (!handle->object->condition_variable.wait_until(
+		    lock, timeout_time, [&handle]() { return handle->object->wake_count != handle->last_seen_wake_count; }))
+	{
+		DASSERT(handle->last_seen_wake_count == handle->object->wake_count);
+		return PVRSRV_ERROR_TIMEOUT;
+	}
+	handle->last_seen_wake_count = handle->object->wake_count;
+	return PVRSRV_OK;
 }
 
 PVRSRV_ERROR
 OSEventObjectOpen(IMG_HANDLE hEventObject, IMG_HANDLE *phOSEvent)
 {
-	auto event_object = msd_img::EventObject::FromHandle(hEventObject);
-	auto event_object_duplicate = std::make_unique<msd_img::EventObject>();
-	zx_status_t status = event_object->event.duplicate(ZX_RIGHT_SAME_RIGHTS, &event_object_duplicate->event);
-	if (status != ZX_OK)
-	{
-		return ZxStatusToError(status);
-	}
-	*phOSEvent = event_object_duplicate.release();
+	auto event_object = msd_img::EventObjectHandle::FromHandle(hEventObject);
+	auto event_object_open = std::make_unique<msd_img::EventObjectOpenHandle>();
+	event_object_open->object = event_object->object;
+	*phOSEvent = event_object_open.release();
 	return PVRSRV_OK;
 }
 
 PVRSRV_ERROR
 OSEventObjectClose(IMG_HANDLE hOSEventKM)
 {
-	auto object = std::unique_ptr<msd_img::EventObject>(msd_img::EventObject::FromHandle(hOSEventKM));
+	delete msd_img::EventObjectOpenHandle::FromHandle(hOSEventKM);
 	return PVRSRV_OK;
 }
 
 PVRSRV_ERROR
 OSEventObjectSignal(IMG_HANDLE hEventObject)
 {
-	auto object = msd_img::EventObject::FromHandle(hEventObject);
-	zx_status_t status = object->event.signal(0u, ZX_EVENT_SIGNALED);
-	return ZxStatusToError(status);
+	auto handle = msd_img::EventObjectHandle::FromHandle(hEventObject);
+	std::lock_guard<std::mutex> lock(handle->object->mutex);
+	handle->object->wake_count++;
+	handle->object->condition_variable.notify_all();
+	return PVRSRV_OK;
 }
 
 PVRSRV_ERROR