[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