On Tue, Apr 19, 2022, 2:49 PM Daniel Lehman <dlehman25@gmail.com> wrote:
Signed-off-by: Daniel Lehman <dlehman25@gmail.com>
---
������dlls/ntdll/tests/pipe.c | 11 +----------
������dlls/ntdll/unix/file.c������ | 18 ++++++++++++++++--
������server/async.c������ ������ ������ ������ ������ | 33 +++++++++++++++++++++++++++++++++
������server/protocol.def������ ������ ������|������ 4 ++++
������4 files changed, 54 insertions(+), 12 deletions(-)

diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c
index 1298e7a37ae..cfad711a09d 100644
--- a/dlls/ntdll/tests/pipe.c
+++ b/dlls/ntdll/tests/pipe.c
@@ -574,11 +574,9 @@ static DWORD WINAPI synchronousio_thread(void *arg)
������ ������ ������U(iosb).Status = 0xdeadbabe;
������ ������ ������iosb.Information = 0xdeadbeef;
������ ������ ������res = listen_pipe(pipe, NULL, &iosb, FALSE);
-������ ������ todo_wine {
������ ������ ������ok(res == STATUS_CANCELLED, "NtFsControlFile returned %lx\n", res);
������ ������ ������ok(U(iosb).Status == 0xdeadbabe, "wrong status %lx\n", U(iosb).Status);
������ ������ ������ok(iosb.Information == 0xdeadbeef, "wrong info %Iu\n", iosb.Information);
-������ ������ }
������ ������ ������return 0;
������}

@@ -594,13 +592,10 @@ 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);
@@ -616,14 +611,12 @@ 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(pipe);
������ ������ ������WaitForSingleObject(thread, INFINITE);
������ ������ ������CloseHandle(thread);
+������ ������ CloseHandle(pipe);

������ ������ ������/* asynchronous i/o */
������ ������ ������res = create_pipe(&pipe, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
@@ -635,11 +628,9 @@ 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);
-������ ������ }
������ ������ ������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..d833a136357 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5975,8 +5975,22 @@ 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;
+
+������ ������ FIXME( "(%p %p %p),partial stub\n", handle, io, io_status );
+
+������ ������ if (io) FIXME( "stub: unused IO_STATUS_BLOCK\n" );

If io is specified, it should never cancel any I/O operations other than the one specified by the parameter.

Better keep returning STATUS_NOT_IMPLEMENTED in this case?

+
+������ ������ SERVER_START_REQ( cancel_sync )
+������ ������ {
+������ ������ ������ ������ req->handle = wine_server_obj_handle( handle );
+������ ������ ������ ������ 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 a4fbeab555e..b78d3a0532a 100644
--- a/server/async.c
+++ b/server/async.c
@@ -588,6 +588,26 @@ restart:
������ ������ ������return woken;
������}

+static int cancel_blocking( struct process *process, struct thread *thread )
+{
+������ ������ 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->thread == thread) && async->blocking)
+������ ������ ������ ������ {
+������ ������ ������ ������ ������ ������ 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 );
@@ -715,6 +735,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 ))
+������ ������ ������ ������ ������ ������ 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 9b7b99ae86a..52a1b7767ce 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2135,6 +2135,10 @@ enum message_type
������#define SERIALINFO_PENDING_WRITE 0x04
������#define SERIALINFO_PENDING_WAIT������ 0x08

+/* Cancel all sync io on a thread */
+@REQ(cancel_sync)
+������ ������ obj_handle_t handle;������ ������ ������ ������ /* thread handle on which to cancel io */
+@END

������/* Create an async I/O */
������@REQ(register_async)
--
2.25.1