Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/kernel32/tests/pipe.c | 93 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c index 7fa3c313d47..50dda0bcc80 100644 --- a/dlls/kernel32/tests/pipe.c +++ b/dlls/kernel32/tests/pipe.c @@ -37,6 +37,7 @@ static HANDLE alarm_event; static BOOL (WINAPI *pDuplicateTokenEx)(HANDLE,DWORD,LPSECURITY_ATTRIBUTES, SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,PHANDLE); static BOOL (WINAPI *pCancelIoEx)(HANDLE handle, LPOVERLAPPED lpOverlapped); +static BOOL (WINAPI *pCancelSynchronousIo)(HANDLE handle); static BOOL (WINAPI *pGetNamedPipeClientProcessId)(HANDLE,ULONG*); static BOOL (WINAPI *pGetNamedPipeServerProcessId)(HANDLE,ULONG*); static BOOL (WINAPI *pGetNamedPipeClientSessionId)(HANDLE,ULONG*); @@ -4202,6 +4203,96 @@ static void test_exit_process_async(void) CloseHandle(server); }
+static DWORD CALLBACK synchronousIoThreadMain(void *arg) +{ + HANDLE pipe; + BOOL ret; + + pipe = arg; + SetLastError(0xdeadbeef); + ret = ConnectNamedPipe(pipe, NULL); + ok(!ret, "expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_OPERATION_ABORTED, "got error %lu\n", GetLastError()); + return 0; +} + +static DWORD CALLBACK synchronousIoThreadMain2(void *arg) +{ + OVERLAPPED ov; + HANDLE pipe; + BOOL ret; + + pipe = arg; + memset(&ov, 0, sizeof(ov)); + ov.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + SetLastError(0xdeadbeef); + ret = ConnectNamedPipe(pipe, &ov); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_IO_PENDING, "got error %lu\n", GetLastError()); + ret = WaitForSingleObject(ov.hEvent, 1000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", ret); + CloseHandle(ov.hEvent); + return 0; +} + +static void test_CancelSynchronousIo(void) +{ + BOOL res; + HANDLE file; + HANDLE pipe; + HANDLE thread; + + /* bogus values */ + SetLastError(0xdeadbeef); + res = pCancelSynchronousIo((HANDLE)0xdeadbeef); + ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_HANDLE, + "In CancelSynchronousIo failure, expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + res = pCancelSynchronousIo(GetCurrentThread()); + ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); + todo_wine + ok(GetLastError() == ERROR_NOT_FOUND, + "In CancelSynchronousIo failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError()); + + /* synchronous i/o */ + pipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError()); + thread = CreateThread(NULL, 0, synchronousIoThreadMain, pipe, 0, NULL); + /* wait for thread to start listening */ + Sleep(100); + res = pCancelSynchronousIo(thread); + todo_wine + ok(res, "CancelSynchronousIo failed with error %ld\n", GetLastError()); + CloseHandle(pipe); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + + /* asynchronous i/o */ + pipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with %lu\n", GetLastError()); + thread = CreateThread(NULL, 0, synchronousIoThreadMain2, pipe, 0, NULL); + Sleep(100); + res = pCancelSynchronousIo(thread); + ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); + todo_wine + ok(GetLastError() == ERROR_NOT_FOUND, + "In CancelSynchronousIo failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError()); + file = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed (%ld)\n", GetLastError()); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + CloseHandle(file); + CloseHandle(pipe); +} + START_TEST(pipe) { char **argv; @@ -4212,6 +4303,7 @@ START_TEST(pipe) pDuplicateTokenEx = (void *) GetProcAddress(hmod, "DuplicateTokenEx"); hmod = GetModuleHandleA("kernel32.dll"); pCancelIoEx = (void *) GetProcAddress(hmod, "CancelIoEx"); + pCancelSynchronousIo = (void *) GetProcAddress(hmod, "CancelSynchronousIo"); pGetNamedPipeClientProcessId = (void *) GetProcAddress(hmod, "GetNamedPipeClientProcessId"); pGetNamedPipeServerProcessId = (void *) GetProcAddress(hmod, "GetNamedPipeServerProcessId"); pGetNamedPipeClientSessionId = (void *) GetProcAddress(hmod, "GetNamedPipeClientSessionId"); @@ -4282,4 +4374,5 @@ START_TEST(pipe) test_nowait(PIPE_TYPE_MESSAGE); test_GetOverlappedResultEx(); test_exit_process_async(); + test_CancelSynchronousIo(); }
Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/ntdll/ntdll.spec | 2 + dlls/ntdll/tests/pipe.c | 93 ++++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/file.c | 9 ++++ dlls/ntdll/unix/loader.c | 1 + include/winternl.h | 1 + 5 files changed, 106 insertions(+)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 311f99be054..74152ef10bc 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -153,6 +153,7 @@ # @ stub NtCancelDeviceWakeupRequest @ stdcall -syscall NtCancelIoFile(long ptr) @ stdcall -syscall NtCancelIoFileEx(long ptr ptr) +@ stdcall -syscall NtCancelSynchronousIoFile(long ptr ptr) @ stdcall -syscall NtCancelTimer(long ptr) @ stdcall -syscall NtClearEvent(long) @ stdcall -syscall NtClose(long) @@ -1181,6 +1182,7 @@ # @ stub ZwCancelDeviceWakeupRequest @ stdcall -private -syscall ZwCancelIoFile(long ptr) NtCancelIoFile @ stdcall -private -syscall ZwCancelIoFileEx(long ptr ptr) NtCancelIoFileEx +@ stdcall -private -syscall ZwCancelSynchronousIoFile(long ptr ptr) NtCancelSynchronousIoFile @ stdcall -private -syscall ZwCancelTimer(long ptr) NtCancelTimer @ stdcall -private -syscall ZwClearEvent(long) NtClearEvent @ stdcall -private -syscall ZwClose(long) NtClose diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c index dc9737e73d8..1298e7a37ae 100644 --- a/dlls/ntdll/tests/pipe.c +++ b/dlls/ntdll/tests/pipe.c @@ -79,6 +79,7 @@ static NTSTATUS (WINAPI *pNtQueryVolumeInformationFile)(HANDLE handle, PIO_STATU static NTSTATUS (WINAPI *pNtSetInformationFile) (HANDLE handle, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class); static NTSTATUS (WINAPI *pNtCancelIoFile) (HANDLE hFile, PIO_STATUS_BLOCK io_status); static NTSTATUS (WINAPI *pNtCancelIoFileEx) (HANDLE hFile, IO_STATUS_BLOCK *iosb, IO_STATUS_BLOCK *io_status); +static NTSTATUS (WINAPI *pNtCancelSynchronousIoFile) (HANDLE hFile, IO_STATUS_BLOCK *iosb, IO_STATUS_BLOCK *io_status); static NTSTATUS (WINAPI *pNtRemoveIoCompletion)(HANDLE, PULONG_PTR, PULONG_PTR, PIO_STATUS_BLOCK, PLARGE_INTEGER); static void (WINAPI *pRtlInitUnicodeString) (PUNICODE_STRING target, PCWSTR source);
@@ -103,6 +104,7 @@ static BOOL init_func_ptrs(void) loadfunc(NtQueryVolumeInformationFile) loadfunc(NtSetInformationFile) loadfunc(NtCancelIoFile) + loadfunc(NtCancelSynchronousIoFile) loadfunc(RtlInitUnicodeString) loadfunc(NtRemoveIoCompletion)
@@ -562,6 +564,94 @@ static void test_cancelio(void) CloseHandle(hEvent); }
+static DWORD WINAPI synchronousio_thread(void *arg) +{ + IO_STATUS_BLOCK iosb; + NTSTATUS res; + HANDLE pipe; + + pipe = 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; +} + +static void test_cancelsynchronousio(void) +{ + DWORD ret; + HANDLE pipe; + HANDLE event; + HANDLE thread; + HANDLE client; + NTSTATUS res; + IO_STATUS_BLOCK iosb; + + /* 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), + "NtCancelSynchronousIoFile returned %lx\n", res); + + /* synchronous i/o */ + res = create_pipe(&pipe, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); + ok(!res, "NtCreateNamedPipeFile returned %lx\n", res); + thread = CreateThread(NULL, 0, synchronousio_thread, pipe, 0, 0); + /* wait for thread to start listening */ + 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); + + /* asynchronous i/o */ + res = create_pipe(&pipe, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */); + ok(!res, "NtCreateNamedPipeFile returned %lx\n", res); + event = CreateEventW(NULL, TRUE, FALSE, NULL); + ok(event != INVALID_HANDLE_VALUE, "Can't create event, GetLastError: %lx\n", GetLastError()); + memset(&iosb, 0x55, sizeof(iosb)); + res = listen_pipe(pipe, event, &iosb, FALSE); + 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, + FILE_FLAG_OVERLAPPED, 0); + ok(client != INVALID_HANDLE_VALUE, "can't open pipe: %lu\n", GetLastError()); + ret = WaitForSingleObject(event, 0); + ok(ret == WAIT_OBJECT_0, "wait returned %lx\n", ret); + CloseHandle(pipe); + CloseHandle(event); + CloseHandle(client); +} + static void _check_pipe_handle_state(int line, HANDLE handle, ULONG read, ULONG completion) { IO_STATUS_BLOCK iosb; @@ -2606,6 +2696,9 @@ START_TEST(pipe) trace("starting cancelio tests\n"); test_cancelio();
+ trace("starting cancelsynchronousio tests\n"); + test_cancelsynchronousio(); + trace("starting byte read in byte mode client -> server\n"); read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE); trace("starting byte read in message mode client -> server\n"); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index cc8bf0c6e82..6990f9b4719 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -5970,6 +5970,15 @@ NTSTATUS WINAPI NtCancelIoFileEx( HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_ }
+/************************************************************************** + * NtCancelSynchronousIoFile (NTDLL.@) + */ +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; +} + /****************************************************************** * NtLockFile (NTDLL.@) */ diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index d1c42ddc0f3..a3ddce6414a 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -139,6 +139,7 @@ static void * const syscalls[] = NtCallbackReturn, NtCancelIoFile, NtCancelIoFileEx, + NtCancelSynchronousIoFile, NtCancelTimer, NtClearEvent, NtClose, diff --git a/include/winternl.h b/include/winternl.h index b4942d86b4c..7e41ad6ab60 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -3927,6 +3927,7 @@ NTSYSAPI NTSTATUS WINAPI NtAssignProcessToJobObject(HANDLE,HANDLE); NTSYSAPI NTSTATUS WINAPI NtCallbackReturn(PVOID,ULONG,NTSTATUS); NTSYSAPI NTSTATUS WINAPI NtCancelIoFile(HANDLE,PIO_STATUS_BLOCK); NTSYSAPI NTSTATUS WINAPI NtCancelIoFileEx(HANDLE,PIO_STATUS_BLOCK,PIO_STATUS_BLOCK); +NTSYSAPI NTSTATUS WINAPI NtCancelSynchronousIoFile(HANDLE,PIO_STATUS_BLOCK,PIO_STATUS_BLOCK); NTSYSAPI NTSTATUS WINAPI NtCancelTimer(HANDLE, BOOLEAN*); NTSYSAPI NTSTATUS WINAPI NtClearEvent(HANDLE); NTSYSAPI NTSTATUS WINAPI NtClose(HANDLE);
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" ); + + 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)
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
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?
i'm not entirely sure how it's used. for the synchronous case where it does cancel, passing a non-null io returns c0000225 (NOT_FOUND) instead of canceling. i don't see any difference in the asynchonous test case that already returns that
returning c0000225 for a non-null io would at least match windows, but feels like a fixme would still be needed since i'd still be ignoring it
the io didn't make any difference for implementing CancelSynchronousIo in kernelbase, which was what i was going for. and since it's more documented, CancelSynchonousIo is more likely to be called than NtCancelSynchronousIoFile directly
i can certainly add more tests to probe it, though, if preferred
thanks daniel
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?
ah, i see. i think i know how it's used. will send a new version
thanks daniel
Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/kernel32/tests/pipe.c | 7 +------ dlls/kernelbase/file.c | 6 +++--- 2 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c index 50dda0bcc80..a27d510a7f6 100644 --- a/dlls/kernel32/tests/pipe.c +++ b/dlls/kernel32/tests/pipe.c @@ -4212,7 +4212,6 @@ static DWORD CALLBACK synchronousIoThreadMain(void *arg) SetLastError(0xdeadbeef); ret = ConnectNamedPipe(pipe, NULL); ok(!ret, "expected failure\n"); - todo_wine ok(GetLastError() == ERROR_OPERATION_ABORTED, "got error %lu\n", GetLastError()); return 0; } @@ -4247,14 +4246,12 @@ static void test_CancelSynchronousIo(void) SetLastError(0xdeadbeef); res = pCancelSynchronousIo((HANDLE)0xdeadbeef); ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "In CancelSynchronousIo failure, expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
SetLastError(0xdeadbeef); res = pCancelSynchronousIo(GetCurrentThread()); ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); - todo_wine ok(GetLastError() == ERROR_NOT_FOUND, "In CancelSynchronousIo failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError());
@@ -4267,11 +4264,10 @@ static void test_CancelSynchronousIo(void) /* wait for thread to start listening */ Sleep(100); res = pCancelSynchronousIo(thread); - todo_wine ok(res, "CancelSynchronousIo failed with error %ld\n", GetLastError()); - CloseHandle(pipe); WaitForSingleObject(thread, INFINITE); CloseHandle(thread); + CloseHandle(pipe);
/* asynchronous i/o */ pipe = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, @@ -4282,7 +4278,6 @@ static void test_CancelSynchronousIo(void) Sleep(100); res = pCancelSynchronousIo(thread); ok(!res, "CancelSynchronousIo succeeded unexpectedly\n"); - todo_wine ok(GetLastError() == ERROR_NOT_FOUND, "In CancelSynchronousIo failure, expected ERROR_NOT_FOUND, got %ld\n", GetLastError()); file = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index 8ae982294f6..9a57c7f2e49 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -2900,9 +2900,9 @@ BOOL WINAPI DECLSPEC_HOTPATCH CancelIoEx( HANDLE handle, LPOVERLAPPED overlapped */ BOOL WINAPI DECLSPEC_HOTPATCH CancelSynchronousIo( HANDLE thread ) { - FIXME( "(%p): stub\n", thread ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + IO_STATUS_BLOCK io; + + return set_ntstatus( NtCancelSynchronousIoFile( thread, NULL, &io ) ); }