[PATCH v2 3/4] ntdll: Partially implement NtCancelSynchronousIoFile.

Daniel Lehman wine at gitlab.winehq.org
Wed Jun 22 01:40:54 CDT 2022


From: Daniel Lehman <dlehman25 at gmail.com>

Signed-off-by: Daniel Lehman <dlehman25 at gmail.com>
---
 dlls/ntdll/tests/pipe.c | 17 +++--------------
 dlls/ntdll/unix/file.c  | 17 +++++++++++++++--
 server/async.c          | 34 ++++++++++++++++++++++++++++++++++
 server/protocol.def     |  5 +++++
 4 files changed, 57 insertions(+), 16 deletions(-)

diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c
index 8c57efdc89a..fa813ceb8b5 100644
--- a/dlls/ntdll/tests/pipe.c
+++ b/dlls/ntdll/tests/pipe.c
@@ -629,7 +629,6 @@ static DWORD WINAPI synchronousio_thread(void *arg)
     NTSTATUS res;
 
     res = listen_pipe(ctx->pipe, NULL, &ctx->iosb, FALSE);
-    todo_wine
     ok(res == STATUS_CANCELLED, "NtFsControlFile returned %lx\n", res);
     return 0;
 }
@@ -646,18 +645,14 @@ static void test_cancelsynchronousio(void)
 
     /* bogus values */
     res = pNtCancelSynchronousIoFile((HANDLE)0xdeadbeef, NULL, &iosb);
-    todo_wine
     ok(res == STATUS_INVALID_HANDLE, "NtCancelSynchronousIoFile returned %lx\n", res);
     res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, NULL);
-    todo_wine
     ok(res == STATUS_ACCESS_VIOLATION, "NtCancelSynchronousIoFile returned %lx\n", res);
     res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, (IO_STATUS_BLOCK*)0xdeadbeef);
-    todo_wine
     ok(res == STATUS_ACCESS_VIOLATION, "NtCancelSynchronousIoFile returned %lx\n", res);
     memset(&iosb, 0x55, sizeof(iosb));
     res = pNtCancelSynchronousIoFile(GetCurrentThread(), (HANDLE)0xdeadbeef, &iosb);
-    todo_wine
-    ok(res == STATUS_ACCESS_VIOLATION || broken(res == STATUS_NOT_FOUND), /* Win<10 */
+    ok(res == STATUS_ACCESS_VIOLATION || res == STATUS_NOT_FOUND, /* Wine & Win < 10 */
         "NtCancelSynchronousIoFile returned %lx\n", res);
 
     /* synchronous i/o */
@@ -672,16 +667,14 @@ static void test_cancelsynchronousio(void)
     Sleep(100);
     memset(&iosb, 0x55, sizeof(iosb));
     res = pNtCancelSynchronousIoFile(thread, NULL, &iosb);
-    todo_wine {
     ok(res == STATUS_SUCCESS, "Failed to cancel I/O\n");
     ok(U(iosb).Status == STATUS_SUCCESS, "iosb.Status got changed to %lx\n", U(iosb).Status);
     ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information);
-    CloseHandle(ctx.pipe);
     WaitForSingleObject(thread, INFINITE);
     CloseHandle(thread);
+    CloseHandle(ctx.pipe);
     ok(U(ctx.iosb).Status == 0xdeadbabe, "wrong status %lx\n", U(ctx.iosb).Status);
     ok(ctx.iosb.Information == 0xdeadbeef, "wrong info %Iu\n", ctx.iosb.Information);
-    }
 
     /* specified io */
     res = create_pipe(&ctx.pipe, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
@@ -694,7 +687,6 @@ static void test_cancelsynchronousio(void)
     Sleep(100);
     memset(&iosb, 0x55, sizeof(iosb));
     res = pNtCancelSynchronousIoFile(thread, &iosb, &iosb);
-    todo_wine {
     ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res);
     res = pNtCancelSynchronousIoFile(NULL, &ctx.iosb, &iosb);
     ok(res == STATUS_INVALID_HANDLE, "NtCancelSynchronousIoFile returned %lx\n", res);
@@ -710,12 +702,11 @@ static void test_cancelsynchronousio(void)
         ok(res == STATUS_SUCCESS, "Failed to cancel I/O\n");
         ok(U(iosb).Status == STATUS_SUCCESS, "iosb.Status got changed to %lx\n", U(iosb).Status);
     }
-    CloseHandle(ctx.pipe);
     WaitForSingleObject(thread, INFINITE);
     CloseHandle(thread);
+    CloseHandle(ctx.pipe);
     ok(U(ctx.iosb).Status == 0xdeadbabe, "wrong status %lx\n", U(ctx.iosb).Status);
     ok(ctx.iosb.Information == 0xdeadbeef, "wrong info %Iu\n", ctx.iosb.Information);
-    }
 
     /* asynchronous i/o */
     U(ctx.iosb).Status = 0xdeadbabe;
@@ -728,7 +719,6 @@ static void test_cancelsynchronousio(void)
     ok(res == STATUS_PENDING, "NtFsControlFile returned %lx\n", res);
     memset(&iosb, 0x55, sizeof(iosb));
     res = pNtCancelSynchronousIoFile(GetCurrentThread(), NULL, &iosb);
-    todo_wine {
     ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res);
     ok(U(iosb).Status == STATUS_NOT_FOUND, "iosb.Status got changed to %lx\n", U(iosb).Status);
     ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information);
@@ -737,7 +727,6 @@ static void test_cancelsynchronousio(void)
     ok(res == STATUS_NOT_FOUND, "NtCancelSynchronousIoFile returned %lx\n", res);
     ok(U(iosb).Status == STATUS_NOT_FOUND, "iosb.Status got changed to %lx\n", U(iosb).Status);
     ok(U(iosb).Information == 0, "iosb.Information got changed to %Iu\n", U(iosb).Information);
-    }
     ret = WaitForSingleObject(event, 0);
     ok(ret == WAIT_TIMEOUT, "wait returned %lx\n", ret);
     client = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 6990f9b4719..ffad82aa9ee 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5975,8 +5975,21 @@ NTSTATUS WINAPI NtCancelIoFileEx( HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_
  */
 NTSTATUS WINAPI NtCancelSynchronousIoFile( HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_BLOCK *io_status )
 {
-    FIXME( "(%p,%p,%p) stub\n", handle, io, io_status );
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS status;
+
+    TRACE( "(%p %p %p)\n", handle, io, io_status );
+
+    SERVER_START_REQ( cancel_sync )
+    {
+        req->handle = wine_server_obj_handle( handle );
+        req->iosb   = wine_server_client_ptr( io );
+        status = wine_server_call( req );
+    }
+    SERVER_END_REQ;
+
+    io_status->u.Status = status;
+    io_status->Information = 0;
+    return status;
 }
 
 /******************************************************************
diff --git a/server/async.c b/server/async.c
index 4832d69b7bf..83ade931ec6 100644
--- a/server/async.c
+++ b/server/async.c
@@ -588,6 +588,27 @@ restart:
     return woken;
 }
 
+static int cancel_blocking( struct process *process, struct thread *thread, client_ptr_t iosb )
+{
+    struct async *async;
+    int woken = 0;
+
+restart:
+    LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry )
+    {
+        if (async->terminated || async->canceled) continue;
+        if (async->blocking && (async->thread == thread) &&
+            (!iosb || async->data.iosb == iosb))
+        {
+            async->canceled = 1;
+            fd_cancel_async( async->fd, async );
+            woken++;
+            goto restart;
+        }
+    }
+    return woken;
+}
+
 void cancel_process_asyncs( struct process *process )
 {
     cancel_async( process, NULL, NULL, 0 );
@@ -731,6 +752,19 @@ struct async *find_pending_async( struct async_queue *queue )
     return NULL;
 }
 
+/* cancels sync I/O on a thread */
+DECL_HANDLER(cancel_sync)
+{
+    struct thread *thread = get_thread_from_handle( req->handle, THREAD_TERMINATE );
+
+    if (thread)
+    {
+        if (!cancel_blocking( current->process, thread, req->iosb ))
+            set_error( STATUS_NOT_FOUND );
+        release_object( thread );
+    }
+}
+
 /* cancels all async I/O */
 DECL_HANDLER(cancel_async)
 {
diff --git a/server/protocol.def b/server/protocol.def
index 2be1658fca2..57274252566 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2135,6 +2135,11 @@ enum message_type
 #define SERIALINFO_PENDING_WRITE 0x04
 #define SERIALINFO_PENDING_WAIT  0x08
 
+/* Cancel all sync io on a thread */
+ at REQ(cancel_sync)
+    obj_handle_t handle;        /* thread handle on which to cancel io */
+    client_ptr_t iosb;          /* I/O status block (NULL=all) */
+ at END
 
 /* Create an async I/O */
 @REQ(register_async)
-- 
GitLab


https://gitlab.winehq.org/wine/wine/-/merge_requests/47



More information about the wine-devel mailing list