ntdll: Add some test cases for asynchronous I/O.

This commit is contained in:
Alexandre Julliard 2007-04-09 12:23:13 +02:00
parent c915215ba6
commit a6ecf0a7a5

View File

@ -37,8 +37,303 @@ static VOID (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR );
static VOID (WINAPI *pRtlFreeUnicodeString)(PUNICODE_STRING);
static NTSTATUS (WINAPI *pNtCreateMailslotFile)( PHANDLE, ULONG, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK,
ULONG, ULONG, ULONG, PLARGE_INTEGER );
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 NTSTATUS (WINAPI *pNtWriteFile)(HANDLE hFile, HANDLE hEvent,
PIO_APC_ROUTINE apc, void* apc_user,
PIO_STATUS_BLOCK io_status,
const void* buffer, ULONG length,
PLARGE_INTEGER offset, PULONG key);
static NTSTATUS (WINAPI *pNtClose)( PHANDLE );
static inline BOOL is_signaled( HANDLE obj )
{
return WaitForSingleObject( obj, 0 ) == 0;
}
#define PIPENAME "\\\\.\\pipe\\ntdll_tests_file.c"
static BOOL create_pipe( HANDLE *read, HANDLE *write, ULONG flags, ULONG size )
{
*read = CreateNamedPipe(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 buffer[MAX_PATH];
HANDLE handle;
GetTempFileNameA( ".", "foo", 0, buffer );
handle = CreateFileA(buffer, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
flags | FILE_FLAG_DELETE_ON_CLOSE, 0);
ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
return (handle == INVALID_HANDLE_VALUE) ? 0 : handle;
}
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_file_test(void)
{
const char text[] = "foobar";
HANDLE handle, read, write;
NTSTATUS status;
IO_STATUS_BLOCK iosb;
DWORD written;
int apc_count = 0;
char buffer[128];
LARGE_INTEGER offset;
HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL );
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" );
WriteFile( write, buffer, 1, &written, NULL );
/* 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 not 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" );
WriteFile( write, buffer, 1, &written, NULL );
/* 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( !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 );
WriteFile( write, buffer, 1, &written, NULL );
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" );
WriteFile( write, buffer, 1, &written, NULL );
/* partial read is good enough */
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
ok( is_signaled( event ), "event is 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 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 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 );
/* now try a real file */
if (!(handle = create_temp_file( FILE_FLAG_OVERLAPPED ))) return;
apc_count = 0;
U(iosb).Status = 0xdeadbabe;
iosb.Information = 0xdeadbeef;
offset.QuadPart = 0;
ResetEvent( event );
pNtWriteFile( handle, event, apc, &apc_count, &iosb, text, strlen(text), &offset, NULL );
ok( status == STATUS_PENDING, "wrong status %x\n", status );
ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status );
ok( iosb.Information == strlen(text), "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 == 1, "apc was not called\n" );
apc_count = 0;
U(iosb).Status = 0xdeadbabe;
iosb.Information = 0xdeadbeef;
offset.QuadPart = 0;
ResetEvent( event );
status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, strlen(text) + 10, &offset, NULL );
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status );
ok( iosb.Information == strlen(text), "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 == 1, "apc was not called\n" );
/* read beyond eof */
apc_count = 0;
U(iosb).Status = 0xdeadbabe;
iosb.Information = 0xdeadbeef;
offset.QuadPart = strlen(text) + 2;
status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, &offset, NULL );
ok( status == STATUS_END_OF_FILE, "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( handle );
/* now a non-overlapped file */
if (!(handle = create_temp_file(0))) return;
apc_count = 0;
U(iosb).Status = 0xdeadbabe;
iosb.Information = 0xdeadbeef;
offset.QuadPart = 0;
pNtWriteFile( handle, event, apc, &apc_count, &iosb, text, strlen(text), &offset, NULL );
ok( status == STATUS_END_OF_FILE, "wrong status %x\n", status );
ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status );
ok( iosb.Information == strlen(text), "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 == 1, "apc was not called\n" );
apc_count = 0;
U(iosb).Status = 0xdeadbabe;
iosb.Information = 0xdeadbeef;
offset.QuadPart = 0;
ResetEvent( event );
status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, strlen(text) + 10, &offset, NULL );
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status );
ok( iosb.Information == strlen(text), "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 */
todo_wine ok( !apc_count, "apc was called\n" );
/* read beyond eof */
apc_count = 0;
U(iosb).Status = 0xdeadbabe;
iosb.Information = 0xdeadbeef;
offset.QuadPart = strlen(text) + 2;
ResetEvent( event );
status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, &offset, NULL );
ok( status == STATUS_END_OF_FILE, "wrong status %x\n", status );
todo_wine ok( U(iosb).Status == STATUS_END_OF_FILE, "wrong status %x\n", U(iosb).Status );
todo_wine ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
todo_wine ok( is_signaled( event ), "event is not signaled\n" );
ok( !apc_count, "apc was called\n" );
SleepEx( 1, TRUE ); /* alertable sleep */
ok( !apc_count, "apc was called\n" );
CloseHandle( handle );
CloseHandle( event );
}
static void nt_mailslot_test(void)
{
HANDLE hslot;
@ -139,7 +434,10 @@ START_TEST(file)
pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString");
pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString");
pNtCreateMailslotFile = (void *)GetProcAddress(hntdll, "NtCreateMailslotFile");
pNtReadFile = (void *)GetProcAddress(hntdll, "NtReadFile");
pNtWriteFile = (void *)GetProcAddress(hntdll, "NtWriteFile");
pNtClose = (void *)GetProcAddress(hntdll, "NtClose");
read_file_test();
nt_mailslot_test();
}