From 06935535827e6ce33ce77ae9c17165d4623b22ec Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Fri, 8 Jun 2018 21:43:37 -0500
Subject: [PATCH 18/83] server: Allow (re)setting esync events on the server
 side.

Some server calls pass an event handle, most notably asyncs. We need to be
able to handle these correctly. Accordingly we pass them along to esync if
it turns out the underlying object is actually an esync object.

In an ideal world we'd just convert all instances of events on the server
side to use esyncs instead. But we want to keep esync perfectly configurable,
so this is how we do it.

---
 server/esync.c | 22 +++++++++++++++++++++-
 server/esync.h |  6 ++++++
 server/event.c | 15 +++++++++++++++
 3 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/server/esync.c b/server/esync.c
index 406c1a557..4f7ff6bda 100644
--- a/server/esync.c
+++ b/server/esync.c
@@ -61,7 +61,7 @@ struct esync
 static void esync_dump( struct object *obj, int verbose );
 static void esync_destroy( struct object *obj );
 
-static const struct object_ops esync_ops =
+const struct object_ops esync_ops =
 {
     sizeof(struct esync),      /* size */
     esync_dump,                /* dump */
@@ -169,6 +169,26 @@ void esync_clear( int fd )
     read( fd, &value, sizeof(value) );
 }
 
+/* Server-side event support. */
+void esync_set_event( struct esync *esync )
+{
+    static const uint64_t value = 1;
+
+    assert( esync->obj.ops == &esync_ops );
+    if (write( esync->fd, &value, sizeof(value) ) == -1)
+        perror( "esync: write" );
+}
+
+void esync_reset_event( struct esync *esync )
+{
+    static uint64_t value = 1;
+
+    assert( esync->obj.ops == &esync_ops );
+
+    /* we don't care about the return value */
+    read( esync->fd, &value, sizeof(value) );
+}
+
 DECL_HANDLER(create_esync)
 {
     struct esync *esync;
diff --git a/server/esync.h b/server/esync.h
index 054a77190..2687c72e4 100644
--- a/server/esync.h
+++ b/server/esync.h
@@ -22,3 +22,9 @@ extern int do_esync(void);
 int esync_create_fd( int initval, int flags );
 void esync_wake_up( struct object *obj );
 void esync_clear( int fd );
+
+struct esync;
+
+extern const struct object_ops esync_ops;
+void esync_set_event( struct esync *esync );
+void esync_reset_event( struct esync *esync );
diff --git a/server/event.c b/server/event.c
index 12724c581..62d8bf7d3 100644
--- a/server/event.c
+++ b/server/event.c
@@ -140,6 +140,10 @@ struct event *create_event( struct object *root, const struct unicode_str *name,
 
 struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access )
 {
+    struct object *obj;
+    if (do_esync() && (obj = get_handle_obj( process, handle, access, &esync_ops)))
+        return (struct event *)obj; /* even though it's not an event */
+
     return (struct event *)get_handle_obj( process, handle, access, &event_ops );
 }
 
@@ -153,6 +157,12 @@ void pulse_event( struct event *event )
 
 void set_event( struct event *event )
 {
+    if (do_esync() && event->obj.ops == &esync_ops)
+    {
+        esync_set_event( (struct esync *)event );
+        return;
+    }
+
     event->signaled = 1;
     /* wake up all waiters if manual reset, a single one otherwise */
     wake_up( &event->obj, !event->manual_reset );
@@ -160,6 +170,11 @@ void set_event( struct event *event )
 
 void reset_event( struct event *event )
 {
+    if (do_esync() && event->obj.ops == &esync_ops)
+    {
+        esync_reset_event( (struct esync *)event );
+        return;
+    }
     event->signaled = 0;
 
     if (do_esync())
-- 
2.20.1

