[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