Based on patches by Alexey Prokhin.
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/tests/sync.c | 65 +++++++++++++++++++++++++++++++++++++++++ server/completion.c | 25 ++++++++++++---- 2 files changed, 85 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/tests/sync.c b/dlls/ntdll/tests/sync.c index f930767a8b0..562df0f66b0 100644 --- a/dlls/ntdll/tests/sync.c +++ b/dlls/ntdll/tests/sync.c @@ -837,6 +837,70 @@ static void test_tid_alert( char **argv ) CloseHandle( pi.hThread ); }
+static HANDLE test_close_io_completion_port_ready, test_close_io_completion_test_ready; +static HANDLE test_close_io_completion_port; + +static DWORD WINAPI test_close_io_completion_thread(void *param) +{ + FILE_IO_COMPLETION_INFORMATION info; + IO_STATUS_BLOCK iosb; + ULONG_PTR key, value; + NTSTATUS status; + ULONG count; + DWORD ret; + + ret = WaitForSingleObject( test_close_io_completion_port_ready, INFINITE ); + ok( ret == WAIT_OBJECT_0, "Got unexpected ret %#x.\n", ret ); + SetEvent( test_close_io_completion_test_ready ); + status = NtRemoveIoCompletion( test_close_io_completion_port, &key, &value, &iosb, NULL ); + if (status == STATUS_INVALID_HANDLE) + skip( "Handle closed before wait started.\n" ); + else + ok( status == STATUS_ABANDONED_WAIT_0, "Got unexpected status %#x.\n", status ); + + ret = WaitForSingleObject( test_close_io_completion_port_ready, INFINITE ); + ok( ret == WAIT_OBJECT_0, "Got unexpected ret %#x.\n", ret ); + SetEvent( test_close_io_completion_test_ready ); + count = 0xdeadbeef; + status = NtRemoveIoCompletionEx( test_close_io_completion_port, &info, 1, &count, NULL, FALSE ); + ok( count == 1, "Got unexpected count %u.\n", count ); + if (status == STATUS_INVALID_HANDLE) + skip( "Handle closed before wait started.\n" ); + else + ok( status == STATUS_ABANDONED_WAIT_0, "Got unexpected status %#x.\n", status ); + + return 0; +} + +static void test_close_io_completion(void) +{ + NTSTATUS status; + unsigned int i; + HANDLE thread; + DWORD ret; + + test_close_io_completion_port_ready = CreateEventA(NULL, FALSE, FALSE, NULL); + test_close_io_completion_test_ready = CreateEventA(NULL, FALSE, FALSE, NULL); + + thread = CreateThread( NULL, 0, test_close_io_completion_thread, NULL, 0, NULL ); + ok( !!thread, "Failed to create thread, error %u.\n", GetLastError() ); + + for (i = 0; i < 2; ++i) + { + status = NtCreateIoCompletion( &test_close_io_completion_port, IO_COMPLETION_ALL_ACCESS, NULL, 0 ); + ok( !status, "Got unexpected status %#x.\n", status ); + ret = SignalObjectAndWait( test_close_io_completion_port_ready, test_close_io_completion_test_ready, + INFINITE, FALSE ); + ok( ret == WAIT_OBJECT_0, "Got unexpected ret %#x.\n", ret ); + Sleep(10); + status = pNtClose( test_close_io_completion_port ); + ok( !status, "Got unexpected status %#x.\n", status ); + } + + WaitForSingleObject( thread, INFINITE ); + CloseHandle( thread ); +} + START_TEST(sync) { HMODULE module = GetModuleHandleA("ntdll.dll"); @@ -884,4 +948,5 @@ START_TEST(sync) test_keyed_events(); test_resource(); test_tid_alert( argv ); + test_close_io_completion(); } diff --git a/server/completion.c b/server/completion.c index 8dd8d4b1247..27a7f3e3e50 100644 --- a/server/completion.c +++ b/server/completion.c @@ -56,11 +56,14 @@ struct type_descr completion_type = }, };
+struct completion; + struct completion_wait { - struct object obj; - struct list queue; - unsigned int depth; + struct object obj; + struct completion *completion; + struct list queue; + unsigned int depth; };
struct completion @@ -71,6 +74,7 @@ struct completion
static void completion_wait_dump( struct object*, int ); static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ); +static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ); static void completion_wait_destroy( struct object * );
static const struct object_ops completion_wait_ops = @@ -81,7 +85,7 @@ static const struct object_ops completion_wait_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ completion_wait_signaled, /* signaled */ - no_satisfied, /* satisfied */ + completion_wait_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ default_map_access, /* map_access */ @@ -159,7 +163,15 @@ static int completion_wait_signaled( struct object *obj, struct wait_queue_entry struct completion_wait *wait = (struct completion_wait *)obj;
assert( obj->ops == &completion_wait_ops ); - return !list_empty( &wait->queue ); + return !wait->completion || !list_empty( &wait->queue ); +} + +static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ) +{ + struct completion_wait *wait = (struct completion_wait *)obj; + + assert( obj->ops == &completion_wait_ops ); + if (!wait->completion) make_wait_abandoned( entry ); }
static void completion_dump( struct object *obj, int verbose ) @@ -191,6 +203,8 @@ static void completion_destroy( struct object *obj ) struct completion *completion = (struct completion *)obj;
assert( obj->ops == &completion_ops ); + completion->wait->completion = NULL; + wake_up( &completion->wait->obj, 0 ); release_object( &completion->wait->obj ); }
@@ -209,6 +223,7 @@ static struct completion *create_completion( struct object *root, const struct u return NULL; }
+ completion->wait->completion = completion; list_init( &completion->wait->queue ); completion->wait->depth = 0; return completion;