[PATCH v5 1/2] ntdll: Cancel asyncs when thread is terminated.

Paul Gofman wine at gitlab.winehq.org
Wed Jun 8 17:40:24 CDT 2022


From: Paul Gofman <pgofman at codeweavers.com>

Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 dlls/ntdll/unix/thread.c | 24 +++++++++++++-----------
 server/async.c           | 16 ++++++++++++++++
 server/file.h            |  1 +
 server/thread.c          |  1 +
 4 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c
index 15bb3be34b2..ad47a5fce74 100644
--- a/dlls/ntdll/unix/thread.c
+++ b/dlls/ntdll/unix/thread.c
@@ -1610,20 +1610,22 @@ NTSTATUS WINAPI NtAlertThread( HANDLE handle )
 NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
 {
     NTSTATUS ret;
-    BOOL self = (handle == GetCurrentThread());
+    BOOL self;
 
-    if (!self || exit_code)
+    SERVER_START_REQ( terminate_thread )
     {
-        SERVER_START_REQ( terminate_thread )
-        {
-            req->handle    = wine_server_obj_handle( handle );
-            req->exit_code = exit_code;
-            ret = wine_server_call( req );
-            self = !ret && reply->self;
-        }
-        SERVER_END_REQ;
+        req->handle    = wine_server_obj_handle( handle );
+        req->exit_code = exit_code;
+        ret = wine_server_call( req );
+        self = !ret && reply->self;
+    }
+    SERVER_END_REQ;
+
+    if (self)
+    {
+        server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, NULL, NULL );
+        exit_thread( exit_code );
     }
-    if (self) exit_thread( exit_code );
     return ret;
 }
 
diff --git a/server/async.c b/server/async.c
index a4fbeab555e..4832d69b7bf 100644
--- a/server/async.c
+++ b/server/async.c
@@ -593,6 +593,22 @@ void cancel_process_asyncs( struct process *process )
     cancel_async( process, NULL, NULL, 0 );
 }
 
+void cancel_terminating_thread_asyncs( struct thread *thread )
+{
+    struct async *async;
+
+restart:
+    LIST_FOR_EACH_ENTRY( async, &thread->process->asyncs, struct async, process_entry )
+    {
+        if (async->thread != thread || async->terminated || async->canceled) continue;
+        if (async->completion && async->data.apc_context && !async->event) continue;
+
+        async->canceled = 1;
+        fd_cancel_async( async->fd, async );
+        goto restart;
+    }
+}
+
 /* wake up async operations on the queue */
 void async_wake_up( struct async_queue *queue, unsigned int status )
 {
diff --git a/server/file.h b/server/file.h
index 9f9d4cd4e1a..0ffe0e2c8dc 100644
--- a/server/file.h
+++ b/server/file.h
@@ -245,6 +245,7 @@ extern struct iosb *async_get_iosb( struct async *async );
 extern struct thread *async_get_thread( struct async *async );
 extern struct async *find_pending_async( struct async_queue *queue );
 extern void cancel_process_asyncs( struct process *process );
+extern void cancel_terminating_thread_asyncs( struct thread *thread );
 
 static inline void init_async_queue( struct async_queue *queue )
 {
diff --git a/server/thread.c b/server/thread.c
index 467ccd1f0db..f49fbf40b78 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -1462,6 +1462,7 @@ DECL_HANDLER(terminate_thread)
         thread->exit_code = req->exit_code;
         if (thread != current) kill_thread( thread, 1 );
         else reply->self = 1;
+        cancel_terminating_thread_asyncs( thread );
         release_object( thread );
     }
 }
-- 
GitLab


https://gitlab.winehq.org/wine/wine/-/merge_requests/135



More information about the wine-devel mailing list