From: Daniel Lehman dlehman25@gmail.com
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(); }
From: Daniel Lehman dlehman25@gmail.com
Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/ntdll/ntdll.spec | 2 + dlls/ntdll/tests/pipe.c | 138 +++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/file.c | 9 +++ dlls/ntdll/unix/loader.c | 1 + include/winternl.h | 1 + 5 files changed, 151 insertions(+)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index b1650ab4306..591fc690a24 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) @@ -1183,6 +1184,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..6ef32caab5d 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,139 @@ static void test_cancelio(void) CloseHandle(hEvent); }
+struct synchronousio_thread_args +{ + HANDLE pipe; + IO_STATUS_BLOCK iosb; +}; + +static DWORD WINAPI synchronousio_thread(void *arg) +{ + struct synchronousio_thread_args *ctx = 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; +} + +static void test_cancelsynchronousio(void) +{ + DWORD ret; + HANDLE event; + HANDLE thread; + HANDLE client; + NTSTATUS res; + IO_STATUS_BLOCK iosb; + struct synchronousio_thread_args ctx; + + /* 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 */ + "NtCancelSynchronousIoFile returned %lx\n", res); + + /* synchronous i/o */ + res = create_pipe(&ctx.pipe, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); + ok(!res, "NtCreateNamedPipeFile returned %lx\n", res); + + /* NULL io */ + U(ctx.iosb).Status = 0xdeadbabe; + ctx.iosb.Information = 0xdeadbeef; + thread = CreateThread(NULL, 0, synchronousio_thread, &ctx, 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(ctx.pipe); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + 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); + ok(!res, "NtCreateNamedPipeFile returned %lx\n", res); + + U(ctx.iosb).Status = 0xdeadbabe; + ctx.iosb.Information = 0xdeadbeef; + thread = CreateThread(NULL, 0, synchronousio_thread, &ctx, 0, 0); + /* wait for thread to start listening */ + 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); + res = pNtCancelSynchronousIoFile(thread, &ctx.iosb, &iosb); + ok(res == STATUS_SUCCESS || broken(res == STATUS_NOT_FOUND) /* 32-bit */, + "Failed to cancel I/O\n"); + ok(U(iosb).Status == STATUS_SUCCESS || broken(U(iosb).Status == STATUS_NOT_FOUND) /* 32-bit */, + "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); + if (res == STATUS_NOT_FOUND) + { + res = pNtCancelSynchronousIoFile(thread, NULL, &iosb); + 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); + 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; + ctx.iosb.Information = 0xdeadbeef; + res = create_pipe(&ctx.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()); + res = listen_pipe(ctx.pipe, event, &ctx.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); + memset(&iosb, 0x55, sizeof(iosb)); + res = pNtCancelSynchronousIoFile(GetCurrentThread(), &ctx.iosb, &iosb); + 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(ctx.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 +2741,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 7f85582adf3..8fa3739957b 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 84babcbb0e9..fbd23a58257 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);
From: Daniel Lehman dlehman25@gmail.com
Signed-off-by: Daniel Lehman dlehman25@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 6ef32caab5d..e5c7a92d754 100644 --- a/dlls/ntdll/tests/pipe.c +++ b/dlls/ntdll/tests/pipe.c @@ -576,7 +576,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; } @@ -593,18 +592,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 */ @@ -619,16 +614,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); @@ -641,7 +634,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); @@ -657,12 +649,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; @@ -675,7 +666,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); @@ -684,7 +674,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 a4fbeab555e..c2838d0f3b6 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 ); @@ -715,6 +736,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 */ +@REQ(cancel_sync) + obj_handle_t handle; /* thread handle on which to cancel io */ + client_ptr_t iosb; /* I/O status block (NULL=all) */ +@END
/* Create an async I/O */ @REQ(register_async)
From: Daniel Lehman dlehman25@gmail.com
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 ) ); }