From 525b78c2da9801372ef32849871859ad4cd16db0 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Sun, 10 Jun 2018 23:12:16 -0500
Subject: [PATCH] server: Allocate shared memory segments for semaphores and
 mutexes.

As has been described in the README, these two objects have state that can't
be expressed (or read from) the eventfd descriptor. Namely, for semaphores
we need to know the current lock count, and for mutexes we need to know the
 owner tid and the recursion count. To make these work across processes, we
store them in a global shared memory section.

This patch has no effect by itself; it's for separation.

We use the WINEPREFIX dir to discriminate shm sections for simultaneously
running servers; this is based off of code in libwine (specifically
init_server_dir()).
---
 server/esync.c      | 64 +++++++++++++++++++++++++++++++++++++++++++++
 server/esync.h      |  1 +
 server/main.c       |  4 +++
 server/protocol.def |  2 ++
 4 files changed, 71 insertions(+)

diff --git a/server/esync.c b/server/esync.c
index 5dd38c42a4f..fb9d02fc7d2 100644
--- a/server/esync.c
+++ b/server/esync.c
@@ -21,12 +21,20 @@
 #include "config.h"
 #include "wine/port.h"
 
+#include <fcntl.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdarg.h>
 #ifdef HAVE_SYS_EVENTFD_H
 # include <sys/eventfd.h>
 #endif
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#include <unistd.h>
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
@@ -52,11 +60,46 @@ int do_esync(void)
 #endif
 }
 
+static char shm_name[29];
+static int shm_fd;
+static off_t shm_size;
+
+static void shm_cleanup(void)
+{
+    close( shm_fd );
+    if (shm_unlink( shm_name ) == -1)
+        perror( "shm_unlink" );
+}
+
+void esync_init(void)
+{
+    struct stat st;
+
+    if (fstat( config_dir_fd, &st ) == -1)
+        fatal_error( "cannot stat config dir\n" );
+
+    if (st.st_ino != (unsigned long)st.st_ino)
+        sprintf( shm_name, "/wine-%lx%08lx-esync", (unsigned long)((unsigned long long)st.st_ino >> 32), (unsigned long)st.st_ino );
+    else
+        sprintf( shm_name, "/wine-%lx-esync", (unsigned long)st.st_ino );
+
+    shm_fd = shm_open( shm_name, O_RDWR | O_CREAT | O_EXCL, 0644 );
+    if (shm_fd == -1)
+        perror( "shm_open" );
+
+    shm_size = sysconf( _SC_PAGESIZE );
+    if (ftruncate( shm_fd, shm_size ) == -1)
+        perror( "ftruncate" );
+
+    atexit( shm_cleanup );
+}
+
 struct esync
 {
     struct object   obj;    /* object header */
     int             fd;     /* eventfd file descriptor */
     enum esync_type type;
+    unsigned int    shm_idx;    /* index into the shared memory section */
 };
 
 static void esync_dump( struct object *obj, int verbose );
@@ -146,6 +189,25 @@ static struct esync *create_esync( struct object *root, const struct unicode_str
                 return NULL;
             }
             esync->type = type;
+            if (type == ESYNC_SEMAPHORE || type == ESYNC_MUTEX)
+            {
+                /* Use the fd as index, since that'll be unique across all
+                 * processes, but should hopefully end up also allowing reuse. */
+                esync->shm_idx = esync->fd + 1; /* we keep index 0 reserved */
+                while (esync->shm_idx * 8 >= shm_size)
+                {
+                    /* Better expand the shm section. */
+                    shm_size += sysconf( _SC_PAGESIZE );
+                    if (ftruncate( shm_fd, shm_size ) == -1)
+                    {
+                        fprintf( stderr, "esync: couldn't expand %s to size %ld: ",
+                            shm_name, shm_size );
+                        perror( "ftruncate" );
+                    }
+                }
+            }
+            else
+                esync->shm_idx = 0;
         }
         else
         {
@@ -247,6 +309,7 @@ DECL_HANDLER(create_esync)
                                                           req->access, objattr->attributes );
 
         reply->type = esync->type;
+        reply->shm_idx = esync->shm_idx;
         send_client_fd( current->process, esync->fd, reply->handle );
         release_object( esync );
     }
@@ -278,6 +341,7 @@ DECL_HANDLER(open_esync)
         }
 
         reply->type = esync->type;
+        reply->shm_idx = esync->shm_idx;
 
         send_client_fd( current->process, esync->fd, reply->handle );
         release_object( esync );
diff --git a/server/esync.h b/server/esync.h
index 2687c72e419..aeb58c5469c 100644
--- a/server/esync.h
+++ b/server/esync.h
@@ -19,6 +19,7 @@
  */
 
 extern int do_esync(void);
+void esync_init(void);
 int esync_create_fd( int initval, int flags );
 void esync_wake_up( struct object *obj );
 void esync_clear( int fd );
diff --git a/server/main.c b/server/main.c
index 483a0c85580..ef4d3d7d835 100644
--- a/server/main.c
+++ b/server/main.c
@@ -36,6 +36,7 @@
 #include "file.h"
 #include "thread.h"
 #include "request.h"
+#include "esync.h"
 
 /* command-line options */
 int debug_level = 0;
@@ -140,6 +141,9 @@ int main( int argc, char *argv[] )
     sock_init();
     open_master_socket();
 
+    if (do_esync())
+        esync_init();
+
     if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() );
     set_current_time();
     init_scheduler();
diff --git a/server/protocol.def b/server/protocol.def
index eb80c81d6e6..dde81a3ebcf 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -4053,6 +4053,7 @@ struct handle_info
 @REPLY
     obj_handle_t handle;        /* handle to the object */
     int          type;          /* type of esync object (see below) */
+    unsigned int shm_idx;       /* this object's index into the shm section */
 @END
 
 /* Open an esync object */
@@ -4065,6 +4066,7 @@ struct handle_info
 @REPLY
     obj_handle_t handle;        /* handle to the event */
     int          type;          /* type of esync object (above) */
+    unsigned int shm_idx;       /* this object's index into the shm section */
 @END
 
 /* Retrieve the esync fd for an object. */
-- 
2.26.0

