[prev in list] [next in list] [prev in thread] [next in thread]
List: wine-devel
Subject: [PATCH 1/3 v3] ntdll/tests: Add more I/O blocking and completion tests.
From: Jacek Caban <jacek () codeweavers ! com>
Date: 2018-10-31 15:44:49
Message-ID: 8ff5ce44-ae46-3eed-fa40-81cc9248a4c4 () codeweavers ! com
[Download RAW message or body]
Signed-off-by: Jacek Caban <jacek@codeweavers.com>
---
dlls/ntdll/tests/pipe.c | 319 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 318 insertions(+), 1 deletion(-)
["0001-ntdll-tests-Add-more-I-O-blocking-and-completion-test.diff" (text/x-patch)]
diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c
index 20bfc736e4..fe650124d8 100644
--- a/dlls/ntdll/tests/pipe.c
+++ b/dlls/ntdll/tests/pipe.c
@@ -1241,7 +1241,7 @@ static void test_completion(void)
FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info;
FILE_PIPE_PEEK_BUFFER peek_buf;
char read_buf[16];
- HANDLE port, pipe, client;
+ HANDLE port, pipe, client, event;
OVERLAPPED ov;
IO_STATUS_BLOCK io;
NTSTATUS status;
@@ -1341,6 +1341,319 @@ static void test_completion(void)
CloseHandle(client);
CloseHandle(pipe);
CloseHandle(port);
+
+ event = CreateEventW(NULL, TRUE, TRUE, NULL);
+ create_pipe_pair( &pipe, &client, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 4096 );
+
+ ok(is_signaled(client), "client is not signaled\n");
+
+ if (broken(1)) { /* blocks on wine */
+ /* no event, APC nor completion: only signals on handle */
+ memset(&io, 0xcc, sizeof(io));
+ status = NtReadFile(client, NULL, NULL, NULL, &io, read_buf, sizeof(read_buf), \
NULL, NULL); + ok(status == STATUS_PENDING, "status = %x\n", status);
+ ok(!is_signaled(client), "client is signaled\n");
+
+ ret = WriteFile(pipe, buf, sizeof(buf), &num_bytes, NULL);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+ ok(is_signaled(client), "client is signaled\n");
+ ok(io.Status == STATUS_SUCCESS, "Status = %x\n", io.Status);
+ ok(io.Information == sizeof(buf), "Information = %lu\n", io.Information);
+ }
+
+ /* event with no APC nor completion: signals only event */
+ memset(&io, 0xcc, sizeof(io));
+ status = NtReadFile(client, event, NULL, NULL, &io, read_buf, sizeof(read_buf), \
NULL, NULL); + ok(status == STATUS_PENDING, "status = %x\n", status);
+ ok(!is_signaled(client), "client is signaled\n");
+ ok(!is_signaled(event), "event is signaled\n");
+
+ ret = WriteFile(pipe, buf, sizeof(buf), &num_bytes, NULL);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+ ok(!is_signaled(client), "client is signaled\n");
+ ok(is_signaled(event), "event is not signaled\n");
+ ok(io.Status == STATUS_SUCCESS, "Status = %x\n", io.Status);
+ ok(io.Information == sizeof(buf), "Information = %lu\n", io.Information);
+
+ /* APC with no event: handle is signaled */
+ ioapc_called = FALSE;
+ memset(&io, 0xcc, sizeof(io));
+ status = NtReadFile(client, NULL, ioapc, &io, &io, read_buf, sizeof(read_buf), \
NULL, NULL); + ok(status == STATUS_PENDING, "status = %x\n", status);
+ ok(!is_signaled(client), "client is signaled\n");
+
+ ret = WriteFile(pipe, buf, sizeof(buf), &num_bytes, NULL);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+ ok(is_signaled(client), "client is signaled\n");
+ ok(io.Status == STATUS_SUCCESS, "Status = %x\n", io.Status);
+ ok(io.Information == sizeof(buf), "Information = %lu\n", io.Information);
+
+ ok(!ioapc_called, "ioapc called\n");
+ SleepEx(0, TRUE);
+ ok(ioapc_called, "ioapc not called\n");
+
+ /* completion with no completion port: handle signaled */
+ memset(&io, 0xcc, sizeof(io));
+ status = NtReadFile(client, NULL, NULL, &io, &io, read_buf, sizeof(read_buf), \
NULL, NULL); + ok(status == STATUS_PENDING, "status = %x\n", status);
+ ok(!is_signaled(client), "client is signaled\n");
+
+ ret = WriteFile(pipe, buf, sizeof(buf), &num_bytes, NULL);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+ ok(is_signaled(client), "client is not signaled\n");
+
+ port = CreateIoCompletionPort(client, NULL, 0xdeadbeef, 0);
+ ok(port != NULL, "CreateIoCompletionPort failed, error %u\n", GetLastError());
+
+ /* skipping completion on succcess: handle is signaled */
+ info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
+ status = pNtSetInformationFile(client, &io, &info, sizeof(info), \
FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS, "expected \
STATUS_SUCCESS, got %08x\n", status); + ok(is_signaled(client), "client is not \
signaled\n"); +
+ memset(&io, 0xcc, sizeof(io));
+ status = NtReadFile(client, NULL, NULL, &io, &io, read_buf, sizeof(read_buf), \
NULL, NULL); + ok(status == STATUS_PENDING, "status = %x\n", status);
+ ok(!is_signaled(client), "client is signaled\n");
+
+ ret = WriteFile(client, buf, 1, &num_bytes, NULL);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+ ok(is_signaled(client), "client is not signaled\n");
+
+ /* skipping set event on handle: handle is never signaled */
+ info.Flags = FILE_SKIP_SET_EVENT_ON_HANDLE;
+ status = pNtSetInformationFile(client, &io, &info, sizeof(info), \
FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS, "expected \
STATUS_SUCCESS, got %08x\n", status); + todo_wine
+ ok(!is_signaled(client), "client is not signaled\n");
+
+ ret = WriteFile(pipe, buf, sizeof(buf), &num_bytes, NULL);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+ todo_wine
+ ok(!is_signaled(client), "client is signaled\n");
+ test_queued_completion(port, &io, STATUS_SUCCESS, sizeof(buf));
+
+ if (broken(1)) { /* blocks on wine */
+ memset(&io, 0xcc, sizeof(io));
+ status = NtReadFile(client, NULL, NULL, NULL, &io, read_buf, sizeof(read_buf), \
NULL, NULL); + ok(status == STATUS_PENDING, "status = %x\n", status);
+ ok(!is_signaled(client), "client is signaled\n");
+ }
+
+ ret = WriteFile(client, buf, 1, &num_bytes, NULL);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+ todo_wine
+ ok(!is_signaled(client), "client is signaled\n");
+
+ ret = WriteFile(pipe, buf, sizeof(buf), &num_bytes, NULL);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+ todo_wine
+ ok(!is_signaled(client), "client is signaled\n");
+
+ CloseHandle(port);
+ CloseHandle(client);
+ CloseHandle(pipe);
+}
+
+struct blocking_thread_args
+{
+ HANDLE wait;
+ HANDLE done;
+ enum {
+ BLOCKING_THREAD_WRITE,
+ BLOCKING_THREAD_READ,
+ BLOCKING_THREAD_QUIT
+ } cmd;
+ HANDLE client;
+ HANDLE pipe;
+ HANDLE event;
+};
+
+static DWORD WINAPI blocking_thread(void *arg)
+{
+ struct blocking_thread_args *ctx = arg;
+ static const char buf[] = "testdata";
+ char read_buf[32];
+ DWORD res, num_bytes;
+ BOOL ret;
+
+ for (;;)
+ {
+ res = WaitForSingleObject(ctx->wait, 10000);
+ ok(res == WAIT_OBJECT_0, "wait returned %x\n", res);
+ if (res != WAIT_OBJECT_0) break;
+ switch(ctx->cmd) {
+ case BLOCKING_THREAD_WRITE:
+ Sleep(100);
+ if(ctx->event)
+ ok(!is_signaled(ctx->event), "event is signaled\n");
+ ok(!ioapc_called, "ioapc called\n");
+ ok(!is_signaled(ctx->client), "client is signaled\n");
+ ok(is_signaled(ctx->pipe), "pipe is not signaled\n");
+ ret = WriteFile(ctx->pipe, buf, 1, &num_bytes, NULL);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+ break;
+ case BLOCKING_THREAD_READ:
+ Sleep(100);
+ if(ctx->event)
+ ok(!is_signaled(ctx->event), "event is signaled\n");
+ ok(!ioapc_called, "ioapc called\n");
+ ok(!is_signaled(ctx->client), "client is signaled\n");
+ ok(is_signaled(ctx->pipe), "pipe is not signaled\n");
+ ret = ReadFile(ctx->pipe, read_buf, 1, &num_bytes, NULL);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+ break;
+ case BLOCKING_THREAD_QUIT:
+ return 0;
+ default:
+ ok(0, "unvalid command\n");
+ }
+ SetEvent(ctx->done);
+ }
+
+ return 1;
+}
+
+static void test_blocking(ULONG options)
+{
+ struct blocking_thread_args ctx;
+ OBJECT_ATTRIBUTES attr;
+ UNICODE_STRING name;
+ char read_buf[16];
+ HANDLE thread;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ DWORD res, num_bytes;
+ BOOL ret;
+
+ ctx.wait = CreateEventW(NULL, FALSE, FALSE, NULL);
+ ctx.done = CreateEventW(NULL, FALSE, FALSE, NULL);
+ thread = CreateThread(NULL, 0, blocking_thread, &ctx, 0, 0);
+ ok(thread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", \
GetLastError()); +
+ status = create_pipe(&ctx.pipe, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | \
FILE_SHARE_WRITE, + options);
+ ok(status == STATUS_SUCCESS, "NtCreateNamedPipeFile returned %x\n", status);
+
+ pRtlInitUnicodeString(&name, testpipe_nt);
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.ObjectName = &name;
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+ status = NtCreateFile(&ctx.client, SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE, \
&attr, &io, + NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, \
FILE_OPEN, + options, NULL, 0 );
+ ok(status == STATUS_SUCCESS, "NtCreateFile returned %x\n", status);
+
+ ok(is_signaled(ctx.client), "client is not signaled\n");
+ ok(is_signaled(ctx.pipe), "pipe is not signaled\n");
+
+ /* blocking read with no event nor APC */
+ ioapc_called = FALSE;
+ memset(&io, 0xff, sizeof(io));
+ ctx.cmd = BLOCKING_THREAD_WRITE;
+ ctx.event = NULL;
+ SetEvent(ctx.wait);
+ status = NtReadFile(ctx.client, NULL, NULL, NULL, &io, read_buf, \
sizeof(read_buf), NULL, NULL); + ok(status == STATUS_SUCCESS, "status = %x\n", \
status); + ok(io.Status == STATUS_SUCCESS, "Status = %x\n", io.Status);
+ ok(io.Information == 1, "Information = %lu\n", io.Information);
+ ok(is_signaled(ctx.client), "client is not signaled\n");
+ ok(is_signaled(ctx.pipe), "pipe is not signaled\n");
+
+ res = WaitForSingleObject(ctx.done, 10000);
+ ok(res == WAIT_OBJECT_0, "wait returned %x\n", res);
+
+ /* blocking read with event and APC */
+ ioapc_called = FALSE;
+ memset(&io, 0xff, sizeof(io));
+ ctx.cmd = BLOCKING_THREAD_WRITE;
+ ctx.event = CreateEventW(NULL, TRUE, TRUE, NULL);
+ SetEvent(ctx.wait);
+ status = NtReadFile(ctx.client, ctx.event, ioapc, &io, &io, read_buf,
+ sizeof(read_buf), NULL, NULL);
+ todo_wine
+ ok(status == STATUS_SUCCESS, "status = %x\n", status);
+ if (status == STATUS_PENDING) WaitForSingleObject(ctx.event, INFINITE);
+ ok(io.Status == STATUS_SUCCESS, "Status = %x\n", io.Status);
+ ok(io.Information == 1, "Information = %lu\n", io.Information);
+ ok(is_signaled(ctx.event), "event is not signaled\n");
+ todo_wine
+ ok(is_signaled(ctx.client), "client is not signaled\n");
+ ok(is_signaled(ctx.pipe), "pipe is not signaled\n");
+
+ if (!(options & FILE_SYNCHRONOUS_IO_ALERT))
+ ok(!ioapc_called, "ioapc called\n");
+ SleepEx(0, TRUE); /* alertable wait state */
+ ok(ioapc_called, "ioapc not called\n");
+
+ res = WaitForSingleObject(ctx.done, 10000);
+ ok(res == WAIT_OBJECT_0, "wait returned %x\n", res);
+ ioapc_called = FALSE;
+ CloseHandle(ctx.event);
+ ctx.event = NULL;
+
+ /* blocking flush */
+ ret = WriteFile(ctx.client, read_buf, 1, &num_bytes, NULL);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+
+ ioapc_called = FALSE;
+ memset(&io, 0xff, sizeof(io));
+ ctx.cmd = BLOCKING_THREAD_READ;
+ SetEvent(ctx.wait);
+ status = NtFlushBuffersFile(ctx.client, &io);
+ ok(status == STATUS_SUCCESS, "status = %x\n", status);
+ ok(io.Status == STATUS_SUCCESS, "Status = %x\n", io.Status);
+ ok(io.Information == 0, "Information = %lu\n", io.Information);
+ ok(is_signaled(ctx.client), "client is not signaled\n");
+
+ res = WaitForSingleObject(ctx.done, 10000);
+ ok(res == WAIT_OBJECT_0, "wait returned %x\n", res);
+
+ ok(is_signaled(ctx.pipe), "pipe is not signaled\n");
+ CloseHandle(ctx.pipe);
+ CloseHandle(ctx.client);
+
+ /* flush is blocking even in overlapped mode */
+ create_pipe_pair(&ctx.pipe, &ctx.client, PIPE_ACCESS_DUPLEX | \
FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | \
PIPE_READMODE_MESSAGE, 4096); +
+ ok(is_signaled(ctx.client), "client is not signaled\n");
+ ok(is_signaled(ctx.pipe), "pipe is not signaled\n");
+
+ ret = WriteFile(ctx.client, read_buf, 1, &num_bytes, NULL);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+
+ ok(is_signaled(ctx.client), "client is not signaled\n");
+ ok(is_signaled(ctx.pipe), "pipe is not signaled\n");
+
+ ioapc_called = FALSE;
+ memset(&io, 0xff, sizeof(io));
+ ctx.cmd = BLOCKING_THREAD_READ;
+ SetEvent(ctx.wait);
+ status = NtFlushBuffersFile(ctx.client, &io);
+ ok(status == STATUS_SUCCESS, "status = %x\n", status);
+ ok(io.Status == STATUS_SUCCESS, "Status = %x\n", io.Status);
+ ok(io.Information == 0, "Information = %lu\n", io.Information);
+ /* client signaling is inconsistent in this case */
+
+ res = WaitForSingleObject(ctx.done, 10000);
+ ok(res == WAIT_OBJECT_0, "wait returned %x\n", res);
+
+ CloseHandle(ctx.pipe);
+ CloseHandle(ctx.client);
+
+ ctx.cmd = BLOCKING_THREAD_QUIT;
+ SetEvent(ctx.wait);
+ res = WaitForSingleObject(thread, 10000);
+ ok(res == WAIT_OBJECT_0, "wait returned %x\n", res);
+
+ CloseHandle(ctx.wait);
+ CloseHandle(ctx.done);
+ CloseHandle(thread);
}
static void test_volume_info(void)
@@ -2092,6 +2405,10 @@ START_TEST(pipe)
trace("starting completion tests\n");
test_completion();
+ trace("starting blocking tests\n");
+ test_blocking(FILE_SYNCHRONOUS_IO_NONALERT);
+ test_blocking(FILE_SYNCHRONOUS_IO_ALERT);
+
trace("starting FILE_PIPE_INFORMATION tests\n");
test_filepipeinfo();
[Attachment #4 (text/plain)]
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic