eventfd_synchronization: Add patch set.

This commit is contained in:
Zebediah Figura 2019-04-03 21:40:49 -05:00
parent 8ce5fe8929
commit 553986fdfb
85 changed files with 11099 additions and 339 deletions

View File

@ -0,0 +1,54 @@
From 2cc1bac9dcbe9d52e395baea3811bfbb38c1ec0b Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Wed, 13 Jun 2018 10:44:49 -0500
Subject: [PATCH 01/83] configure: Check for sys/eventfd.h, ppoll(), and
shm_open().
We use ppoll() instead of poll() for the better time granularity.
Although perhaps we shouldn't since the server doesn't do this.
---
configure.ac | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/configure.ac b/configure.ac
index b2c614726..b44729df7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -505,6 +505,7 @@ AC_CHECK_HEADERS(\
sys/elf32.h \
sys/epoll.h \
sys/event.h \
+ sys/eventfd.h \
sys/exec_elf.h \
sys/filio.h \
sys/inotify.h \
@@ -2245,6 +2246,7 @@ AC_CHECK_FUNCS(\
pipe2 \
poll \
port_create \
+ ppoll \
prctl \
pread \
proc_pidinfo \
@@ -2317,6 +2319,16 @@ AC_SEARCH_LIBS(clock_gettime, rt,
test "$ac_res" = "none required" || AC_SUBST(RT_LIBS,"$ac_res")])
LIBS=$ac_save_LIBS
+dnl Check for shm_open which may be in -lrt
+if test "$ac_cv_header_sys_mman_h" = "yes" -a "x$RT_LIBS" = "x"
+then
+ ac_save_LIBS=$LIBS
+ AC_SEARCH_LIBS(shm_open, rt,
+ [AC_DEFINE(HAVE_SHM_OPEN, 1, [Define to 1 if you have the `shm_open' function.])
+ test "$ac_res" = "none required" || AC_SUBST(RT_LIBS,"$ac_res")])
+fi
+LIBS=$ac_save_LIBS
+
dnl **** Check for OpenLDAP ***
if test "x$with_ldap" != "xno"
then
--
2.20.1

View File

@ -0,0 +1,189 @@
From ed20373cc262b783cd7e04641618a732f33e8a51 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Thu, 7 Jun 2018 20:09:59 -0500
Subject: [PATCH 02/83] server: Create server objects for eventfd-based
synchronization objects.
---
server/Makefile.in | 1 +
server/esync.c | 137 ++++++++++++++++++++++++++++++++++++++++++++
server/protocol.def | 10 ++++
3 files changed, 148 insertions(+)
create mode 100644 server/esync.c
diff --git a/server/Makefile.in b/server/Makefile.in
index d2715e8cb..4f8f10cd5 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -11,6 +11,7 @@ C_SRCS = \
debugger.c \
device.c \
directory.c \
+ esync.c \
event.c \
fd.c \
file.c \
diff --git a/server/esync.c b/server/esync.c
new file mode 100644
index 000000000..147fb7724
--- /dev/null
+++ b/server/esync.c
@@ -0,0 +1,137 @@
+/*
+ * 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 "wine/port.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#ifdef HAVE_SYS_EVENTFD_H
+# include <sys/eventfd.h>
+#endif
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winternl.h"
+
+#include "handle.h"
+#include "request.h"
+#include "file.h"
+
+struct esync
+{
+ struct object obj; /* object header */
+ int fd; /* eventfd file descriptor */
+};
+
+static void esync_dump( struct object *obj, int verbose );
+static void esync_destroy( struct object *obj );
+
+static const struct object_ops esync_ops =
+{
+ sizeof(struct esync), /* size */
+ esync_dump, /* dump */
+ no_get_type, /* get_type */
+ no_add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ NULL, /* satisfied */
+ no_signal, /* signal */
+ no_get_fd, /* get_fd */
+ no_map_access, /* map_access */
+ default_get_sd, /* get_sd */
+ default_set_sd, /* set_sd */
+ no_lookup_name, /* lookup_name */
+ directory_link_name, /* link_name */
+ default_unlink_name, /* unlink_name */
+ no_open_file, /* open_file */
+ no_kernel_obj_list, /* get_kernel_obj_list */
+ no_close_handle, /* close_handle */
+ esync_destroy /* destroy */
+};
+
+static void esync_dump( struct object *obj, int verbose )
+{
+ struct esync *esync = (struct esync *)obj;
+ assert( obj->ops == &esync_ops );
+ fprintf( stderr, "esync fd=%d\n", esync->fd );
+}
+
+static void esync_destroy( struct object *obj )
+{
+ struct esync *esync = (struct esync *)obj;
+ close( esync->fd );
+}
+
+struct esync *create_esync( struct object *root, const struct unicode_str *name,
+ unsigned int attr, int initval, int flags,
+ const struct security_descriptor *sd )
+{
+#ifdef HAVE_SYS_EVENTFD_H
+ struct esync *esync;
+
+ if ((esync = create_named_object( root, &esync_ops, name, attr, sd )))
+ {
+ if (get_error() != STATUS_OBJECT_NAME_EXISTS)
+ {
+ /* initialize it if it didn't already exist */
+ esync->fd = eventfd( initval, flags | EFD_CLOEXEC | EFD_NONBLOCK );
+ if (esync->fd == -1)
+ {
+ perror( "eventfd" );
+ file_set_error();
+ release_object( esync );
+ return NULL;
+ }
+ }
+ }
+ return esync;
+#else
+ /* FIXME: Provide a fallback implementation using pipe(). */
+ set_error( STATUS_NOT_IMPLEMENTED );
+ return NULL;
+#endif
+}
+
+DECL_HANDLER(create_esync)
+{
+ struct esync *esync;
+ struct unicode_str name;
+ struct object *root;
+ const struct security_descriptor *sd;
+ const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
+
+ if (!objattr) return;
+
+ if ((esync = create_esync( root, &name, objattr->attributes, req->initval, req->flags, sd )))
+ {
+ if (get_error() == STATUS_OBJECT_NAME_EXISTS)
+ reply->handle = alloc_handle( current->process, esync, req->access, objattr->attributes );
+ else
+ reply->handle = alloc_handle_no_access_check( current->process, esync,
+ req->access, objattr->attributes );
+
+ send_client_fd( current->process, esync->fd, reply->handle );
+ release_object( esync );
+ }
+
+ if (root) release_object( root );
+}
diff --git a/server/protocol.def b/server/protocol.def
index c3751e609..a56f098ab 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -4041,3 +4041,13 @@ struct handle_info
@REQ(resume_process)
obj_handle_t handle; /* process handle */
@END
+
+/* Create a new eventfd-based synchronization object */
+@REQ(create_esync)
+ unsigned int access; /* wanted access rights */
+ int initval; /* initial value */
+ int flags; /* flags (EFD_SEMAPHORE or 0) */
+ VARARG(objattr,object_attributes); /* object attributes */
+@REPLY
+ obj_handle_t handle; /* handle to the object */
+@END
--
2.20.1

View File

@ -0,0 +1,292 @@
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

View File

@ -0,0 +1,123 @@
From 3f6f2c22a0ee8e7c9067b74aef67018ed0739484 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Thu, 7 Jun 2018 20:45:57 -0500
Subject: [PATCH 04/83] ntdll: Store esync objects locally.
Slight tweak for optimization: return UINT_PTR instead, and remove a useless
cmpxchg.
---
dlls/ntdll/esync.c | 62 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 61 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c
index da35bdf85..2bb85d910 100644
--- a/dlls/ntdll/esync.c
+++ b/dlls/ntdll/esync.c
@@ -19,6 +19,7 @@
*/
#include "config.h"
+#include "wine/port.h"
#include <assert.h>
#include <stdarg.h>
@@ -26,6 +27,9 @@
#ifdef HAVE_SYS_EVENTFD_H
# include <sys/eventfd.h>
#endif
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
@@ -34,6 +38,7 @@
#include "winternl.h"
#include "wine/server.h"
#include "wine/debug.h"
+#include "wine/library.h"
#include "ntdll_misc.h"
#include "esync.h"
@@ -78,6 +83,59 @@ struct semaphore
int max;
};
+/* We'd like lookup to be fast. To that end, we use a static list indexed by handle.
+ * This is copied and adapted from the fd cache code. */
+
+#define ESYNC_LIST_BLOCK_SIZE (65536 / sizeof(struct esync *))
+#define ESYNC_LIST_ENTRIES 128
+
+static struct esync * *esync_list[ESYNC_LIST_ENTRIES];
+static struct esync * esync_list_initial_block[ESYNC_LIST_BLOCK_SIZE];
+
+static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry )
+{
+ UINT_PTR idx = (((UINT_PTR)handle) >> 2) - 1;
+ *entry = idx / ESYNC_LIST_BLOCK_SIZE;
+ return idx % ESYNC_LIST_BLOCK_SIZE;
+}
+
+static BOOL add_to_list( HANDLE handle, struct esync *obj )
+{
+ UINT_PTR entry, idx = handle_to_index( handle, &entry );
+
+ if (entry >= ESYNC_LIST_ENTRIES)
+ {
+ FIXME( "too many allocated handles, not caching %p\n", handle );
+ return FALSE;
+ }
+
+ if (!esync_list[entry]) /* do we need to allocate a new block of entries? */
+ {
+ if (!entry) esync_list[0] = esync_list_initial_block;
+ else
+ {
+ void *ptr = wine_anon_mmap( NULL, ESYNC_LIST_BLOCK_SIZE * sizeof(struct esync *),
+ PROT_READ | PROT_WRITE, 0 );
+ if (ptr == MAP_FAILED) return FALSE;
+ esync_list[entry] = ptr;
+ }
+ }
+
+ obj = interlocked_xchg_ptr((void **)&esync_list[entry][idx], obj);
+ assert(!obj);
+ return TRUE;
+}
+
+static void *esync_get_object( HANDLE handle )
+{
+ UINT_PTR entry, idx = handle_to_index( handle, &entry );
+
+ if (entry >= ESYNC_LIST_ENTRIES || !esync_list[entry]) return NULL;
+
+ return esync_list[entry][idx];
+}
+
+
static NTSTATUS create_esync(int *fd, HANDLE *handle, ACCESS_MASK access,
const OBJECT_ATTRIBUTES *attr, int initval, int flags)
{
@@ -115,7 +173,7 @@ static NTSTATUS create_esync(int *fd, HANDLE *handle, ACCESS_MASK access,
return ret;
}
-extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access,
+NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access,
const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max)
{
struct semaphore *semaphore;
@@ -135,6 +193,8 @@ extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access,
semaphore->obj.type = ESYNC_SEMAPHORE;
semaphore->obj.fd = fd;
semaphore->max = max;
+
+ add_to_list( *handle, &semaphore->obj );
}
return ret;
--
2.20.1

View File

@ -0,0 +1,78 @@
From eb0273dfd273f1f6c48db45b444ec318fe514699 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Thu, 7 Jun 2018 21:02:14 -0500
Subject: [PATCH 05/83] ntdll: Implement NtReleaseSemaphore().
---
dlls/ntdll/esync.c | 22 ++++++++++++++++++++++
dlls/ntdll/esync.h | 1 +
dlls/ntdll/sync.c | 4 ++++
3 files changed, 27 insertions(+)
diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c
index 2bb85d910..bca95b9b2 100644
--- a/dlls/ntdll/esync.c
+++ b/dlls/ntdll/esync.c
@@ -23,6 +23,7 @@
#include <assert.h>
#include <stdarg.h>
+#include <stdint.h>
#include <stdlib.h>
#ifdef HAVE_SYS_EVENTFD_H
# include <sys/eventfd.h>
@@ -199,3 +200,24 @@ NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access,
return ret;
}
+
+NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev )
+{
+ struct semaphore *semaphore = esync_get_object( handle );
+ uint64_t count64 = count;
+
+ TRACE("%p, %d, %p.\n", handle, count, prev);
+
+ if (!semaphore) return STATUS_INVALID_HANDLE;
+
+ if (prev)
+ {
+ FIXME("Can't write previous value.\n");
+ *prev = 1;
+ }
+
+ if (write( semaphore->obj.fd, &count64, sizeof(count64) ) == -1)
+ return FILE_GetNtStatus();
+
+ return STATUS_SUCCESS;
+}
diff --git a/dlls/ntdll/esync.h b/dlls/ntdll/esync.h
index 1a88170cf..fec0b68e8 100644
--- a/dlls/ntdll/esync.h
+++ b/dlls/ntdll/esync.h
@@ -22,6 +22,7 @@ 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;
+extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN;
/* We have to synchronize on the fd cache CS so that our calls to receive_fd
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index c259267fb..93052ddb5 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -333,6 +333,10 @@ NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS cla
NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, PULONG previous )
{
NTSTATUS ret;
+
+ if (do_esync())
+ return esync_release_semaphore( handle, count, previous );
+
SERVER_START_REQ( release_semaphore )
{
req->handle = wine_server_obj_handle( handle );
--
2.20.1

View File

@ -0,0 +1,78 @@
From d101cc56af09470319046d570891e861d0a6154a Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Thu, 7 Jun 2018 21:07:51 -0500
Subject: [PATCH 06/83] ntdll: Close esync objects.
---
dlls/ntdll/esync.c | 19 +++++++++++++++++++
dlls/ntdll/esync.h | 1 +
dlls/ntdll/om.c | 4 ++++
3 files changed, 24 insertions(+)
diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c
index bca95b9b2..f7a427425 100644
--- a/dlls/ntdll/esync.c
+++ b/dlls/ntdll/esync.c
@@ -136,6 +136,25 @@ static void *esync_get_object( HANDLE handle )
return esync_list[entry][idx];
}
+NTSTATUS esync_close( HANDLE handle )
+{
+ UINT_PTR entry, idx = handle_to_index( handle, &entry );
+ struct esync *obj;
+
+ TRACE("%p.\n", handle);
+
+ if (entry < ESYNC_LIST_ENTRIES && esync_list[entry])
+ {
+ if ((obj = interlocked_xchg_ptr( (void **)&esync_list[entry][idx], 0 )))
+ {
+ close( obj->fd );
+ RtlFreeHeap( GetProcessHeap(), 0, obj );
+ return STATUS_SUCCESS;
+ }
+ }
+
+ return STATUS_INVALID_HANDLE;
+}
static NTSTATUS create_esync(int *fd, HANDLE *handle, ACCESS_MASK access,
const OBJECT_ATTRIBUTES *attr, int initval, int flags)
diff --git a/dlls/ntdll/esync.h b/dlls/ntdll/esync.h
index fec0b68e8..a22618de8 100644
--- a/dlls/ntdll/esync.h
+++ b/dlls/ntdll/esync.h
@@ -19,6 +19,7 @@
*/
extern int do_esync(void) DECLSPEC_HIDDEN;
+extern NTSTATUS esync_close( HANDLE handle ) DECLSPEC_HIDDEN;
extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access,
const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c
index b9fe302b1..ef2cb8b94 100644
--- a/dlls/ntdll/om.c
+++ b/dlls/ntdll/om.c
@@ -34,6 +34,7 @@
#include "windef.h"
#include "winternl.h"
#include "ntdll_misc.h"
+#include "esync.h"
#include "wine/server.h"
#include "wine/exception.h"
#include "wine/unicode.h"
@@ -446,6 +447,9 @@ NTSTATUS close_handle( HANDLE handle )
NTSTATUS ret;
int fd = server_remove_fd_from_cache( handle );
+ if (do_esync())
+ esync_close( handle );
+
SERVER_START_REQ( close_handle )
{
req->handle = wine_server_obj_handle( handle );
--
2.20.1

View File

@ -0,0 +1,225 @@
From f3596cd66ac694d4a7633f91bc53a2f44b2608cc Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Thu, 7 Jun 2018 21:23:52 -0500
Subject: [PATCH 07/83] ntdll: Implement waiting on esync objects.
This is the most basic case: WAIT_ANY. We use poll() (actually ppoll(), for
the better granularity) to select on all of the handles that we can.
---
dlls/ntdll/esync.c | 161 +++++++++++++++++++++++++++++++++++++++++++++
dlls/ntdll/esync.h | 3 +
dlls/ntdll/sync.c | 7 ++
3 files changed, 171 insertions(+)
diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c
index f7a427425..0950d8b5a 100644
--- a/dlls/ntdll/esync.c
+++ b/dlls/ntdll/esync.c
@@ -22,6 +22,13 @@
#include "wine/port.h"
#include <assert.h>
+#include <errno.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+# include <sys/poll.h>
+#endif
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
@@ -240,3 +247,157 @@ NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev )
return STATUS_SUCCESS;
}
+
+#define TICKSPERSEC 10000000
+#define TICKSPERMSEC 10000
+
+static LONGLONG update_timeout( ULONGLONG end )
+{
+ LARGE_INTEGER now;
+ LONGLONG timeleft;
+
+ NtQuerySystemTime( &now );
+ timeleft = end - now.QuadPart;
+ if (timeleft < 0) timeleft = 0;
+ return timeleft;
+}
+
+static int do_poll( struct pollfd *fds, nfds_t nfds, ULONGLONG *end )
+{
+ if (end)
+ {
+ LONGLONG timeleft = update_timeout( *end );
+
+#ifdef HAVE_PPOLL
+ /* We use ppoll() if available since the time granularity is better. */
+ struct timespec tmo_p;
+ tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC;
+ tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100;
+ return ppoll( fds, nfds, &tmo_p, NULL );
+#else
+ return poll( fds, nfds, timeleft / TICKSPERMSEC );
+#endif
+ }
+ else
+ return poll( fds, nfds, -1 );
+}
+
+/* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we
+ * need to delegate to server_select(). */
+NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
+ BOOLEAN alertable, const LARGE_INTEGER *timeout )
+{
+ struct esync *objs[MAXIMUM_WAIT_OBJECTS];
+ struct pollfd fds[MAXIMUM_WAIT_OBJECTS];
+ int has_esync = 0, has_server = 0;
+ LONGLONG timeleft;
+ LARGE_INTEGER now;
+ ULONGLONG end;
+ int ret;
+ int i;
+
+ NtQuerySystemTime( &now );
+ if (timeout)
+ {
+ if (timeout->QuadPart == TIMEOUT_INFINITE)
+ timeout = NULL;
+ else if (timeout->QuadPart >= 0)
+ end = timeout->QuadPart;
+ else
+ end = now.QuadPart - timeout->QuadPart;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ objs[i] = esync_get_object( handles[i] );
+ if (objs[i])
+ has_esync = 1;
+ else
+ has_server = 1;
+ }
+
+ if (has_esync && has_server)
+ {
+ FIXME("Can't wait on esync and server objects at the same time!\n");
+ /* Wait on just the eventfds; it's the best we can do. */
+ }
+ else if (has_server)
+ {
+ /* It's just server objects, so delegate to the server. */
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (TRACE_ON(esync))
+ {
+ TRACE("Waiting for %s of %d handles:", wait_any ? "any" : "all", count);
+ for (i = 0; i < count; i++)
+ DPRINTF(" %p", handles[i]);
+
+ if (!timeout)
+ DPRINTF(", timeout = INFINITE.\n");
+ else
+ {
+ timeleft = update_timeout( end );
+ DPRINTF(", timeout = %ld.%07ld sec.\n",
+ (long) timeleft / TICKSPERSEC, (long) timeleft % TICKSPERSEC);
+ }
+ }
+
+ if (wait_any || count == 1)
+ {
+ for (i = 0; i < count; i++)
+ {
+ fds[i].fd = objs[i] ? objs[i]->fd : -1;
+ fds[i].events = POLLIN;
+ }
+
+ while (1)
+ {
+ ret = do_poll( fds, count, timeout ? &end : NULL );
+ if (ret > 0)
+ {
+ /* Find out which object triggered the wait. */
+ for (i = 0; i < count; i++)
+ {
+ if (fds[i].revents & (POLLERR | POLLHUP | POLLNVAL))
+ {
+ ERR("Polling on fd %d returned %#x.\n", fds[i].fd, fds[i].revents);
+ return STATUS_INVALID_HANDLE;
+ }
+
+ if (objs[i])
+ {
+ int64_t value;
+ ssize_t size;
+
+ if ((size = read( fds[i].fd, &value, sizeof(value) )) == sizeof(value))
+ {
+ /* We found our object. */
+ TRACE("Woken up by handle %p [%d].\n", handles[i], i);
+ return i;
+ }
+ }
+ }
+
+ /* If we got here, someone else stole (or reset, etc.) whatever
+ * we were waiting for. So keep waiting. */
+ NtQuerySystemTime( &now );
+ }
+ else if (ret == 0)
+ {
+ TRACE("Wait timed out.\n");
+ return STATUS_TIMEOUT;
+ }
+ else
+ {
+ ERR("ppoll failed: %s\n", strerror(errno));
+ return FILE_GetNtStatus();
+ }
+ }
+ }
+ else
+ {
+ FIXME("Wait-all not implemented.\n");
+ return STATUS_NOT_IMPLEMENTED;
+ }
+}
diff --git a/dlls/ntdll/esync.h b/dlls/ntdll/esync.h
index a22618de8..8f7f9b030 100644
--- a/dlls/ntdll/esync.h
+++ b/dlls/ntdll/esync.h
@@ -25,6 +25,9 @@ extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access,
const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN;
extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN;
+extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
+ BOOLEAN alertable, const LARGE_INTEGER *timeout ) 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.
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 93052ddb5..40bc619a2 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -1089,6 +1089,13 @@ static NTSTATUS wait_objects( DWORD count, const HANDLE *handles,
if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
+ if (do_esync())
+ {
+ NTSTATUS ret = esync_wait_objects( count, handles, wait_any, alertable, timeout );
+ if (ret != STATUS_NOT_IMPLEMENTED)
+ return ret;
+ }
+
if (alertable) flags |= SELECT_ALERTABLE;
select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL;
for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] );
--
2.20.1

View File

@ -0,0 +1,100 @@
From 0ab9981b2309831fb12ee778e026cb1b4651dab6 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Fri, 8 Jun 2018 15:33:46 -0500
Subject: [PATCH 08/83] ntdll: Create esync objects for events.
---
dlls/ntdll/esync.c | 34 ++++++++++++++++++++++++++++++++++
dlls/ntdll/esync.h | 2 ++
dlls/ntdll/sync.c | 3 +++
3 files changed, 39 insertions(+)
diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c
index 0950d8b5a..ace2f4a45 100644
--- a/dlls/ntdll/esync.c
+++ b/dlls/ntdll/esync.c
@@ -77,6 +77,8 @@ int do_esync(void)
enum esync_type
{
ESYNC_SEMAPHORE = 1,
+ ESYNC_AUTO_EVENT,
+ ESYNC_MANUAL_EVENT,
};
struct esync
@@ -91,6 +93,11 @@ struct semaphore
int max;
};
+struct event
+{
+ struct esync obj;
+};
+
/* We'd like lookup to be fast. To that end, we use a static list indexed by handle.
* This is copied and adapted from the fd cache code. */
@@ -248,6 +255,33 @@ NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev )
return STATUS_SUCCESS;
}
+NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access,
+ const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial )
+{
+ struct event *event;
+ NTSTATUS ret;
+ int fd;
+
+ TRACE("name %s, %s-reset, initial %d.\n",
+ attr ? debugstr_us(attr->ObjectName) : "<no name>",
+ type == NotificationEvent ? "manual" : "auto", initial);
+
+ ret = create_esync( &fd, handle, access, attr, initial, 0 );
+ if (!ret || ret == STATUS_OBJECT_NAME_EXISTS)
+ {
+ event = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*event) );
+ if (!event)
+ return STATUS_NO_MEMORY;
+
+ event->obj.type = (type == NotificationEvent ? ESYNC_MANUAL_EVENT : ESYNC_AUTO_EVENT);
+ event->obj.fd = fd;
+
+ add_to_list( *handle, &event->obj);
+ }
+
+ return ret;
+}
+
#define TICKSPERSEC 10000000
#define TICKSPERMSEC 10000
diff --git a/dlls/ntdll/esync.h b/dlls/ntdll/esync.h
index 8f7f9b030..32a259e39 100644
--- a/dlls/ntdll/esync.h
+++ b/dlls/ntdll/esync.h
@@ -24,6 +24,8 @@ extern NTSTATUS esync_close( HANDLE handle ) DECLSPEC_HIDDEN;
extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access,
const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN;
extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN;
+extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access,
+ const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN;
extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 40bc619a2..6f0e72125 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -365,6 +365,9 @@ NTSTATUS WINAPI NtCreateEvent( PHANDLE EventHandle, ACCESS_MASK DesiredAccess,
data_size_t len;
struct object_attributes *objattr;
+ if (do_esync())
+ return esync_create_event( EventHandle, DesiredAccess, attr, type, InitialState );
+
if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
SERVER_START_REQ( create_event )
--
2.20.1

View File

@ -0,0 +1,73 @@
From b3f22ae85154f22532b66362a2399592d755ce33 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Fri, 8 Jun 2018 15:41:01 -0500
Subject: [PATCH 09/83] ntdll: Implement NtSetEvent().
---
dlls/ntdll/esync.c | 21 +++++++++++++++++++++
dlls/ntdll/esync.h | 1 +
dlls/ntdll/sync.c | 4 ++++
3 files changed, 26 insertions(+)
diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c
index ace2f4a45..62c56af75 100644
--- a/dlls/ntdll/esync.c
+++ b/dlls/ntdll/esync.c
@@ -282,6 +282,27 @@ NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access,
return ret;
}
+NTSTATUS esync_set_event( HANDLE handle, LONG *prev )
+{
+ struct event *event = esync_get_object( handle );
+ static const uint64_t value = 1;
+
+ TRACE("%p.\n", handle);
+
+ if (!event) return STATUS_INVALID_HANDLE;
+
+ if (prev)
+ {
+ FIXME("Can't write previous value.\n");
+ *prev = 1;
+ }
+
+ if (write( event->obj.fd, &value, sizeof(value) ) == -1)
+ return FILE_GetNtStatus();
+
+ return STATUS_SUCCESS;
+}
+
#define TICKSPERSEC 10000000
#define TICKSPERMSEC 10000
diff --git a/dlls/ntdll/esync.h b/dlls/ntdll/esync.h
index 32a259e39..ba1c89665 100644
--- a/dlls/ntdll/esync.h
+++ b/dlls/ntdll/esync.h
@@ -26,6 +26,7 @@ extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access,
extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN;
extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access,
const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN;
+extern NTSTATUS esync_set_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN;
extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 6f0e72125..1e1e381b4 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -417,6 +417,10 @@ NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_AT
NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state )
{
NTSTATUS ret;
+
+ if (do_esync())
+ return esync_set_event( handle, prev_state );
+
SERVER_START_REQ( event_op )
{
req->handle = wine_server_obj_handle( handle );
--
2.20.1

View File

@ -0,0 +1,73 @@
From 022deba562034611dccefaf2af504861e391fe7c Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Fri, 8 Jun 2018 15:44:49 -0500
Subject: [PATCH 10/83] ntdll: Implement NtResetEvent().
---
dlls/ntdll/esync.c | 21 +++++++++++++++++++++
dlls/ntdll/esync.h | 1 +
dlls/ntdll/sync.c | 4 ++++
3 files changed, 26 insertions(+)
diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c
index 62c56af75..9e091819a 100644
--- a/dlls/ntdll/esync.c
+++ b/dlls/ntdll/esync.c
@@ -303,6 +303,27 @@ NTSTATUS esync_set_event( HANDLE handle, LONG *prev )
return STATUS_SUCCESS;
}
+NTSTATUS esync_reset_event( HANDLE handle, LONG *prev )
+{
+ struct event *event = esync_get_object( handle );
+ static uint64_t value;
+
+ TRACE("%p.\n", handle);
+
+ if (!event) return STATUS_INVALID_HANDLE;
+
+ if (prev)
+ {
+ FIXME("Can't write previous value.\n");
+ *prev = 1;
+ }
+
+ /* we don't care about the return value */
+ read( event->obj.fd, &value, sizeof(value) );
+
+ return STATUS_SUCCESS;
+}
+
#define TICKSPERSEC 10000000
#define TICKSPERMSEC 10000
diff --git a/dlls/ntdll/esync.h b/dlls/ntdll/esync.h
index ba1c89665..8d2b4683e 100644
--- a/dlls/ntdll/esync.h
+++ b/dlls/ntdll/esync.h
@@ -27,6 +27,7 @@ extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev
extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access,
const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN;
extern NTSTATUS esync_set_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN;
+extern NTSTATUS esync_reset_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN;
extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 1e1e381b4..4be641eb5 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -438,6 +438,10 @@ NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state )
NTSTATUS WINAPI NtResetEvent( HANDLE handle, LONG *prev_state )
{
NTSTATUS ret;
+
+ if (do_esync())
+ return esync_reset_event( handle, prev_state );
+
SERVER_START_REQ( event_op )
{
req->handle = wine_server_obj_handle( handle );
--
2.20.1

View File

@ -0,0 +1,76 @@
From 728fb6100bab81223baad2815878fccfe7fe17a6 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Fri, 8 Jun 2018 15:47:16 -0500
Subject: [PATCH 11/83] ntdll: Implement NtPulseEvent().
---
dlls/ntdll/esync.c | 25 +++++++++++++++++++++++++
dlls/ntdll/esync.h | 1 +
dlls/ntdll/sync.c | 3 +++
3 files changed, 29 insertions(+)
diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c
index 9e091819a..1055e11ae 100644
--- a/dlls/ntdll/esync.c
+++ b/dlls/ntdll/esync.c
@@ -324,6 +324,31 @@ NTSTATUS esync_reset_event( HANDLE handle, LONG *prev )
return STATUS_SUCCESS;
}
+NTSTATUS esync_pulse_event( HANDLE handle, LONG *prev )
+{
+ struct event *event = esync_get_object( handle );
+ static uint64_t value = 1;
+
+ TRACE("%p.\n", handle);
+
+ if (!event) return STATUS_INVALID_HANDLE;
+
+ if (prev)
+ {
+ FIXME("Can't write previous value.\n");
+ *prev = 1;
+ }
+
+ /* This isn't really correct; an application could miss the write.
+ * Unfortunately we can't really do much better. Fortunately this is rarely
+ * used (and publicly deprecated). */
+ if (write( event->obj.fd, &value, sizeof(value) ) == -1)
+ return FILE_GetNtStatus();
+ read( event->obj.fd, &value, sizeof(value) );
+
+ return STATUS_SUCCESS;
+}
+
#define TICKSPERSEC 10000000
#define TICKSPERMSEC 10000
diff --git a/dlls/ntdll/esync.h b/dlls/ntdll/esync.h
index 8d2b4683e..551257fbc 100644
--- a/dlls/ntdll/esync.h
+++ b/dlls/ntdll/esync.h
@@ -28,6 +28,7 @@ extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access,
const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN;
extern NTSTATUS esync_set_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN;
extern NTSTATUS esync_reset_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN;
+extern NTSTATUS esync_pulse_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN;
extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 4be641eb5..74b50cbc7 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -474,6 +474,9 @@ NTSTATUS WINAPI NtPulseEvent( HANDLE handle, LONG *prev_state )
{
NTSTATUS ret;
+ if (do_esync())
+ return esync_pulse_event( handle, prev_state );
+
SERVER_START_REQ( event_op )
{
req->handle = wine_server_obj_handle( handle );
--
2.20.1

View File

@ -0,0 +1,46 @@
From ba99a79e4ed4be4525e14aec71eaf52421580c32 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Fri, 8 Jun 2018 15:55:39 -0500
Subject: [PATCH 12/83] ntdll: Implement waiting on events.
More specifically, implement waiting on manual-reset events. Auto-reset events already worked.
---
dlls/ntdll/esync.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c
index 1055e11ae..7a384dc61 100644
--- a/dlls/ntdll/esync.c
+++ b/dlls/ntdll/esync.c
@@ -471,11 +471,23 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an
int64_t value;
ssize_t size;
- if ((size = read( fds[i].fd, &value, sizeof(value) )) == sizeof(value))
+ if (objs[i]->type == ESYNC_MANUAL_EVENT)
{
- /* We found our object. */
- TRACE("Woken up by handle %p [%d].\n", handles[i], i);
- return i;
+ /* Don't grab the object, just check if it's signaled. */
+ if (fds[i].revents & POLLIN)
+ {
+ TRACE("Woken up by handle %p [%d].\n", handles[i], i);
+ return i;
+ }
+ }
+ else
+ {
+ if ((size = read( fds[i].fd, &value, sizeof(value) )) == sizeof(value))
+ {
+ /* We found our object. */
+ TRACE("Woken up by handle %p [%d].\n", handles[i], i);
+ return i;
+ }
}
}
}
--
2.20.1

View File

@ -0,0 +1,64 @@
From 74d7000943e1037303294332b415b0b4b5e8291c Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Fri, 8 Jun 2018 18:55:49 -0500
Subject: [PATCH 14/83] server: Add a request to get the eventfd file
descriptor associated with a waitable handle.
---
server/esync.c | 28 ++++++++++++++++++++++++++++
server/protocol.def | 6 ++++++
2 files changed, 34 insertions(+)
diff --git a/server/esync.c b/server/esync.c
index f3a139da4..351da1a7c 100644
--- a/server/esync.c
+++ b/server/esync.c
@@ -136,3 +136,31 @@ DECL_HANDLER(create_esync)
if (root) release_object( root );
}
+
+/* Retrieve a file descriptor for an esync object which will be signaled by the
+ * server. The client should only read from (i.e. wait on) this object. */
+DECL_HANDLER(get_esync_fd)
+{
+ struct object *obj;
+ int fd;
+
+ if (!(obj = get_handle_obj( current->process, req->handle, SYNCHRONIZE, NULL )))
+ return;
+
+ if (obj->ops->get_esync_fd)
+ {
+ fd = obj->ops->get_esync_fd( obj );
+ send_client_fd( current->process, fd, req->handle );
+ }
+ else
+ {
+ if (debug_level)
+ {
+ fprintf( stderr, "%04x: esync: can't wait on object: ", current->id );
+ obj->ops->dump( obj, 0 );
+ }
+ set_error( STATUS_NOT_IMPLEMENTED );
+ }
+
+ release_object( obj );
+}
diff --git a/server/protocol.def b/server/protocol.def
index a56f098ab..5f2d77bc7 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -4051,3 +4051,9 @@ struct handle_info
@REPLY
obj_handle_t handle; /* handle to the object */
@END
+
+/* Retrieve the esync fd for an object. */
+@REQ(get_esync_fd)
+ obj_handle_t handle; /* handle to the object */
+@REPLY
+@END
--
2.20.1

View File

@ -0,0 +1,178 @@
From 4473e26d9c3177ee7a42f023fcbe48edc672f9bc Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Fri, 8 Jun 2018 18:57:12 -0500
Subject: [PATCH 15/83] server: Create eventfd file descriptors for process
objects.
---
server/esync.c | 33 +++++++++++++++++++++++++++++++++
server/esync.h | 22 ++++++++++++++++++++++
server/process.c | 17 ++++++++++++++++-
server/process.h | 1 +
4 files changed, 72 insertions(+), 1 deletion(-)
create mode 100644 server/esync.h
diff --git a/server/esync.c b/server/esync.c
index 351da1a7c..da26d27cb 100644
--- a/server/esync.c
+++ b/server/esync.c
@@ -35,6 +35,21 @@
#include "handle.h"
#include "request.h"
#include "file.h"
+#include "esync.h"
+
+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
+ return 0;
+#endif
+}
struct esync
{
@@ -112,6 +127,24 @@ struct esync *create_esync( struct object *root, const struct unicode_str *name,
#endif
}
+/* Create a file descriptor for an existing handle.
+ * Caller must close the handle when it's done; it's not linked to an esync
+ * server object in any way. */
+int esync_create_fd( int initval, int flags )
+{
+#ifdef HAVE_SYS_EVENTFD_H
+ int fd;
+
+ fd = eventfd( initval, flags | EFD_CLOEXEC | EFD_NONBLOCK );
+ if (fd == -1)
+ perror( "eventfd" );
+
+ return fd;
+#else
+ return -1;
+#endif
+}
+
DECL_HANDLER(create_esync)
{
struct esync *esync;
diff --git a/server/esync.h b/server/esync.h
new file mode 100644
index 000000000..f93535b7b
--- /dev/null
+++ b/server/esync.h
@@ -0,0 +1,22 @@
+/*
+ * 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);
+int esync_create_fd( int initval, int flags );
diff --git a/server/process.c b/server/process.c
index a96972e6b..0bb220dba 100644
--- a/server/process.c
+++ b/server/process.c
@@ -48,6 +48,7 @@
#include "request.h"
#include "user.h"
#include "security.h"
+#include "esync.h"
/* process structure */
@@ -66,6 +67,7 @@ static unsigned int process_map_access( struct object *obj, unsigned int access
static struct security_descriptor *process_get_sd( struct object *obj );
static void process_poll_event( struct fd *fd, int event );
static void process_destroy( struct object *obj );
+static int process_get_esync_fd( struct object *obj );
static void terminate_process( struct process *process, struct thread *skip, int exit_code );
static const struct object_ops process_ops =
@@ -76,7 +78,7 @@ static const struct object_ops process_ops =
add_queue, /* add_queue */
remove_queue, /* remove_queue */
process_signaled, /* signaled */
- NULL, /* get_esync_fd */
+ process_get_esync_fd, /* get_esync_fd */
no_satisfied, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
@@ -529,6 +531,7 @@ struct process *create_process( int fd, struct process *parent, int inherit_all,
process->trace_data = 0;
process->rawinput_mouse = NULL;
process->rawinput_kbd = NULL;
+ process->esync_fd = -1;
list_init( &process->thread_list );
list_init( &process->locks );
list_init( &process->asyncs );
@@ -572,6 +575,9 @@ struct process *create_process( int fd, struct process *parent, int inherit_all,
}
if (!process->handles || !process->token) goto error;
+ if (do_esync())
+ process->esync_fd = esync_create_fd( 0, 0 );
+
set_fd_events( process->msg_fd, POLLIN ); /* start listening to events */
return process;
@@ -620,6 +626,9 @@ static void process_destroy( struct object *obj )
if (process->id) free_ptid( process->id );
if (process->token) release_object( process->token );
free( process->dir_cache );
+
+ if (do_esync())
+ close( process->esync_fd );
}
/* dump a process on stdout for debugging purposes */
@@ -643,6 +652,12 @@ static int process_signaled( struct object *obj, struct wait_queue_entry *entry
return !process->running_threads;
}
+static int process_get_esync_fd( struct object *obj )
+{
+ struct process *process = (struct process *)obj;
+ return process->esync_fd;
+}
+
static unsigned int process_map_access( struct object *obj, unsigned int access )
{
if (access & GENERIC_READ) access |= STANDARD_RIGHTS_READ | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ;
diff --git a/server/process.h b/server/process.h
index ea2809194..f8fd12833 100644
--- a/server/process.h
+++ b/server/process.h
@@ -96,6 +96,7 @@ struct process
struct list rawinput_devices;/* list of registered rawinput devices */
const struct rawinput_device *rawinput_mouse; /* rawinput mouse device, if any */
const struct rawinput_device *rawinput_kbd; /* rawinput keyboard device, if any */
+ int esync_fd; /* esync file descriptor (signaled on exit) */
};
struct process_snapshot
--
2.20.1

View File

@ -0,0 +1,192 @@
From 4f6cb6b5955df87982491aed1fd23e18051d095a Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Fri, 8 Jun 2018 19:25:05 -0500
Subject: [PATCH 16/83] ntdll, server: Implement waiting on server-bound
objects.
The code here is sort of self-explanatory, but since I split it up over
several patches I'll provide a quick explanation. The basic principle is
that we can create an eventfd descriptor for any synchronizable handle, and
signal it on the server side whenever a wakeup would be triggered. This means
not only that we can wait simultaneously on esync primitives and on other
primitives, but that we can do it all in "user-mode", i.e. without having to
make a server call.
With this patch we break waiting on svcctl.exe.
---
dlls/ntdll/esync.c | 68 +++++++++++++++++++++++++++++++++++++++++++---
server/esync.c | 16 +++++++++++
server/esync.h | 1 +
server/thread.c | 4 +++
4 files changed, 85 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c
index 7a384dc61..23b03b23b 100644
--- a/dlls/ntdll/esync.c
+++ b/dlls/ntdll/esync.c
@@ -79,6 +79,7 @@ enum esync_type
ESYNC_SEMAPHORE = 1,
ESYNC_AUTO_EVENT,
ESYNC_MANUAL_EVENT,
+ ESYNC_MANUAL_SERVER,
};
struct esync
@@ -150,6 +151,63 @@ static void *esync_get_object( HANDLE handle )
return esync_list[entry][idx];
}
+/* Gets a waitable object. This is either a proper esync object (i.e. an event,
+ * semaphore, etc. created using create_esync) or a generic synchronizable
+ * server-side object which the server will signal (e.g. a process, thread,
+ * message queue, etc.) */
+static NTSTATUS get_waitable_object( HANDLE handle, struct esync **obj )
+{
+ obj_handle_t fd_handle;
+ struct esync *esync;
+ sigset_t sigset;
+ NTSTATUS ret;
+ int fd;
+
+ if ((*obj = esync_get_object( handle ))) return STATUS_SUCCESS;
+
+ /* We need to try grabbing it from the server. */
+ server_enter_uninterrupted_section( &fd_cache_section, &sigset );
+ if (!(esync = esync_get_object( handle )))
+ {
+ SERVER_START_REQ( get_esync_fd )
+ {
+ req->handle = wine_server_obj_handle( handle );
+ if (!(ret = wine_server_call( req )))
+ {
+ fd = receive_fd( &fd_handle );
+ assert( wine_server_ptr_handle(fd_handle) == handle );
+ }
+ }
+ SERVER_END_REQ;
+ }
+ server_leave_uninterrupted_section( &fd_cache_section, &sigset );
+
+ if (esync)
+ {
+ /* We managed to grab it while in the CS; return it. */
+ *obj = esync;
+ return STATUS_SUCCESS;
+ }
+
+ if (ret)
+ {
+ WARN("Failed to retrieve fd for handle %p, status %#x.\n", handle, ret);
+ *obj = NULL;
+ return ret;
+ }
+
+ TRACE("Got fd %d for handle %p.\n", fd, handle);
+
+ esync = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*esync) );
+ esync->fd = fd;
+ esync->type = ESYNC_MANUAL_SERVER;
+
+ add_to_list( handle, esync );
+
+ *obj = esync;
+ return ret;
+}
+
NTSTATUS esync_close( HANDLE handle )
{
UINT_PTR entry, idx = handle_to_index( handle, &entry );
@@ -410,11 +468,13 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an
for (i = 0; i < count; i++)
{
- objs[i] = esync_get_object( handles[i] );
- if (objs[i])
+ ret = get_waitable_object( handles[i], &objs[i] );
+ if (ret == STATUS_SUCCESS)
has_esync = 1;
- else
+ else if (ret == STATUS_NOT_IMPLEMENTED)
has_server = 1;
+ else
+ return ret;
}
if (has_esync && has_server)
@@ -471,7 +531,7 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an
int64_t value;
ssize_t size;
- if (objs[i]->type == ESYNC_MANUAL_EVENT)
+ if (objs[i]->type == ESYNC_MANUAL_EVENT || objs[i]->type == ESYNC_MANUAL_SERVER)
{
/* Don't grab the object, just check if it's signaled. */
if (fds[i].revents & POLLIN)
diff --git a/server/esync.c b/server/esync.c
index da26d27cb..96bf6a57f 100644
--- a/server/esync.c
+++ b/server/esync.c
@@ -21,6 +21,7 @@
#include "config.h"
#include "wine/port.h"
+#include <stdint.h>
#include <stdio.h>
#include <stdarg.h>
#ifdef HAVE_SYS_EVENTFD_H
@@ -145,6 +146,21 @@ int esync_create_fd( int initval, int flags )
#endif
}
+/* Wake up a server-side esync object. */
+void esync_wake_up( struct object *obj )
+{
+ static const uint64_t value = 1;
+ int fd;
+
+ if (obj->ops->get_esync_fd)
+ {
+ fd = obj->ops->get_esync_fd( obj );
+
+ if (write( fd, &value, sizeof(value) ) == -1)
+ perror( "esync: write" );
+ }
+}
+
DECL_HANDLER(create_esync)
{
struct esync *esync;
diff --git a/server/esync.h b/server/esync.h
index f93535b7b..bbfe0aef8 100644
--- a/server/esync.h
+++ b/server/esync.h
@@ -20,3 +20,4 @@
extern int do_esync(void);
int esync_create_fd( int initval, int flags );
+void esync_wake_up( struct object *obj );
diff --git a/server/thread.c b/server/thread.c
index cf401f79b..ae00c89da 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -51,6 +51,7 @@
#include "request.h"
#include "user.h"
#include "security.h"
+#include "esync.h"
#ifdef __i386__
@@ -940,6 +941,9 @@ void wake_up( struct object *obj, int max )
struct list *ptr;
int ret;
+ if (do_esync())
+ esync_wake_up( obj );
+
LIST_FOR_EACH( ptr, &obj->wait_queue )
{
struct wait_queue_entry *entry = LIST_ENTRY( ptr, struct wait_queue_entry, entry );
--
2.20.1

View File

@ -0,0 +1,144 @@
From da31b19b8edb1c270fe3735ac2f5d54132c3007c Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Fri, 8 Jun 2018 21:01:24 -0500
Subject: [PATCH 17/83] server: Create eventfd file descriptors for event
objects.
We still need this, since there are some events which the server signals.
This lets system processes shut down.
---
server/esync.c | 8 ++++++++
server/esync.h | 1 +
server/event.c | 28 ++++++++++++++++++++++++++--
3 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/server/esync.c b/server/esync.c
index 96bf6a57f..406c1a557 100644
--- a/server/esync.c
+++ b/server/esync.c
@@ -161,6 +161,14 @@ void esync_wake_up( struct object *obj )
}
}
+void esync_clear( int fd )
+{
+ uint64_t value;
+
+ /* we don't care about the return value */
+ read( fd, &value, sizeof(value) );
+}
+
DECL_HANDLER(create_esync)
{
struct esync *esync;
diff --git a/server/esync.h b/server/esync.h
index bbfe0aef8..054a77190 100644
--- a/server/esync.h
+++ b/server/esync.h
@@ -21,3 +21,4 @@
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 );
diff --git a/server/event.c b/server/event.c
index f78c12d26..12724c581 100644
--- a/server/event.c
+++ b/server/event.c
@@ -35,6 +35,7 @@
#include "thread.h"
#include "request.h"
#include "security.h"
+#include "esync.h"
struct event
{
@@ -42,15 +43,18 @@ struct event
struct list kernel_object; /* list of kernel object pointers */
int manual_reset; /* is it a manual reset event? */
int signaled; /* event has been signaled */
+ int esync_fd; /* esync file descriptor */
};
static void event_dump( struct object *obj, int verbose );
static struct object_type *event_get_type( struct object *obj );
static int event_signaled( struct object *obj, struct wait_queue_entry *entry );
static void event_satisfied( struct object *obj, struct wait_queue_entry *entry );
+static int event_get_esync_fd( struct object *obj );
static unsigned int event_map_access( struct object *obj, unsigned int access );
static int event_signal( struct object *obj, unsigned int access);
static struct list *event_get_kernel_obj_list( struct object *obj );
+static void event_destroy( struct object *obj );
static const struct object_ops event_ops =
{
@@ -60,7 +64,7 @@ static const struct object_ops event_ops =
add_queue, /* add_queue */
remove_queue, /* remove_queue */
event_signaled, /* signaled */
- NULL, /* get_esync_fd */
+ event_get_esync_fd, /* get_esync_fd */
event_satisfied, /* satisfied */
event_signal, /* signal */
no_get_fd, /* get_fd */
@@ -73,7 +77,7 @@ static const struct object_ops event_ops =
no_open_file, /* open_file */
event_get_kernel_obj_list, /* get_kernel_obj_list */
no_close_handle, /* close_handle */
- no_destroy /* destroy */
+ event_destroy /* destroy */
};
@@ -126,6 +130,9 @@ struct event *create_event( struct object *root, const struct unicode_str *name,
list_init( &event->kernel_object );
event->manual_reset = manual_reset;
event->signaled = initial_state;
+
+ if (do_esync())
+ event->esync_fd = esync_create_fd( initial_state, 0 );
}
}
return event;
@@ -154,6 +161,9 @@ void set_event( struct event *event )
void reset_event( struct event *event )
{
event->signaled = 0;
+
+ if (do_esync())
+ esync_clear( event->esync_fd );
}
static void event_dump( struct object *obj, int verbose )
@@ -177,6 +187,12 @@ static int event_signaled( struct object *obj, struct wait_queue_entry *entry )
return event->signaled;
}
+static int event_get_esync_fd( struct object *obj )
+{
+ struct event *event = (struct event *)obj;
+ return event->esync_fd;
+}
+
static void event_satisfied( struct object *obj, struct wait_queue_entry *entry )
{
struct event *event = (struct event *)obj;
@@ -214,6 +230,14 @@ static struct list *event_get_kernel_obj_list( struct object *obj )
return &event->kernel_object;
}
+static void event_destroy( struct object *obj )
+{
+ struct event *event = (struct event *)obj;
+
+ if (do_esync())
+ close( event->esync_fd );
+}
+
struct keyed_event *create_keyed_event( struct object *root, const struct unicode_str *name,
unsigned int attr, const struct security_descriptor *sd )
{
--
2.20.1

View File

@ -0,0 +1,117 @@
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

View File

@ -0,0 +1,69 @@
From fe2e94200cfb6a88e82b9261f2d8a05a6fae0cbe Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Fri, 8 Jun 2018 21:58:37 -0500
Subject: [PATCH 19/83] ntdll: Try again if poll() returns EINTR.
I originally had this return STATUS_USER_APC, but that isn't correct. The
server code here is a bit confusing, but only the thread that waits *during*
the suspend should receive STATUS_USER_APC (and I imagine that it really
should receive STATUS_KERNEL_APC instead). The thread that is suspended
should just keep on waiting.
Besides, we could be suspended for reasons other than to deliver a system
APC.
---
dlls/ntdll/esync.c | 32 +++++++++++++++++++++-----------
1 file changed, 21 insertions(+), 11 deletions(-)
diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c
index 23b03b23b..0655ab779 100644
--- a/dlls/ntdll/esync.c
+++ b/dlls/ntdll/esync.c
@@ -423,22 +423,32 @@ static LONGLONG update_timeout( ULONGLONG end )
static int do_poll( struct pollfd *fds, nfds_t nfds, ULONGLONG *end )
{
- if (end)
+ int ret;
+
+ do
{
- LONGLONG timeleft = update_timeout( *end );
+ if (end)
+ {
+ LONGLONG timeleft = update_timeout( *end );
#ifdef HAVE_PPOLL
- /* We use ppoll() if available since the time granularity is better. */
- struct timespec tmo_p;
- tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC;
- tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100;
- return ppoll( fds, nfds, &tmo_p, NULL );
+ /* We use ppoll() if available since the time granularity is better. */
+ struct timespec tmo_p;
+ tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC;
+ tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100;
+ ret = ppoll( fds, nfds, &tmo_p, NULL );
#else
- return poll( fds, nfds, timeleft / TICKSPERMSEC );
+ ret = poll( fds, nfds, timeleft / TICKSPERMSEC );
#endif
- }
- else
- return poll( fds, nfds, -1 );
+ }
+ else
+ ret = poll( fds, nfds, -1 );
+
+ /* If we receive EINTR we were probably suspended (SIGUSR1), possibly for a
+ * system APC. The right thing to do is just try again. */
+ } while (ret < 0 && errno == EINTR);
+
+ return ret;
}
/* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we
--
2.20.1

View File

@ -0,0 +1,88 @@
From 69c158267facd8919329e71e082e872031ee4054 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Fri, 8 Jun 2018 22:04:29 -0500
Subject: [PATCH 20/83] server: Create eventfd file descriptors for thread
objects.
---
server/thread.c | 16 +++++++++++++++-
server/thread.h | 1 +
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/server/thread.c b/server/thread.c
index ae00c89da..e82d71f67 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -133,6 +133,7 @@ static const struct object_ops thread_apc_ops =
static void dump_thread( struct object *obj, int verbose );
static struct object_type *thread_get_type( struct object *obj );
static int thread_signaled( struct object *obj, struct wait_queue_entry *entry );
+static int thread_get_esync_fd( struct object *obj );
static unsigned int thread_map_access( struct object *obj, unsigned int access );
static void thread_poll_event( struct fd *fd, int event );
static void destroy_thread( struct object *obj );
@@ -145,7 +146,7 @@ static const struct object_ops thread_ops =
add_queue, /* add_queue */
remove_queue, /* remove_queue */
thread_signaled, /* signaled */
- NULL, /* get_esync_fd */
+ thread_get_esync_fd, /* get_esync_fd */
no_satisfied, /* satisfied */
no_signal, /* signal */
no_get_fd, /* get_fd */
@@ -185,6 +186,7 @@ static inline void init_thread_structure( struct thread *thread )
thread->suspend_context = NULL;
thread->teb = 0;
thread->entry_point = 0;
+ thread->esync_fd = -1;
thread->debug_ctx = NULL;
thread->debug_event = NULL;
thread->debug_break = 0;
@@ -292,6 +294,9 @@ struct thread *create_thread( int fd, struct process *process, const struct secu
return NULL;
}
+ if (do_esync())
+ thread->esync_fd = esync_create_fd( 0, 0 );
+
set_fd_events( thread->request_fd, POLLIN ); /* start listening to events */
add_process_thread( thread->process, thread );
return thread;
@@ -364,6 +369,9 @@ static void destroy_thread( struct object *obj )
if (thread->exit_poll) remove_timeout_user( thread->exit_poll );
if (thread->id) free_ptid( thread->id );
if (thread->token) release_object( thread->token );
+
+ if (do_esync())
+ close( thread->esync_fd );
}
/* dump a thread on stdout for debugging purposes */
@@ -388,6 +396,12 @@ static int thread_signaled( struct object *obj, struct wait_queue_entry *entry )
return mythread->state == TERMINATED && !mythread->exit_poll;
}
+static int thread_get_esync_fd( struct object *obj )
+{
+ struct thread *thread = (struct thread *)obj;
+ return thread->esync_fd;
+}
+
static unsigned int thread_map_access( struct object *obj, unsigned int access )
{
if (access & GENERIC_READ) access |= STANDARD_RIGHTS_READ | THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT;
diff --git a/server/thread.h b/server/thread.h
index bfd818ce2..4913577f7 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -54,6 +54,7 @@ struct thread
struct process *process;
thread_id_t id; /* thread id */
struct list mutex_list; /* list of currently owned mutexes */
+ int esync_fd; /* esync file descriptor (signalled on exit) */
struct debug_ctx *debug_ctx; /* debugger context if this thread is a debugger */
struct debug_event *debug_event; /* debug event being sent to debugger */
int debug_break; /* debug breakpoint pending? */
--
2.20.1

Some files were not shown because too many files have changed in this diff Show More