Changping Yu : kernel32/tests: Add test for thread enumeration order in toolhelp.
Alexandre Julliard
julliard at winehq.org
Tue Nov 10 13:46:24 CST 2020
Module: wine
Branch: stable
Commit: ea0920da0a3ddf0fbc5469657c783b00de1930e4
URL: https://source.winehq.org/git/wine.git/?a=commit;h=ea0920da0a3ddf0fbc5469657c783b00de1930e4
Author: Changping Yu <dead.ash at hotmail.com>
Date: Mon Jun 29 11:25:01 2020 +0800
kernel32/tests: Add test for thread enumeration order in toolhelp.
Signed-off-by: Changping Yu <dead.ash at hotmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
(cherry picked from commit ab7485bb4beccae445717719bff718f11f80e3d5)
Signed-off-by: Michael Stefaniuc <mstefani at winehq.org>
---
dlls/kernel32/tests/toolhelp.c | 174 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 172 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/tests/toolhelp.c b/dlls/kernel32/tests/toolhelp.c
index bdb01b9824d..7ec0b3aab3a 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,166 @@ 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 i, 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, TRUE, FALSE, NULL);
+ ok(ev != NULL, "Cannot create event\n");
+
+ for (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 != PtrToUlong(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 == PtrToUlong(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 (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 (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 (i = 0; i < NUM_THREADS; i++)
+ {
+ if (thread_traversed[i] != thread_ids[i])
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ todo_wine
+ ok(found == FALSE, "wrong order in NtQuerySystemInformation function\n");
+
+ SetEvent(ev);
+ WaitForMultipleObjects( NUM_THREADS, threads, TRUE, WAIT_TIME );
+ for (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(ULongToPtr(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, ULongToPtr(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;
@@ -158,7 +324,7 @@ static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid)
int num = 0;
unsigned curr_found = 0;
unsigned sub_found = 0;
-
+
hSnapshot = pCreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
ok(hSnapshot != NULL, "Cannot create snapshot\n");
@@ -291,6 +457,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 +466,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 +508,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));
More information about the wine-cvs
mailing list