[PATCH 2/4] server: Abandon wait when completion port is closed.

Paul Gofman pgofman at codeweavers.com
Tue Dec 7 04:59:15 CST 2021


Based on patches by Alexey Prokhin.

Signed-off-by: Paul Gofman <pgofman at 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;
-- 
2.33.1




More information about the wine-devel mailing list