diff --git a/patches/eventfd_synchronization/0089-ntdll-server-Abandon-esync-mutexes-on-thread-exit.patch b/patches/eventfd_synchronization/0089-ntdll-server-Abandon-esync-mutexes-on-thread-exit.patch new file mode 100644 index 00000000..d6085595 --- /dev/null +++ b/patches/eventfd_synchronization/0089-ntdll-server-Abandon-esync-mutexes-on-thread-exit.patch @@ -0,0 +1,197 @@ +From c00917721a5076b90e3e61a7d326ef485c1f9dfb Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 17 Feb 2020 11:28:37 -0600 +Subject: [PATCH] ntdll, server: Abandon esync mutexes on thread exit. + +Signed-off-by: Zebediah Figura +--- + dlls/ntdll/esync.c | 31 ++++++++++++++++++++++++++----- + server/esync.c | 32 +++++++++++++++++++++++++++++--- + server/esync.h | 1 + + server/thread.c | 2 ++ + 4 files changed, 58 insertions(+), 8 deletions(-) + +diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c +index 87f303403..c2190f2fd 100644 +--- a/dlls/ntdll/esync.c ++++ b/dlls/ntdll/esync.c +@@ -807,7 +807,7 @@ NTSTATUS esync_query_mutex( HANDLE handle, MUTANT_INFORMATION_CLASS class, + + out->CurrentCount = 1 - mutex->count; + out->OwnedByCaller = (mutex->tid == GetCurrentThreadId()); +- out->AbandonedState = FALSE; ++ out->AbandonedState = (mutex->tid == ~0); + if (ret_len) *ret_len = sizeof(*out); + + return STATUS_SUCCESS; +@@ -857,14 +857,19 @@ static int do_poll( struct pollfd *fds, nfds_t nfds, ULONGLONG *end ) + return ret; + } + +-static void update_grabbed_object( struct esync *obj ) ++/* Return TRUE if abandoned. */ ++static BOOL update_grabbed_object( struct esync *obj ) + { ++ BOOL ret = FALSE; ++ + if (obj->type == ESYNC_MUTEX) + { + struct mutex *mutex = obj->shm; + /* We don't have to worry about a race between this and read(); the + * fact that we grabbed it means the count is now zero, so nobody else + * can (and the only thread that can release it is us). */ ++ if (mutex->tid == ~0) ++ ret = TRUE; + mutex->tid = GetCurrentThreadId(); + mutex->count++; + } +@@ -885,6 +890,8 @@ static void update_grabbed_object( struct esync *obj ) + * This might already be 0, but that's okay! */ + event->signaled = 0; + } ++ ++ return ret; + } + + /* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we +@@ -1018,7 +1025,13 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, + { + if ((size = read( obj->fd, &value, sizeof(value) )) == sizeof(value)) + { +- TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ if (mutex->tid == ~0) ++ { ++ TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i); ++ i += STATUS_ABANDONED_WAIT_0; ++ } ++ else ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->tid = GetCurrentThreadId(); + mutex->count++; + return i; +@@ -1136,7 +1149,8 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, + { + /* We found our object. */ + TRACE("Woken up by handle %p [%d].\n", handles[i], i); +- update_grabbed_object( obj ); ++ if (update_grabbed_object( obj )) ++ return STATUS_ABANDONED_WAIT_0 + i; + return i; + } + } +@@ -1255,6 +1269,8 @@ tryagain: + ret = poll( fds, pollcount, 0 ); + if (ret == pollcount) + { ++ BOOL abandoned = FALSE; ++ + /* Quick, grab everything. */ + for (i = 0; i < pollcount; i++) + { +@@ -1295,8 +1311,13 @@ tryagain: + /* Make sure to let ourselves know that we grabbed the mutexes + * and semaphores. */ + for (i = 0; i < count; i++) +- update_grabbed_object( objs[i] ); ++ abandoned |= update_grabbed_object( objs[i] ); + ++ if (abandoned) ++ { ++ TRACE("Wait successful, but some object(s) were abandoned.\n"); ++ return STATUS_ABANDONED; ++ } + TRACE("Wait successful.\n"); + return STATUS_SUCCESS; + } +diff --git a/server/esync.c b/server/esync.c +index 040e24e69..1b035bdb0 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -104,12 +104,15 @@ void esync_init(void) + atexit( shm_cleanup ); + } + ++static struct list mutex_list = LIST_INIT(mutex_list); ++ + struct esync + { +- struct object obj; /* object header */ +- int fd; /* eventfd file descriptor */ ++ struct object obj; /* object header */ ++ int fd; /* eventfd file descriptor */ + enum esync_type type; +- unsigned int shm_idx; /* index into the shared memory section */ ++ unsigned int shm_idx; /* index into the shared memory section */ ++ struct list mutex_entry; /* entry in the mutex list (if applicable) */ + }; + + static void esync_dump( struct object *obj, int verbose ); +@@ -168,6 +171,8 @@ static unsigned int esync_map_access( struct object *obj, unsigned int access ) + static void esync_destroy( struct object *obj ) + { + struct esync *esync = (struct esync *)obj; ++ if (esync->type == ESYNC_MUTEX) ++ list_remove( &esync->mutex_entry ); + close( esync->fd ); + } + +@@ -301,6 +306,7 @@ static struct esync *create_esync( struct object *root, const struct unicode_str + struct mutex *mutex = get_shm( esync->shm_idx ); + mutex->tid = initval ? 0 : current->id; + mutex->count = initval ? 0 : 1; ++ list_add_tail( &mutex_list, &esync->mutex_entry ); + break; + } + default: +@@ -447,6 +453,26 @@ void esync_reset_event( struct esync *esync ) + } + } + ++void esync_abandon_mutexes( struct thread *thread ) ++{ ++ unsigned int index = 0; ++ struct esync *esync; ++ ++ LIST_FOR_EACH_ENTRY( esync, &mutex_list, struct esync, mutex_entry ) ++ { ++ struct mutex *mutex = get_shm( esync->shm_idx ); ++ ++ if (mutex->tid == thread->id) ++ { ++ if (debug_level) ++ fprintf( stderr, "esync_abandon_mutexes() fd=%d\n", esync->fd ); ++ mutex->tid = ~0; ++ mutex->count = 0; ++ esync_wake_fd( esync->fd ); ++ } ++ } ++} ++ + DECL_HANDLER(create_esync) + { + struct esync *esync; +diff --git a/server/esync.h b/server/esync.h +index cea025d93..125da8e9d 100644 +--- a/server/esync.h ++++ b/server/esync.h +@@ -30,3 +30,4 @@ struct esync; + extern const struct object_ops esync_ops; + void esync_set_event( struct esync *esync ); + void esync_reset_event( struct esync *esync ); ++void esync_abandon_mutexes( struct thread *thread ); +diff --git a/server/thread.c b/server/thread.c +index d1923b4e8..1d5bca525 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -1253,6 +1253,8 @@ void kill_thread( struct thread *thread, int violent_death ) + kill_console_processes( thread, 0 ); + debug_exit_thread( thread ); + abandon_mutexes( thread ); ++ if (do_esync()) ++ esync_abandon_mutexes( thread ); + if (violent_death) + { + send_thread_signal( thread, SIGQUIT ); +-- +2.25.0 + diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index a503b53f..9bbeb999 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -3703,6 +3703,7 @@ if test "$enable_eventfd_synchronization" -eq 1; then patch_apply eventfd_synchronization/0086-ntdll-Check-the-APC-fd-first.patch patch_apply eventfd_synchronization/0087-ntdll-esync-Lock-accessing-the-shm_addrs-array.patch patch_apply eventfd_synchronization/0088-ntdll-Get-rid-of-the-per-event-spinlock-for-auto-res.patch + patch_apply eventfd_synchronization/0089-ntdll-server-Abandon-esync-mutexes-on-thread-exit.patch ( printf '%s\n' '+ { "Zebediah Figura", "configure: Check for sys/eventfd.h, ppoll(), and shm_open().", 1 },'; printf '%s\n' '+ { "Zebediah Figura", "server: Create server objects for eventfd-based synchronization objects.", 1 },'; @@ -3792,6 +3793,7 @@ if test "$enable_eventfd_synchronization" -eq 1; then printf '%s\n' '+ { "Zebediah Figura", "ntdll: Check the APC fd first.", 1 },'; printf '%s\n' '+ { "Zebediah Figura", "ntdll/esync: Lock accessing the shm_addrs array.", 1 },'; printf '%s\n' '+ { "Zebediah Figura", "ntdll: Get rid of the per-event spinlock for auto-reset events.", 1 },'; + printf '%s\n' '+ { "Zebediah Figura", "ntdll, server: Abandon esync mutexes on thread exit.", 1 },'; ) >> "$patchlist" fi