eventfd_synchronization: Abandon esync mutexes on thread exit.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48089
This commit is contained in:
Zebediah Figura 2020-02-17 17:37:50 -06:00
parent ede44e4e8f
commit 8b2fd051c9
2 changed files with 199 additions and 0 deletions

View File

@ -0,0 +1,197 @@
From c00917721a5076b90e3e61a7d326ef485c1f9dfb Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Mon, 17 Feb 2020 11:28:37 -0600
Subject: [PATCH] ntdll, server: Abandon esync mutexes on thread exit.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
---
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

View File

@ -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