[PATCH v3 1/2] ws2_32/tests: Add tests for terminated thread asyncs completion.
Paul Gofman
wine at gitlab.winehq.org
Fri Jun 3 15:12:06 CDT 2022
From: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
dlls/ws2_32/tests/afd.c | 159 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 159 insertions(+)
diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c
index 5b64ccd7715..b8579a7c9f7 100644
--- a/dlls/ws2_32/tests/afd.c
+++ b/dlls/ws2_32/tests/afd.c
@@ -2355,6 +2355,164 @@ static void test_getsockname(void)
CloseHandle(event);
}
+struct ioctl_params
+{
+ HANDLE handle, event;
+ PIO_APC_ROUTINE apc;
+ void *apc_context;
+ IO_STATUS_BLOCK *io;
+ ULONG code;
+ void *in_buffer;
+ ULONG in_size;
+ void *out_buffer;
+ ULONG out_size;
+ NTSTATUS ret;
+ HANDLE complete_event;
+ BOOL kill_thread;
+};
+
+static DWORD WINAPI async_ioctl_thread(void *params)
+{
+ struct ioctl_params *io = params;
+
+ io->ret = NtDeviceIoControlFile(io->handle, io->event, io->apc, io->apc_context, io->io,
+ io->code, io->in_buffer, io->in_size, io->out_buffer, io->out_size);
+ SetEvent(io->complete_event);
+ if (io->kill_thread)
+ Sleep(3000);
+ return io->ret;
+}
+
+static NTSTATUS WINAPI thread_NtDeviceIoControlFile(BOOL kill_thread, HANDLE handle, HANDLE event,
+ PIO_APC_ROUTINE apc, void *apc_context, IO_STATUS_BLOCK *io, ULONG code, void *in_buffer, ULONG in_size,
+ void *out_buffer, ULONG out_size)
+{
+ struct ioctl_params p;
+ HANDLE thread;
+ DWORD ret;
+
+ p.handle = handle;
+ p.event = event;
+ p.apc = apc;
+ p.apc_context = apc_context;
+ p.io = io;
+ p.code = code;
+ p.in_buffer = in_buffer;
+ p.in_size = in_size;
+ p.out_buffer = out_buffer;
+ p.out_size = out_size;
+ p.complete_event = CreateEventW(NULL, FALSE, FALSE, NULL);
+ p.kill_thread = kill_thread;
+
+ thread = CreateThread(NULL, 0, async_ioctl_thread, &p, 0, NULL);
+ ok(!!thread, "got NULL.\n");
+ ret = WaitForSingleObject(p.complete_event, INFINITE);
+ ok(ret == WAIT_OBJECT_0, "got ret %#lx.\n", ret);
+ if (kill_thread)
+ TerminateThread(thread, -1);
+ CloseHandle(p.complete_event);
+ ret = WaitForSingleObject(thread, INFINITE);
+ ok(ret == WAIT_OBJECT_0, "got ret %#lx.\n", ret);
+ CloseHandle(thread);
+ return p.ret;
+}
+
+static void test_async_thread_termination(void)
+{
+ const struct sockaddr_in bind_addr = {.sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK)};
+ char in_buffer[offsetof(struct afd_poll_params, sockets[3])];
+ char out_buffer[offsetof(struct afd_poll_params, sockets[3])];
+ struct afd_poll_params *in_params = (struct afd_poll_params *)in_buffer;
+ struct afd_poll_params *out_params = (struct afd_poll_params *)out_buffer;
+ LARGE_INTEGER zero = {{0}};
+ ULONG_PTR key, value;
+ IO_STATUS_BLOCK io;
+ HANDLE event, port;
+ ULONG params_size;
+ SOCKET listener;
+ int ret;
+
+ event = CreateEventW(NULL, FALSE, FALSE, NULL);
+
+ listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ ret = bind(listener, (const struct sockaddr *)&bind_addr, sizeof(bind_addr));
+ ok(!ret, "got error %u\n", WSAGetLastError());
+ ret = listen(listener, 1);
+ ok(!ret, "got error %u\n", WSAGetLastError());
+
+ in_params->count = 1;
+ in_params->exclusive = FALSE;
+ in_params->sockets[0].socket = listener;
+ in_params->sockets[0].flags = ~0;
+ in_params->sockets[0].status = 0xdeadbeef;
+ params_size = offsetof(struct afd_poll_params, sockets[1]);
+ in_params->timeout = -10 * 1000 * 1000 * 5;
+
+ memset(&io, 0xcc, sizeof(io));
+ ret = thread_NtDeviceIoControlFile(TRUE, (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);
+
+ 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);
+
+ port = CreateIoCompletionPort((HANDLE)listener, NULL, 0, 0);
+
+ memset(&io, 0xcc, sizeof(io));
+ ret = thread_NtDeviceIoControlFile(TRUE, (HANDLE)listener, event, NULL, (void *)0xdeadbeef, &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);
+
+ 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);
+ }
+
+ memset(&io, 0xcc, sizeof(io));
+ ret = thread_NtDeviceIoControlFile(FALSE, (HANDLE)listener, event, NULL, (void *)0xdeadbeef, &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);
+
+ 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);
+ }
+
+ CloseHandle(port);
+ CloseHandle(event);
+ closesocket(listener);
+}
+
START_TEST(afd)
{
WSADATA data;
@@ -2372,6 +2530,7 @@ START_TEST(afd)
test_get_events_reset();
test_bind();
test_getsockname();
+ test_async_thread_termination();
WSACleanup();
}
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/135
More information about the wine-devel
mailing list