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:
parent
43be3507c0
commit
ab7485bb4b
|
@ -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));
|
||||
|
||||
|
|
Loading…
Reference in New Issue