From 4df197cdb567f731bec385786ccda35499d656b4 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Thu, 7 Jun 2018 20:29:21 -0500
Subject: [PATCH 03/83] ntdll: Create eventfd-based objects for semaphores.

This patch break things, of course. That is fine. Its purpose is to prevent a Massive Patch Munge.

---
 dlls/ntdll/Makefile.in  |   1 +
 dlls/ntdll/esync.c      | 141 ++++++++++++++++++++++++++++++++++++++++
 dlls/ntdll/esync.h      |  32 +++++++++
 dlls/ntdll/ntdll_misc.h |   1 +
 dlls/ntdll/server.c     |   7 +-
 dlls/ntdll/sync.c       |   5 ++
 6 files changed, 184 insertions(+), 3 deletions(-)
 create mode 100644 dlls/ntdll/esync.c
 create mode 100644 dlls/ntdll/esync.h

diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index ed4bb94e4..b75e8308a 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -15,6 +15,7 @@ C_SRCS = \
 	directory.c \
 	env.c \
 	error.c \
+	esync.c \
 	exception.c \
 	file.c \
 	handletable.c \
diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c
new file mode 100644
index 000000000..da35bdf85
--- /dev/null
+++ b/dlls/ntdll/esync.c
@@ -0,0 +1,141 @@
+/*
+ * eventfd-based synchronization objects
+ *
+ * Copyright (C) 2018 Zebediah Figura
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#ifdef HAVE_SYS_EVENTFD_H
+# include <sys/eventfd.h>
+#endif
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#define NONAMELESSUNION
+#include "windef.h"
+#include "winternl.h"
+#include "wine/server.h"
+#include "wine/debug.h"
+
+#include "ntdll_misc.h"
+#include "esync.h"
+
+#ifndef EFD_SEMAPHORE
+#define EFD_SEMAPHORE 1
+#endif
+
+WINE_DEFAULT_DEBUG_CHANNEL(esync);
+
+int do_esync(void)
+{
+#ifdef HAVE_SYS_EVENTFD_H
+    static int do_esync_cached = -1;
+
+    if (do_esync_cached == -1)
+        do_esync_cached = (getenv("WINEESYNC") != NULL);
+
+    return do_esync_cached;
+#else
+    static int once;
+    if (!once++)
+        FIXME("eventfd not supported on this platform.\n");
+    return 0;
+#endif
+}
+
+enum esync_type
+{
+    ESYNC_SEMAPHORE = 1,
+};
+
+struct esync
+{
+    enum esync_type type;
+    int fd;
+};
+
+struct semaphore
+{
+    struct esync obj;
+    int max;
+};
+
+static NTSTATUS create_esync(int *fd, HANDLE *handle, ACCESS_MASK access,
+    const OBJECT_ATTRIBUTES *attr, int initval, int flags)
+{
+    NTSTATUS ret;
+    data_size_t len;
+    struct object_attributes *objattr;
+    obj_handle_t fd_handle;
+    sigset_t sigset;
+
+    if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
+
+    /* We have to synchronize on the fd cache CS so that our calls to
+     * receive_fd don't race with theirs. */
+    server_enter_uninterrupted_section( &fd_cache_section, &sigset );
+    SERVER_START_REQ( create_esync )
+    {
+        req->access  = access;
+        req->initval = initval;
+        req->flags   = flags;
+        wine_server_add_data( req, objattr, len );
+        ret = wine_server_call( req );
+        if (!ret || ret == STATUS_OBJECT_NAME_EXISTS)
+        {
+            *handle = wine_server_ptr_handle( reply->handle );
+            *fd = receive_fd( &fd_handle );
+            assert( wine_server_ptr_handle(fd_handle) == *handle );
+        }
+    }
+    SERVER_END_REQ;
+    server_leave_uninterrupted_section( &fd_cache_section, &sigset );
+
+    TRACE("-> handle %p, fd %d.\n", *handle, *fd);
+
+    RtlFreeHeap( GetProcessHeap(), 0, objattr );
+    return ret;
+}
+
+extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access,
+    const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max)
+{
+    struct semaphore *semaphore;
+    NTSTATUS ret;
+    int fd = -1;
+
+    TRACE("name %s, initial %d, max %d.\n",
+        attr ? debugstr_us(attr->ObjectName) : "<no name>", initial, max);
+
+    ret = create_esync( &fd, handle, access, attr, initial, EFD_SEMAPHORE );
+    if (!ret || ret == STATUS_OBJECT_NAME_EXISTS)
+    {
+        semaphore = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*semaphore) );
+        if (!semaphore)
+            return STATUS_NO_MEMORY;
+
+        semaphore->obj.type = ESYNC_SEMAPHORE;
+        semaphore->obj.fd = fd;
+        semaphore->max = max;
+    }
+
+    return ret;
+}
diff --git a/dlls/ntdll/esync.h b/dlls/ntdll/esync.h
new file mode 100644
index 000000000..1a88170cf
--- /dev/null
+++ b/dlls/ntdll/esync.h
@@ -0,0 +1,32 @@
+/*
+ * eventfd-based synchronization objects
+ *
+ * Copyright (C) 2018 Zebediah Figura
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+extern int do_esync(void) DECLSPEC_HIDDEN;
+
+extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access,
+    const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN;
+
+
+/* We have to synchronize on the fd cache CS so that our calls to receive_fd
+ * don't race with theirs. It looks weird, I know.
+ *
+ * If we weren't trying to avoid touching the code I'd rename the CS to
+ * "server_fd_section" or something similar. */
+extern RTL_CRITICAL_SECTION fd_cache_section;
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index 17d87cd52..dad0996c4 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -107,6 +107,7 @@ extern unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *
 extern int server_remove_fd_from_cache( HANDLE handle ) DECLSPEC_HIDDEN;
 extern int server_get_unix_fd( HANDLE handle, unsigned int access, int *unix_fd,
                                int *needs_close, enum server_fd_type *type, unsigned int *options ) DECLSPEC_HIDDEN;
+extern int receive_fd( obj_handle_t *handle ) DECLSPEC_HIDDEN;
 extern int server_pipe( int fd[2] ) DECLSPEC_HIDDEN;
 extern NTSTATUS alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_attributes **ret,
                                          data_size_t *ret_len ) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c
index d2d238968..dcb355a65 100644
--- a/dlls/ntdll/server.c
+++ b/dlls/ntdll/server.c
@@ -81,6 +81,7 @@
 #include "wine/server.h"
 #include "wine/debug.h"
 #include "ntdll_misc.h"
+#include "esync.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(server);
 WINE_DECLARE_DEBUG_CHANNEL(winediag);
@@ -120,14 +121,14 @@ sigset_t server_block_set;  /* signals to block during server calls */
 static int fd_socket = -1;  /* socket to exchange file descriptors with the server */
 static pid_t server_pid;
 
-static RTL_CRITICAL_SECTION fd_cache_section;
+RTL_CRITICAL_SECTION fd_cache_section;
 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
 {
     0, 0, &fd_cache_section,
     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
       0, 0, { (DWORD_PTR)(__FILE__ ": fd_cache_section") }
 };
-static RTL_CRITICAL_SECTION fd_cache_section = { &critsect_debug, -1, 0, 0, 0, 0 };
+RTL_CRITICAL_SECTION fd_cache_section = { &critsect_debug, -1, 0, 0, 0, 0 };
 
 /* atomically exchange a 64-bit value */
 static inline LONG64 interlocked_xchg64( LONG64 *dest, LONG64 val )
@@ -773,7 +774,7 @@ void CDECL wine_server_send_fd( int fd )
  *
  * Receive a file descriptor passed from the server.
  */
-static int receive_fd( obj_handle_t *handle )
+int receive_fd( obj_handle_t *handle )
 {
     struct iovec vec;
     struct msghdr msghdr;
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index b74bebf08..c259267fb 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -59,7 +59,9 @@
 #include "winternl.h"
 #include "wine/server.h"
 #include "wine/debug.h"
+
 #include "ntdll_misc.h"
+#include "esync.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
 
@@ -248,6 +250,9 @@ NTSTATUS WINAPI NtCreateSemaphore( OUT PHANDLE SemaphoreHandle,
     if (MaximumCount <= 0 || InitialCount < 0 || InitialCount > MaximumCount)
         return STATUS_INVALID_PARAMETER;
 
+    if (do_esync())
+        return esync_create_semaphore( SemaphoreHandle, access, attr, InitialCount, MaximumCount );
+
     if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
 
     SERVER_START_REQ( create_semaphore )
-- 
2.20.1

