From: Paul Gofman pgofman@codeweavers.com
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/unix/thread.c | 6 +++++- dlls/ws2_32/tests/afd.c | 38 ++++++++++++++++---------------------- server/async.c | 19 ++++++++++++++----- server/file.h | 1 + server/thread.c | 14 ++++++++------ server/thread.h | 3 ++- server/timer.c | 2 +- 7 files changed, 47 insertions(+), 36 deletions(-)
diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 15bb3be34b2..c202897f172 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1623,7 +1623,11 @@ NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code ) } SERVER_END_REQ; } - if (self) exit_thread( exit_code ); + if (self) + { + server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, NULL, NULL ); + exit_thread( exit_code ); + } return ret; }
diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index b8579a7c9f7..de042358297 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -2453,16 +2453,16 @@ static void test_async_thread_termination(void) IOCTL_AFD_POLL, in_params, params_size, out_params, params_size); ok(ret == STATUS_PENDING, "got %#x\n", ret); ret = WaitForSingleObject(event, 1000); - todo_wine ok(!ret, "got %#x\n", ret); - todo_wine ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status); + ok(!ret, "got %#x\n", ret); + ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status);
memset(&io, 0xcc, sizeof(io)); ret = thread_NtDeviceIoControlFile(FALSE, (HANDLE)listener, event, NULL, NULL, &io, IOCTL_AFD_POLL, in_params, params_size, out_params, params_size); ok(ret == STATUS_PENDING, "got %#x\n", ret); ret = WaitForSingleObject(event, 1000); - todo_wine ok(!ret, "got %#x\n", ret); - todo_wine ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status); + ok(!ret, "got %#x\n", ret); + ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status);
port = CreateIoCompletionPort((HANDLE)listener, NULL, 0, 0);
@@ -2472,20 +2472,17 @@ static void test_async_thread_termination(void) ok(ret == STATUS_PENDING, "got %#x\n", ret);
ret = WaitForSingleObject(event, 1000); - todo_wine ok(!ret, "got %#x\n", ret); - todo_wine ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status); + ok(!ret, "got %#x\n", ret); + ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status);
memset(&io, 0xcc, sizeof(io)); key = 0xcc; value = 0; ret = NtRemoveIoCompletion(port, &key, &value, &io, &zero); - todo_wine - { - ok(!ret, "got %#x\n", ret); - ok(!key, "got key %#Ix\n", key); - ok(value == 0xdeadbeef, "got value %#Ix\n", value); - ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status); - } + ok(!ret, "got %#x\n", ret); + ok(!key, "got key %#Ix\n", key); + ok(value == 0xdeadbeef, "got value %#Ix\n", value); + ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status);
memset(&io, 0xcc, sizeof(io)); ret = thread_NtDeviceIoControlFile(FALSE, (HANDLE)listener, event, NULL, (void *)0xdeadbeef, &io, @@ -2493,20 +2490,17 @@ static void test_async_thread_termination(void) ok(ret == STATUS_PENDING, "got %#x\n", ret);
ret = WaitForSingleObject(event, 1000); - todo_wine ok(!ret, "got %#x\n", ret); - todo_wine ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status); + ok(!ret, "got %#x\n", ret); + ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status);
memset(&io, 0xcc, sizeof(io)); key = 0xcc; value = 0; ret = NtRemoveIoCompletion(port, &key, &value, &io, &zero); - todo_wine - { - ok(!ret, "got %#x\n", ret); - ok(!key, "got key %#Ix\n", key); - ok(value == 0xdeadbeef, "got value %#Ix\n", value); - ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status); - } + ok(!ret, "got %#x\n", ret); + ok(!key, "got key %#Ix\n", key); + ok(value == 0xdeadbeef, "got value %#Ix\n", value); + ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status);
CloseHandle(port); CloseHandle(event); diff --git a/server/async.c b/server/async.c index a4fbeab555e..46a7b06a0dd 100644 --- a/server/async.c +++ b/server/async.c @@ -62,6 +62,7 @@ struct async unsigned int comp_flags; /* completion flags */ async_completion_callback completion_callback; /* callback to be called on completion */ void *completion_callback_private; /* argument to completion_callback */ + int thread_terminating; /* async is being canceled due to thread termination */ };
static void async_dump( struct object *obj, int verbose ); @@ -202,7 +203,7 @@ void async_terminate( struct async *async, unsigned int status ) else data.async_io.status = status;
- thread_queue_apc( async->thread->process, async->thread, &async->obj, &data ); + thread_queue_apc( async->thread->process, async->thread, &async->obj, &data, async->thread_terminating ); }
async_reselect( async ); @@ -281,6 +282,7 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da async->comp_flags = 0; async->completion_callback = NULL; async->completion_callback_private = NULL; + async->thread_terminating = 0;
if (iosb) async->iosb = (struct iosb *)grab_object( iosb ); else async->iosb = NULL; @@ -520,7 +522,7 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota data.user.args[0] = async->data.apc_context; data.user.args[1] = async->data.iosb; data.user.args[2] = 0; - thread_queue_apc( NULL, async->thread, NULL, &data ); + thread_queue_apc( NULL, async->thread, NULL, &data, 0 ); } else if (async->data.apc_context && (async->pending || !(async->comp_flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS))) @@ -562,7 +564,8 @@ int async_waiting( struct async_queue *queue ) return !async->terminated; }
-static int cancel_async( struct process *process, struct object *obj, struct thread *thread, client_ptr_t iosb ) +static int cancel_async( struct process *process, struct object *obj, struct thread *thread, client_ptr_t iosb, + int thread_terminating ) { struct async *async; int woken = 0; @@ -580,6 +583,7 @@ restart: (!iosb || async->data.iosb == iosb)) { async->canceled = 1; + async->thread_terminating = thread_terminating; fd_cancel_async( async->fd, async ); woken++; goto restart; @@ -590,7 +594,12 @@ restart:
void cancel_process_asyncs( struct process *process ) { - cancel_async( process, NULL, NULL, 0 ); + cancel_async( process, NULL, NULL, 0, 0 ); +} + +void cancel_terminating_thread_asyncs( struct thread *thread ) +{ + cancel_async( thread->process, NULL, thread, 0, 1 ); }
/* wake up async operations on the queue */ @@ -723,7 +732,7 @@ DECL_HANDLER(cancel_async)
if (obj) { - int count = cancel_async( current->process, obj, thread, req->iosb ); + int count = cancel_async( current->process, obj, thread, req->iosb, 0 ); if (!count && req->iosb) set_error( STATUS_NOT_FOUND ); release_object( obj ); } 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..e7c0f294c55 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1094,7 +1094,7 @@ static inline int is_in_apc_wait( struct thread *thread ) }
/* queue an existing APC to a given thread */ -static int queue_apc( struct process *process, struct thread *thread, struct thread_apc *apc ) +static int queue_apc( struct process *process, struct thread *thread, struct thread_apc *apc, int queue_only ) { struct list *queue;
@@ -1135,7 +1135,7 @@ static int queue_apc( struct process *process, struct thread *thread, struct thr if (thread->state == TERMINATED) return 0; if (!(queue = get_apc_queue( thread, apc->call.type ))) return 1; /* send signal for system APCs if needed */ - if (queue == &thread->system_apc && list_empty( queue ) && !is_in_apc_wait( thread )) + if (!queue_only && queue == &thread->system_apc && list_empty( queue ) && !is_in_apc_wait( thread )) { if (!send_thread_signal( thread, SIGUSR1 )) return 0; } @@ -1152,14 +1152,15 @@ static int queue_apc( struct process *process, struct thread *thread, struct thr }
/* queue an async procedure call */ -int thread_queue_apc( struct process *process, struct thread *thread, struct object *owner, const apc_call_t *call_data ) +int thread_queue_apc( struct process *process, struct thread *thread, struct object *owner, + const apc_call_t *call_data, int queue_only ) { struct thread_apc *apc; int ret = 0;
if ((apc = create_apc( owner, call_data ))) { - ret = queue_apc( process, thread, apc ); + ret = queue_apc( process, thread, apc, queue_only ); release_object( apc ); } return ret; @@ -1462,6 +1463,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 ); } } @@ -1761,7 +1763,7 @@ DECL_HANDLER(queue_apc)
if (thread) { - if (!queue_apc( NULL, thread, apc )) set_error( STATUS_UNSUCCESSFUL ); + if (!queue_apc( NULL, thread, apc, 0 )) set_error( STATUS_UNSUCCESSFUL ); release_object( thread ); } else if (process) @@ -1772,7 +1774,7 @@ DECL_HANDLER(queue_apc) obj_handle_t handle = alloc_handle( current->process, apc, SYNCHRONIZE, 0 ); if (handle) { - if (queue_apc( process, NULL, apc )) + if (queue_apc( process, NULL, apc, 0 )) { apc->caller = (struct thread *)grab_object( current ); reply->handle = handle; diff --git a/server/thread.h b/server/thread.h index 8dcf966a90a..9c84c5133b9 100644 --- a/server/thread.h +++ b/server/thread.h @@ -114,7 +114,8 @@ extern int add_queue( struct object *obj, struct wait_queue_entry *entry ); extern void remove_queue( struct object *obj, struct wait_queue_entry *entry ); extern void kill_thread( struct thread *thread, int violent_death ); extern void wake_up( struct object *obj, int max ); -extern int thread_queue_apc( struct process *process, struct thread *thread, struct object *owner, const apc_call_t *call_data ); +extern int thread_queue_apc( struct process *process, struct thread *thread, struct object *owner, + const apc_call_t *call_data, int queue_only ); extern void thread_cancel_apc( struct thread *thread, struct object *owner, enum apc_type type ); extern int thread_add_inflight_fd( struct thread *thread, int client, int server ); extern int thread_get_inflight_fd( struct thread *thread, int client ); diff --git a/server/timer.c b/server/timer.c index 96dc9d00ca1..98a340c789f 100644 --- a/server/timer.c +++ b/server/timer.c @@ -133,7 +133,7 @@ static void timer_callback( void *private ) data.user.args[1] = (unsigned int)timer->when; data.user.args[2] = timer->when >> 32;
- if (!thread_queue_apc( NULL, timer->thread, &timer->obj, &data )) + if (!thread_queue_apc( NULL, timer->thread, &timer->obj, &data, 0 )) { release_object( timer->thread ); timer->thread = NULL;