kernel32/tests: Add test for thread enumeration order in toolhelp.

Signed-off-by: Changping Yu <dead.ash@hotmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Changping Yu 2020-06-29 11:25:01 +08:00 committed by Alexandre Julliard
parent 43be3507c0
commit ab7485bb4b
1 changed files with 172 additions and 2 deletions

View File

@ -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));