From: Jacek Caban Subject: [PATCH 16/16] ntdll/tests: Added more pipe read tests. Message-Id: Date: Thu, 26 Jan 2017 00:53:48 +0100 Also moved existing tests to pipe.c. Signed-off-by: Jacek Caban --- dlls/ntdll/tests/file.c | 271 +---------------------------------- dlls/ntdll/tests/pipe.c | 369 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 371 insertions(+), 269 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 9fbe63c..88d5d25 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -95,21 +95,8 @@ static const char* debugstr_longlong(ULONGLONG ll) return str; } -#define PIPENAME "\\\\.\\pipe\\ntdll_tests_file.c" #define TEST_BUF_LEN 3 -static BOOL create_pipe( HANDLE *read, HANDLE *write, ULONG flags, ULONG size ) -{ - *read = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_INBOUND | flags, PIPE_TYPE_BYTE | PIPE_WAIT, - 1, size, size, NMPWAIT_USE_DEFAULT_WAIT, NULL); - ok(*read != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); - - *write = CreateFileA(PIPENAME, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - ok(*write != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError()); - - return TRUE; -} - static HANDLE create_temp_file( ULONG flags ) { char path[MAX_PATH], buffer[MAX_PATH]; @@ -633,268 +620,14 @@ static void delete_file_test(void) static void read_file_test(void) { const char text[] = "foobar"; - HANDLE handle, read, write; + HANDLE handle; NTSTATUS status; - IO_STATUS_BLOCK iosb, iosb2; - DWORD written; + IO_STATUS_BLOCK iosb; int apc_count = 0; char buffer[128]; LARGE_INTEGER offset; HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL ); - BOOL ret; - - buffer[0] = 1; - - if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return; - - /* try read with no data */ - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - ok( is_signaled( read ), "read handle is not signaled\n" ); - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( read ), "read handle is signaled\n" ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - ret = WriteFile( write, buffer, 1, &written, NULL ); - ok(ret && written == 1, "WriteFile error %d\n", GetLastError()); - /* iosb updated here by async i/o */ - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); - ok( !is_signaled( read ), "read handle is signaled\n" ); - ok( is_signaled( event ), "event is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - apc_count = 0; - SleepEx( 1, FALSE ); /* non-alertable sleep */ - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc not called\n" ); - - /* with no event, the pipe handle itself gets signaled */ - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - ok( !is_signaled( read ), "read handle is signaled\n" ); - status = pNtReadFile( read, 0, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( read ), "read handle is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - ret = WriteFile( write, buffer, 1, &written, NULL ); - ok(ret && written == 1, "WriteFile error %d\n", GetLastError()); - /* iosb updated here by async i/o */ - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( read ), "read handle is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - apc_count = 0; - SleepEx( 1, FALSE ); /* non-alertable sleep */ - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc not called\n" ); - - /* now read with data ready */ - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - ResetEvent( event ); - ret = WriteFile( write, buffer, 1, &written, NULL ); - ok(ret && written == 1, "WriteFile error %d\n", GetLastError()); - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); - ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); - ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( event ), "event is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, FALSE ); /* non-alertable sleep */ - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc not called\n" ); - - /* try read with no data */ - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - ok( is_signaled( event ), "event is not signaled\n" ); /* check that read resets the event */ - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - ret = WriteFile( write, buffer, 1, &written, NULL ); - ok(ret && written == 1, "WriteFile error %d\n", GetLastError()); - /* partial read is good enough */ - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( is_signaled( event ), "event is not signaled\n" ); - ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc was not called\n" ); - - /* read from disconnected pipe */ - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - CloseHandle( write ); - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); - ok( status == STATUS_PIPE_BROKEN, "wrong status %x\n", status ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( !apc_count, "apc was called\n" ); - CloseHandle( read ); - - /* read from closed handle */ - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - SetEvent( event ); - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); - ok( status == STATUS_INVALID_HANDLE, "wrong status %x\n", status ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( event ), "event is not signaled\n" ); /* not reset on invalid handle */ - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( !apc_count, "apc was called\n" ); - - /* disconnect while async read is in progress */ - if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return; - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - CloseHandle( write ); - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( U(iosb).Status == STATUS_PIPE_BROKEN, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( event ), "event is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc was not called\n" ); - CloseHandle( read ); - - if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return; - ret = DuplicateHandle(GetCurrentProcess(), read, GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS); - ok(ret, "Failed to duplicate handle: %d\n", GetLastError()); - - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - /* Cancel by other handle */ - status = pNtCancelIoFile( read, &iosb2 ); - ok(status == STATUS_SUCCESS, "failed to cancel by different handle: %x\n", status); - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( event ), "event is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc was not called\n" ); - - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - /* Close queued handle */ - CloseHandle( read ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - status = pNtCancelIoFile( read, &iosb2 ); - ok(status == STATUS_INVALID_HANDLE, "cancelled by closed handle?\n"); - status = pNtCancelIoFile( handle, &iosb2 ); - ok(status == STATUS_SUCCESS, "failed to cancel: %x\n", status); - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( event ), "event is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc was not called\n" ); - CloseHandle( handle ); - CloseHandle( write ); - - if (pNtCancelIoFileEx) - { - /* Basic Cancel Ex */ - if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return; - - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - status = pNtCancelIoFileEx( read, &iosb, &iosb2 ); - ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n"); - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( event ), "event is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc was not called\n" ); - - /* Duplicate iosb */ - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - status = pNtCancelIoFileEx( read, &iosb, &iosb2 ); - ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n"); - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( event ), "event is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 2, "apc was not called\n" ); - - CloseHandle( read ); - CloseHandle( write ); - } - /* now try a real file */ if (!(handle = create_temp_file( FILE_FLAG_OVERLAPPED ))) return; apc_count = 0; U(iosb).Status = 0xdeadbabe; diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c index dce5d34..c1a9b1c 100644 --- a/dlls/ntdll/tests/pipe.c +++ b/dlls/ntdll/tests/pipe.c @@ -80,6 +80,10 @@ static void (WINAPI *pRtlInitUnicodeString) (PUNICODE_STRING target, PCWSTR sour static HANDLE (WINAPI *pOpenThread)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId); static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData); +static NTSTATUS (WINAPI *pNtReadFile)(HANDLE hFile, HANDLE hEvent, + PIO_APC_ROUTINE apc, void* apc_user, + PIO_STATUS_BLOCK io_status, void* buffer, ULONG length, + PLARGE_INTEGER offset, PULONG key); static BOOL init_func_ptrs(void) @@ -98,6 +102,7 @@ static BOOL init_func_ptrs(void) loadfunc(NtCancelIoFile) loadfunc(NtCancelIoFileEx) loadfunc(RtlInitUnicodeString) + loadfunc(NtReadFile) /* not fatal */ module = GetModuleHandleA("kernel32.dll"); @@ -106,6 +111,11 @@ static BOOL init_func_ptrs(void) return TRUE; } +static inline BOOL is_signaled( HANDLE obj ) +{ + return WaitForSingleObject( obj, 0 ) == WAIT_OBJECT_0; +} + static const WCHAR testpipe[] = { '\\', '\\', '.', '\\', 'p', 'i', 'p', 'e', '\\', 't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 }; static const WCHAR testpipe_nt[] = { '\\', '?', '?', '\\', 'p', 'i', 'p', 'e', '\\', @@ -710,6 +720,352 @@ static void test_filepipeinfo(void) CloseHandle(hServer); } +#define PIPENAME "\\\\.\\pipe\\ntdll_tests_pipe.c" + +static BOOL create_pipe_pair( HANDLE *read, HANDLE *write, ULONG flags, ULONG type, ULONG size ) +{ + const BOOL server_reader = flags & PIPE_ACCESS_INBOUND; + HANDLE client, server; + + server = CreateNamedPipeA(PIPENAME, flags, PIPE_WAIT | type, + 1, size, size, NMPWAIT_USE_DEFAULT_WAIT, NULL); + ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); + + client = CreateFileA(PIPENAME, server_reader ? GENERIC_WRITE : GENERIC_READ | FILE_WRITE_ATTRIBUTES, 0, + NULL, OPEN_EXISTING, flags & FILE_FLAG_OVERLAPPED, 0); + ok(client != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError()); + + if(server_reader) + { + *read = server; + *write = client; + } + else + { + if(type & PIPE_READMODE_MESSAGE) + { + DWORD read_mode = PIPE_READMODE_MESSAGE; + ok(SetNamedPipeHandleState(client, &read_mode, NULL, NULL), "Change mode\n"); + } + + *read = client; + *write = server; + } + return TRUE; +} + +static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved ) +{ + int *count = arg; + + //trace( "apc called block %p iosb.status %x iosb.info %lu\n", + // iosb, U(*iosb).Status, iosb->Information ); + (*count)++; + ok( !reserved, "reserved is not 0: %x\n", reserved ); +} + +static void read_pipe_test(ULONG pipe_flags, ULONG pipe_type) +{ + HANDLE handle, read, write; + NTSTATUS status; + IO_STATUS_BLOCK iosb, iosb2; + DWORD written; + int apc_count = 0; + char buffer[128]; + HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL ); + BOOL ret; + buffer[0] = 1; + + if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return; + + /* try read with no data */ + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + ok( is_signaled( read ), "read handle is not signaled\n" ); + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( read ), "read handle is signaled\n" ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + ret = WriteFile( write, buffer, 1, &written, NULL ); + ok(ret && written == 1, "WriteFile error %d\n", GetLastError()); + /* iosb updated here by async i/o */ + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); + ok( !is_signaled( read ), "read handle is signaled\n" ); + ok( is_signaled( event ), "event is not signaled\n" ); + ok( !apc_count, "apc was called\n" ); + apc_count = 0; + SleepEx( 1, FALSE ); /* non-alertable sleep */ + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc not called\n" ); + + /* with no event, the pipe handle itself gets signaled */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + ok( !is_signaled( read ), "read handle is signaled\n" ); + status = pNtReadFile( read, 0, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( read ), "read handle is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + ret = WriteFile( write, buffer, 1, &written, NULL ); + ok(ret && written == 1, "WriteFile error %d\n", GetLastError()); + /* iosb updated here by async i/o */ + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( read ), "read handle is not signaled\n" ); + ok( !apc_count, "apc was called\n" ); + apc_count = 0; + SleepEx( 1, FALSE ); /* non-alertable sleep */ + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc not called\n" ); + + /* now read with data ready */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + ResetEvent( event ); + ret = WriteFile( write, buffer, 1, &written, NULL ); + ok(ret && written == 1, "WriteFile error %d\n", GetLastError()); + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); + ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); + ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is not signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, FALSE ); /* non-alertable sleep */ + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc not called\n" ); + + /* now partial read with data ready */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + ResetEvent( event ); + ret = WriteFile( write, buffer, 2, &written, NULL ); + ok(ret && written == 2, "WriteFile error %d\n", GetLastError()); + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); + if (pipe_type & PIPE_READMODE_MESSAGE) + { + ok( status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", status ); + ok( U(iosb).Status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", U(iosb).Status ); + } + else + { + ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); + ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); + } + ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is not signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, FALSE ); /* non-alertable sleep */ + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc not called\n" ); + apc_count = 0; + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); + ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); + ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is not signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, FALSE ); /* non-alertable sleep */ + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc not called\n" ); + + /* try read with no data */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + ok( is_signaled( event ), "event is not signaled\n" ); /* check that read resets the event */ + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + ret = WriteFile( write, buffer, 1, &written, NULL ); + ok(ret && written == 1, "WriteFile error %d\n", GetLastError()); + /* partial read is good enough */ + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( is_signaled( event ), "event is not signaled\n" ); + ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc was not called\n" ); + + /* read from disconnected pipe */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + CloseHandle( write ); + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); + ok( status == STATUS_PIPE_BROKEN, "wrong status %x\n", status ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( !apc_count, "apc was called\n" ); + CloseHandle( read ); + + /* read from closed handle */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + SetEvent( event ); + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); + ok( status == STATUS_INVALID_HANDLE, "wrong status %x\n", status ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is not signaled\n" ); /* not reset on invalid handle */ + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( !apc_count, "apc was called\n" ); + + /* disconnect while async read is in progress */ + if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return; + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + CloseHandle( write ); + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + todo_wine_if(!(pipe_type & PIPE_TYPE_MESSAGE) && (pipe_flags & PIPE_ACCESS_OUTBOUND)) + ok( U(iosb).Status == STATUS_PIPE_BROKEN, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is not signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc was not called\n" ); + CloseHandle( read ); + + if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return; + ret = DuplicateHandle(GetCurrentProcess(), read, GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS); + ok(ret, "Failed to duplicate handle: %d\n", GetLastError()); + + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + /* Cancel by other handle */ + status = pNtCancelIoFile( read, &iosb2 ); + ok(status == STATUS_SUCCESS, "failed to cancel by different handle: %x\n", status); + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is not signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc was not called\n" ); + + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + /* Close queued handle */ + CloseHandle( read ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + status = pNtCancelIoFile( read, &iosb2 ); + ok(status == STATUS_INVALID_HANDLE, "cancelled by closed handle?\n"); + status = pNtCancelIoFile( handle, &iosb2 ); + ok(status == STATUS_SUCCESS, "failed to cancel: %x\n", status); + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is not signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc was not called\n" ); + CloseHandle( handle ); + CloseHandle( write ); + + if (pNtCancelIoFileEx) + { + /* Basic Cancel Ex */ + if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return; + + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + status = pNtCancelIoFileEx( read, &iosb, &iosb2 ); + ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n"); + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is not signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc was not called\n" ); + + /* Duplicate iosb */ + apc_count = 0; + U(iosb).Status = 0xdeadbabe; + iosb.Information = 0xdeadbeef; + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); + ok( status == STATUS_PENDING, "wrong status %x\n", status ); + ok( !is_signaled( event ), "event is signaled\n" ); + ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); + ok( !apc_count, "apc was called\n" ); + status = pNtCancelIoFileEx( read, &iosb, &iosb2 ); + ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n"); + Sleep(1); /* FIXME: needed for wine to run the i/o apc */ + ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is not signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 2, "apc was not called\n" ); + + CloseHandle( read ); + CloseHandle( write ); + } + + CloseHandle( event ); +} + START_TEST(pipe) { if (!init_func_ptrs()) @@ -738,4 +1094,17 @@ START_TEST(pipe) trace("starting cancelio tests\n"); test_cancelio(); + + 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"); + read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE); + trace("starting message read in message mode client -> server\n"); + read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE); + trace("starting byte read in byte mode server -> client\n"); + read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE); + trace("starting byte read in message mode server -> client\n"); + read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE); + trace("starting message read in message mode server -> client\n"); + read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE); }