From: Marc-Aurel Zent mzent@codeweavers.com
--- dlls/ntdll/tests/info.c | 135 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index d24639b6b68..b92d421891f 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -31,7 +31,18 @@ #include "psapi.h" #include "wine/test.h"
+struct PROCESS_BASIC_INFORMATION_PRIVATE +{ + NTSTATUS ExitStatus; + PPEB PebBaseAddress; + DWORD_PTR AffinityMask; + DWORD_PTR BasePriority; + ULONG_PTR UniqueProcessId; + ULONG_PTR InheritedFromUniqueProcessId; +}; + static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); +static NTSTATUS (WINAPI * pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); static NTSTATUS (WINAPI * pNtSetSystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG); static NTSTATUS (WINAPI * pRtlGetNativeSystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); static NTSTATUS (WINAPI * pNtQuerySystemInformationEx)(SYSTEM_INFORMATION_CLASS, void*, ULONG, void*, ULONG, ULONG*); @@ -90,6 +101,7 @@ static void InitFunctionPtrs(void) HMODULE hkernel32 = GetModuleHandleA("kernel32");
NTDLL_GET_PROC(NtQuerySystemInformation); + NTDLL_GET_PROC(NtQueryInformationProcess); NTDLL_GET_PROC(NtQuerySystemInformationEx); NTDLL_GET_PROC(NtSetSystemInformation); NTDLL_GET_PROC(RtlGetNativeSystemInformation); @@ -3263,6 +3275,128 @@ static void test_affinity(void) "Unexpected thread affinity\n" ); }
+static void test_priority(void) +{ + NTSTATUS status; + DWORD proc_priority; + int thread_base_priority, expected_nt_priority; + ULONG nt_thread_priority; + THREAD_BASIC_INFORMATION tbi; + DECLSPEC_ALIGN(8) PROCESS_PRIORITY_CLASS ppc; /* needs align, or STATUS_DATATYPE_MISALIGNMENT is returned */ + struct PROCESS_BASIC_INFORMATION_PRIVATE pbi; + BOOL ret; + + /* Change process priority class to HIGH_PRIORITY_CLASS and test */ + ret = SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ); + ok( ret, "SetPriorityClass to HIGH_PRIORITY_CLASS failed: %lu\n", GetLastError() ); + proc_priority = GetPriorityClass( GetCurrentProcess() ); + ok( proc_priority == HIGH_PRIORITY_CLASS, "Expected HIGH_PRIORITY_CLASS, got %lu\n", proc_priority ); + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessPriorityClass, &ppc, sizeof(ppc), NULL ); + ok( status == STATUS_SUCCESS, "NtQueryInformationProcess failed: %08lx\n", status ); + ok( ppc.PriorityClass == PROCESS_PRIOCLASS_HIGH, "Expected PROCESS_PRIOCLASS_HIGH, got %lu\n", proc_priority ); + + /* Restore process priority back to normal */ + ret = SetPriorityClass( GetCurrentProcess(), NORMAL_PRIORITY_CLASS ); + ok( ret, "Restore SetPriorityClass failed: %lu\n", GetLastError() ); + proc_priority = GetPriorityClass( GetCurrentProcess() ); + ok( proc_priority == NORMAL_PRIORITY_CLASS, "Expected NORMAL_PRIORITY_CLASS after restore, got %lu\n", proc_priority ); + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessPriorityClass, &ppc, sizeof(ppc), NULL ); + ok( status == STATUS_SUCCESS, "NtQueryInformationProcess failed: %08lx\n", status ); + ok( ppc.PriorityClass == PROCESS_PRIOCLASS_NORMAL, "Expected PROCESS_PRIOCLASS_NORMAL, got %lu\n", proc_priority ); + + /* Before checking any thread priorities, disable priority boosting + * in order to make the tests reliable. */ + SetThreadPriorityBoost( GetCurrentThread(), TRUE ); + + /* Test thread priority: + * Compare the value from GetThreadPriority (thread priority level) + * with the BasePriority from NtQueryInformationThread. */ + thread_base_priority = GetThreadPriority( GetCurrentThread() ); + ok( thread_base_priority != THREAD_PRIORITY_ERROR_RETURN, "GetThreadPriority returned error\n" ); + + status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); + ok( status == STATUS_SUCCESS, "NtQueryInformationThread failed: %08lx\n", status ); + ok( thread_base_priority == tbi.BasePriority, "Thread priority mismatch: Win32 API returned %d, NT BasePriority is %ld\n", + thread_base_priority, tbi.BasePriority ); + + /* Change the thread priority to THREAD_PRIORITY_HIGHEST and compare with + * underlying NT priority, which should be now the NORMAL_PRIORITY_CLASS + * base value (8) + THREAD_PRIORITY_HIGHEST (+2) = 10 (without boost). */ + ret = SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST ); + ok( ret, "SetThreadPriority(THREAD_PRIORITY_HIGHEST) failed: %lu\n", GetLastError() ); + thread_base_priority = GetThreadPriority( GetCurrentThread() ); + ok( thread_base_priority == THREAD_PRIORITY_HIGHEST, "Expected THREAD_PRIORITY_HIGHEST (%d), got %d\n", + THREAD_PRIORITY_HIGHEST, thread_base_priority ); + + status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); + ok( status == STATUS_SUCCESS, "NtQueryInformationThread failed after setting priority: %08lx\n", status ); + ok( thread_base_priority == tbi.BasePriority, "After setting, API priority (%d) does not match NT BasePriority (%ld)\n", + thread_base_priority, tbi.BasePriority ); + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), NULL ); + expected_nt_priority = pbi.BasePriority + THREAD_PRIORITY_HIGHEST; + todo_wine ok( expected_nt_priority == tbi.Priority, "After setting, effective NT priority (%ld) does not match expected priority %d.\n", + tbi.Priority, expected_nt_priority ); + + /* Test setting the thread priority to THREAD_PRIORITY_LOWEST now, but using + * pNtSetInformationThread, also testing NT priority directly afterwards. */ + nt_thread_priority = THREAD_PRIORITY_LOWEST; + status = pNtSetInformationThread( GetCurrentThread(), ThreadBasePriority, &nt_thread_priority, sizeof(ULONG) ); + ok( status == STATUS_SUCCESS, "NtSetInformationThread(ThreadBasePriority) failed: %08lx\n", status ); + /* Effective thread priority should be now NORMAL_PRIORITY_CLASS base + * value (8) + THREAD_PRIORITY_LOWEST (-2) = 6. */ + status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); + ok( status == STATUS_SUCCESS, "NtQueryInformationThread failed after setting priority: %08lx\n", status ); + ok( nt_thread_priority == tbi.BasePriority, "After setting, BasePriority (%ld) does not match set BasePriority (%ld)\n", + nt_thread_priority, tbi.BasePriority ); + expected_nt_priority = pbi.BasePriority + THREAD_PRIORITY_LOWEST; + todo_wine ok( expected_nt_priority == tbi.Priority, "After setting, effective NT priority (%ld) does not match expected priority %d.\n", + tbi.Priority, expected_nt_priority ); + /* Now set NT thread priority directly to 12, a value normally impossible to + * reach in NORMAL_PRIORITY_CLASS without boost. */ + nt_thread_priority = 12; + status = pNtSetInformationThread( GetCurrentThread(), ThreadPriority, &nt_thread_priority, sizeof(ULONG) ); + todo_wine ok( status == STATUS_SUCCESS, "NtSetInformationThread(ThreadPriority) failed: %08lx\n", status ); + /* Effective thread priority should be now 12, BasePriority should be + * unchanged. */ + status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); + ok( status == STATUS_SUCCESS, "NtQueryInformationThread failed after setting priority: %08lx\n", status ); + ok( THREAD_PRIORITY_LOWEST == tbi.BasePriority, "After setting, BasePriority (%ld) does not match set BasePriority THREAD_PRIORITY_LOWEST.\n", + tbi.BasePriority ); + todo_wine ok( nt_thread_priority == tbi.Priority, "After setting, effective NT priority (%ld) does not match expected priority %lu.\n", + tbi.Priority, nt_thread_priority ); + /* Changing process priority recalculates all priorities again and + * overwrites our custom priority of 12. */ + ret = SetPriorityClass( GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS ); + ok( ret, "SetPriorityClass to BELOW_NORMAL_PRIORITY_CLASS failed: %lu\n", GetLastError() ); + /* Effective thread priority should be now BELOW_NORMAL_PRIORITY_CLASS base + * value (6) + THREAD_PRIORITY_LOWEST (-2) = 4. */ + status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); + ok( status == STATUS_SUCCESS, "NtQueryInformationThread failed after setting priority: %08lx\n", status ); + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), NULL ); + expected_nt_priority = pbi.BasePriority + THREAD_PRIORITY_LOWEST; + todo_wine ok( expected_nt_priority == tbi.Priority, "After setting, effective NT priority (%ld) does not match expected priority %d.\n", + tbi.Priority, expected_nt_priority ); + /* Setting an out of range priority above HIGH_PRIORITY (31) or LOW_PRIORITY (0) + * and lower fails. */ + nt_thread_priority = 42; + status = pNtSetInformationThread( GetCurrentThread(), ThreadPriority, &nt_thread_priority, sizeof(ULONG) ); + todo_wine ok( status == STATUS_INVALID_PARAMETER, "got %08lx, expected STATUS_INVALID_PARAMETER.\n", status ); + nt_thread_priority = 0; /* 0 also fails in addition to negative values. */ + status = pNtSetInformationThread( GetCurrentThread(), ThreadPriority, &nt_thread_priority, sizeof(ULONG) ); + todo_wine ok( status == STATUS_INVALID_PARAMETER, "got %08lx, expected STATUS_INVALID_PARAMETER.\n", status ); + /* Moving a thread into the realtime band is normally not possible in a non-realtime process. */ + nt_thread_priority = 24; + status = pNtSetInformationThread( GetCurrentThread(), ThreadPriority, &nt_thread_priority, sizeof(ULONG) ); + todo_wine ok( status == STATUS_PRIVILEGE_NOT_HELD, "got %08lx, expected STATUS_PRIVILEGE_NOT_HELD.\n", status ); + + /* Restore thread priority and boosting behaviour back to normal */ + SetThreadPriorityBoost( GetCurrentThread(), FALSE ); + ret = SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_NORMAL ); + ok( ret, "Restore SetThreadPriority(THREAD_PRIORITY_NORMAL) failed: %lu\n", GetLastError() ); + ret = SetPriorityClass( GetCurrentProcess(), NORMAL_PRIORITY_CLASS ); + ok( ret, "SetPriorityClass to NORMAL_PRIORITY_CLASS failed: %lu\n", GetLastError() ); +} + static DWORD WINAPI hide_from_debugger_thread(void *arg) { HANDLE stop_event = arg; @@ -4197,6 +4331,7 @@ START_TEST(info) test_ThreadIsTerminated();
test_affinity(); + test_priority(); test_debug_object();
/* belongs to its own file */