[PATCH v2 3/3] ntdll/tests: Add a test for closing a completion port being waited on.

Alexey Prokhin alexey at prokhin.ru
Wed Apr 29 10:26:42 CDT 2020


The test reproduces a hang by Planet Zoo when exiting the game.

Signed-off-by: Alexey Prokhin <alexey at prokhin.ru>
---
v2: Update kernelbase patch. Supersedes 184509

Given it is one of my first contributions to wine, I have a few
questions/notes:

1.
> LPTHREAD_START_ROUTINE test_routines[] = {

I didn't find such pattern anywhere else in the tests, but I hope
it's ok.

2.
> ok( info[0].CompletionKey == 0xdeadbeef || info[0].CompletionKey == 0,

I am not sure if info should be checked at all in the case. And if
it is, should I mark the second equality as broken? (Because info
is only zeroed out on win server 2008)

3. Is it ok there is a test for GetQueuedCompletionStatus. Or
should it be moved to kernelbase?

4. Should a test for GetQueuedCompletionStatusEx also be added?
---
 dlls/ntdll/tests/file.c | 101 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 101 insertions(+)

diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 31c18454f0..c5fb28e16f 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -4953,6 +4953,106 @@ static void test_file_readonly_access(void)
     DeleteFileW(path);
 }
 
+static DWORD WINAPI io_thread_NtRemoveIoCompletion(void *data)
+{
+    LARGE_INTEGER timeout;
+    IO_STATUS_BLOCK iosb;
+    ULONG_PTR key, value;
+    HANDLE h = data;
+    NTSTATUS res;
+
+    timeout.QuadPart = -30000000;
+    res = pNtRemoveIoCompletion( h, &key, &value, &iosb, &timeout );
+    ok( res == STATUS_ABANDONED_WAIT_0 || broken( res == STATUS_TIMEOUT ), /* XP/2003 */
+        "expected STATUS_ABANDONED_WAIT_0, got %#x\n", res );
+    /* key, value and iosb either are unchanged or contain garbage */
+
+    return 0;
+}
+
+static DWORD WINAPI io_thread_NtRemoveIoCompletionEx(void *data)
+{
+    FILE_IO_COMPLETION_INFORMATION info[2] = {{0}};
+    LARGE_INTEGER timeout;
+    HANDLE h = data;
+    NTSTATUS res;
+    ULONG count;
+
+    if (!pNtRemoveIoCompletionEx)
+    {
+        skip("NtRemoveIoCompletionEx() not present\n");
+        return 1;
+    }
+
+    timeout.QuadPart = -30000000;
+    count = 0xdeadbeef;
+    info[0].CompletionKey = 0xdeadbeef;
+    info[0].CompletionValue = 0xdeadbeef;
+    info[0].IoStatusBlock.Information = 0xdeadbeef;
+    U(info[0].IoStatusBlock).Status = 0xdeadbeef;
+
+    res = pNtRemoveIoCompletionEx( h, info, 2, &count, &timeout, FALSE );
+    ok( res == STATUS_ABANDONED_WAIT_0, "expected STATUS_ABANDONED_WAIT_0, got %#x\n", res );
+    ok( count == 1, "wrong count %u\n", count );
+    ok( info[0].CompletionKey == 0xdeadbeef || info[0].CompletionKey == 0,
+        "wrong key %#lx\n", info[0].CompletionKey );
+    ok( info[0].CompletionValue == 0xdeadbeef || info[0].CompletionValue == 0,
+        "wrong value %#lx\n", info[0].CompletionValue );
+    ok( info[0].IoStatusBlock.Information == 0xdeadbeef || info[0].IoStatusBlock.Information == 0,
+        "wrong information %#lx\n", info[0].IoStatusBlock.Information );
+    ok( U(info[0].IoStatusBlock).Status == 0xdeadbeef || U(info[0].IoStatusBlock).Status == 0,
+        "wrong status %#x\n", U(info[0].IoStatusBlock).Status);
+
+    return 0;
+}
+
+static DWORD WINAPI io_thread_GetQueuedCompletionStatus(void *data)
+{
+    HANDLE h = data;
+    OVERLAPPED *pov;
+    NTSTATUS error;
+    ULONG_PTR key;
+    DWORD count;
+    BOOL ret;
+
+    pov = (void *)0xdeadbeaf;
+    SetLastError(0xdeadbeef);
+    ret = GetQueuedCompletionStatus( h, &count, &key, &pov, 3000 );
+    error = GetLastError();
+    ok( !ret, "GetQueuedCompletionStatus succeeded\n" );
+    ok( error == ERROR_ABANDONED_WAIT_0 || broken( error == WAIT_TIMEOUT ), /* XP/2003 */
+        "expected ERROR_ABANDONED_WAIT_0, got %#x\n", error );
+    ok( pov == NULL, "expected NULL, got %p\n", pov );
+
+    return 0;
+}
+
+static void test_close_io_completion(void)
+{
+    HANDLE h, hThread;
+    NTSTATUS res;
+    LPTHREAD_START_ROUTINE test_routines[] = {
+        io_thread_NtRemoveIoCompletion,
+        io_thread_NtRemoveIoCompletionEx,
+        io_thread_GetQueuedCompletionStatus
+    };
+
+    for (int i = 0; i < ARRAY_SIZE(test_routines); ++i)
+    {
+        res = pNtCreateIoCompletion( &h, IO_COMPLETION_ALL_ACCESS, NULL, 0 );
+        ok( res == STATUS_SUCCESS, "%d: NtCreateIoCompletion failed: %#x\n", i, res );
+        ok( h && h != INVALID_HANDLE_VALUE, "%d: got invalid handle %p\n", i, h );
+
+        hThread = CreateThread( NULL, 0, test_routines[i], h, 0, NULL );
+        Sleep( 400 );
+
+        CloseHandle( h );
+
+        ok( WaitForSingleObject( hThread, 10000 ) == 0, "%d: wait failed\n", i );
+        CloseHandle( hThread );
+    }
+}
+
 START_TEST(file)
 {
     HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
@@ -5023,4 +5123,5 @@ START_TEST(file)
     test_query_attribute_information_file();
     test_ioctl();
     test_flush_buffers_file();
+    test_close_io_completion();
 }
-- 
2.26.2




More information about the wine-devel mailing list