[PATCH v6 1/2] kernel32/tests: Add test about toolhelp to get thread order.

Changping Yu dead.ash at hotmail.com
Sun Jun 28 22:42:10 CDT 2020


>From e1df33c6faabfbf3fe10b4372bb9c2298ceed071 Mon Sep 17 00:00:00 2001
From: Changping Yu <dead.ash at hotmail.com>
Date: Mon, 29 Jun 2020 11:25:01 +0800
Subject: [PATCH v6 1/2] kernel32/tests: Add test about toolhelp to get
 thread order.

v6: Adjust the code to make the NtQuerySystemInformation function judgment take effect
Signed-off-by: Changping Yu <dead.ash at hotmail.com>
---
 dlls/kernel32/tests/toolhelp.c | 171 ++++++++++++++++++++++++++++++++-
 1 file changed, 170 insertions(+), 1 deletion(-)

diff --git a/dlls/kernel32/tests/toolhelp.c b/dlls/kernel32/tests/toolhelp.c
index 9250f8dc54..15c6309aac 100644
--- a/dlls/kernel32/tests/toolhelp.c
+++ b/dlls/kernel32/tests/toolhelp.c
@@ -22,11 +22,14 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
 #include "tlhelp32.h"
 #include "wine/test.h"
 #include "winuser.h"
+#include "winternl.h"
 
 static char     selfname[MAX_PATH];
 
@@ -38,9 +41,12 @@ static BOOL (WINAPI *pProcess32First)(HANDLE, LPPROCESSENTRY32);
 static BOOL (WINAPI *pProcess32Next)(HANDLE, LPPROCESSENTRY32);
 static BOOL (WINAPI *pThread32First)(HANDLE, LPTHREADENTRY32);
 static BOOL (WINAPI *pThread32Next)(HANDLE, LPTHREADENTRY32);
+static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, void *, ULONG, ULONG *);
 
 /* 1 minute should be more than enough */
 #define WAIT_TIME       (60 * 1000)
+/* Specify the number of simultaneous threads to test */
+#define NUM_THREADS 4
 
 static DWORD WINAPI sub_thread(void* pmt)
 {
@@ -150,6 +156,165 @@ static void test_process(DWORD curr_pid, DWORD sub_pcs_pid)
     ok(!pProcess32First( hSnapshot, &pe ), "shouldn't return a process\n");
 }
 
+static DWORD WINAPI get_id_thread(void* curr_pid)
+{
+    HANDLE              hSnapshot;
+    THREADENTRY32       te;
+    HANDLE              ev, threads[NUM_THREADS];
+    DWORD               thread_ids[NUM_THREADS];
+    DWORD               thread_traversed[NUM_THREADS];
+    DWORD               tid, first_tid = 0;
+    BOOL                found = FALSE;
+    int                 matched_idx = -1;
+    ULONG               buf_size = 0;
+    NTSTATUS            status;
+    BYTE*               pcs_buffer = NULL;
+    DWORD               pcs_offset = 0;
+    SYSTEM_PROCESS_INFORMATION* spi = NULL;
+
+    ev = CreateEventW(NULL, FALSE, FALSE, NULL);
+    ok(ev != NULL, "Cannot create event\n");
+
+    for (int i = 0; i < NUM_THREADS; i++)
+    {
+        threads[i] = CreateThread(NULL, 0, sub_thread, ev, 0, &tid);
+        ok(threads[i] != NULL, "Cannot create thread\n");
+        thread_ids[i] = tid;
+    }
+
+    hSnapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
+    ok(hSnapshot != NULL, "Cannot create snapshot\n");
+
+    /* Check that this current process is enumerated */
+    te.dwSize = sizeof(te);
+    ok(pThread32First(hSnapshot, &te), "Thread cannot traverse\n");
+    do
+    {
+        if (found)
+        {
+            if (te.th32OwnerProcessID != (DWORD)curr_pid) break;
+
+            if (matched_idx >= 0)
+            {
+                thread_traversed[matched_idx++] = te.th32ThreadID;
+                if (matched_idx >= NUM_THREADS) break;
+            }
+            else if (thread_ids[0] == te.th32ThreadID)
+            {
+                matched_idx = 0;
+                thread_traversed[matched_idx++] = te.th32ThreadID;
+            }
+        }
+        else if (te.th32OwnerProcessID == (DWORD)curr_pid)
+        {
+            found = TRUE;
+            first_tid = te.th32ThreadID;
+        }
+    }
+    while (pThread32Next(hSnapshot, &te));
+
+    ok(found, "Couldn't find self and/or sub-process in process list\n");
+
+    /* Check if the thread order is strictly consistent */
+    found = FALSE;
+    for (int i = 0; i < NUM_THREADS; i++)
+    {
+        if (thread_traversed[i] != thread_ids[i])
+        {
+            found = TRUE;
+            break;
+        }
+        /* Reset data */
+        thread_traversed[i] = 0;
+    }
+    todo_wine
+    ok(found == FALSE, "The thread order is not strictly consistent\n");
+
+    /* Determine the order by NtQuerySystemInformation function */
+    pcs_buffer = NULL;
+    status = pNtQuerySystemInformation(SystemProcessInformation, pcs_buffer, buf_size, &buf_size);
+    ok(status == STATUS_INFO_LENGTH_MISMATCH, "Failed with %x\n", status);
+    if (status == STATUS_INFO_LENGTH_MISMATCH)
+    {
+        pcs_buffer = HeapAlloc(GetProcessHeap(), 0, buf_size);
+        ok(pcs_buffer != NULL, "Unable to allocate space\n");
+        found = FALSE;
+        matched_idx = -1;
+
+        status = NtQuerySystemInformation(SystemProcessInformation, pcs_buffer, buf_size, &buf_size);
+        do {
+            spi = (SYSTEM_PROCESS_INFORMATION*)&pcs_buffer[pcs_offset];
+            if (spi->UniqueProcessId == curr_pid)
+            {
+                found = TRUE;
+                break;
+            }
+            pcs_offset += spi->NextEntryOffset;
+        } while (spi->NextEntryOffset != 0);
+
+        ok(found && spi, "No process found\n");
+        for (unsigned int i = 0; i < spi->dwThreadCount; i++)
+        {
+            tid = HandleToULong(spi->ti[i].ClientId.UniqueThread);
+            if (matched_idx > 0)
+            {
+                thread_traversed[matched_idx++] = tid;
+                if (matched_idx >= NUM_THREADS) break;
+            }
+            else if (tid == thread_ids[0])
+            {
+                matched_idx = 0;
+                thread_traversed[matched_idx++] = tid;
+            }
+        }
+	}
+    if (pcs_buffer)
+        HeapFree(GetProcessHeap(), 0, pcs_buffer);
+
+    ok(matched_idx > 0, "No thread id match found\n");
+
+    found = FALSE;
+    for (int i = 0; i < NUM_THREADS; i++)
+    {
+        if (thread_traversed[i] != thread_ids[i])
+        {
+            found = TRUE;
+            break;
+        }
+    }
+    todo_wine
+    ok(found == FALSE, "Judge the failure of traversing thread by NtQuerySystemInformation function\n");
+
+    SetEvent(ev);
+    for (int i = 0; i < NUM_THREADS; i++)
+        CloseHandle(threads[i]);
+    CloseHandle(ev);
+    CloseHandle(hSnapshot);
+
+    return first_tid;
+}
+
+static void test_main_thread(DWORD curr_pid, DWORD main_tid)
+{
+    HANDLE              thread;
+    DWORD               tid = 0;
+    int                 error;
+
+    /* Check that the main thread id is first one in this thread. */
+    tid = get_id_thread((void *)curr_pid);
+    todo_wine
+    ok(tid == main_tid, "The first thread id returned is not the main thread id\n");
+
+    /* Check that the main thread id is first one in other thread. */
+    thread = CreateThread(NULL, 0, get_id_thread, (void *)curr_pid, 0, NULL);
+    error = WaitForSingleObject(thread, WAIT_TIME);
+    ok(error == WAIT_OBJECT_0, "Thread did not complete within timelimit\n");
+
+    ok(GetExitCodeThread(thread, &tid), "Could not retrieve exit code\n");
+    todo_wine
+    ok(tid == main_tid, "The first thread id returned is not the main thread id\n");
+}
+
 static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid)
 {
     HANDLE              hSnapshot;
@@ -291,6 +456,7 @@ START_TEST(toolhelp)
     HANDLE              ev1, ev2;
     DWORD               w;
     HANDLE              hkernel32 = GetModuleHandleA("kernel32");
+    HANDLE              hntdll = GetModuleHandleA("ntdll.dll");
 
     pCreateToolhelp32Snapshot = (VOID *) GetProcAddress(hkernel32, "CreateToolhelp32Snapshot");
     pModule32First = (VOID *) GetProcAddress(hkernel32, "Module32First");
@@ -299,11 +465,13 @@ START_TEST(toolhelp)
     pProcess32Next = (VOID *) GetProcAddress(hkernel32, "Process32Next");
     pThread32First = (VOID *) GetProcAddress(hkernel32, "Thread32First");
     pThread32Next = (VOID *) GetProcAddress(hkernel32, "Thread32Next");
+    pNtQuerySystemInformation = (VOID *) GetProcAddress(hntdll, "NtQuerySystemInformation");
 
     if (!pCreateToolhelp32Snapshot || 
         !pModule32First || !pModule32Next ||
         !pProcess32First || !pProcess32Next ||
-        !pThread32First || !pThread32Next)
+        !pThread32First || !pThread32Next ||
+        !pNtQuerySystemInformation)
     {
         win_skip("Needed functions are not available, most likely running on Windows NT\n");
         return;
@@ -339,6 +507,7 @@ START_TEST(toolhelp)
 
     test_process(pid, info.dwProcessId);
     test_thread(pid, info.dwProcessId);
+    test_main_thread(pid, GetCurrentThreadId());
     test_module(pid, curr_expected_modules, ARRAY_SIZE(curr_expected_modules));
     test_module(info.dwProcessId, sub_expected_modules, ARRAY_SIZE(sub_expected_modules));
 
-- 
2.27.0.windows.1



More information about the wine-devel mailing list