This implements setting `ThreadPriorityBoost`, `ProcessPriorityBoost`, `ProcessBasePriority` and getting `ThreadPriorityBoost`, `ProcessPriorityBoost` NT info classes and adds tests where appropriate.
The actual boosting mechanism will be in part 2 to keep the size of this MR manageable.
-- v3: kernel32/tests: Add tests for GetProcessPriorityBoost/SetProcessPriorityBoost. kernelbase: Implement SetProcessPriorityBoost. kernelbase: Implement GetProcessPriorityBoost. ntdll: Implement ProcessPriorityBoost class in NtSetInformationProcess. ntdll: Implement ProcessPriorityBoost class in NtQueryInformationProcess. ntdll: Implement ThreadPriorityBoost class in NtSetInformationThread. ntdll: Properly implement ThreadPriorityBoost class in NtQueryInformationThread. ntdll/tests: Add tests for setting process base priority. ntdll: Implement ProcessBasePriority class in NtSetInformationProcess.
From: Marc-Aurel Zent mzent@codeweavers.com
--- server/mach.c | 2 +- server/process.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- server/process.h | 4 ++-- 3 files changed, 47 insertions(+), 6 deletions(-)
diff --git a/server/mach.c b/server/mach.c index 50d21e2810a..19737fceef8 100644 --- a/server/mach.c +++ b/server/mach.c @@ -157,7 +157,7 @@ void init_process_tracing( struct process *process ) } /* On Mach thread priorities depend on having the process port available, so * reapply all thread priorities here after process tracing is initialized */ - set_process_priority( process, process->priority ); + set_process_base_priority( process, process->base_priority ); }
/* terminate the per-process tracing mechanism */ diff --git a/server/process.c b/server/process.c index b161e3394ba..4f6e429551a 100644 --- a/server/process.c +++ b/server/process.c @@ -55,6 +55,7 @@ #include "ntstatus.h" #define WIN32_NO_STATUS #include "winternl.h" +#include "ddk/wdm.h"
#include "file.h" #include "handle.h" @@ -662,6 +663,7 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla process->exit_code = STILL_ACTIVE; process->running_threads = 0; process->priority = PROCESS_PRIOCLASS_NORMAL; + process->base_priority = 8; process->suspend = 0; process->is_system = 0; process->debug_children = 1; @@ -1512,7 +1514,7 @@ DECL_HANDLER(get_process_info) reply->ppid = process->parent_id; reply->exit_code = process->exit_code; reply->priority = process->priority; - reply->base_priority = priority_from_class_and_level( process->priority, THREAD_PRIORITY_NORMAL ); + reply->base_priority = process->base_priority; reply->affinity = process->affinity; reply->peb = process->peb; reply->start_time = process->start_time; @@ -1634,11 +1636,17 @@ DECL_HANDLER(get_process_vm_counters) release_object( process ); }
-void set_process_priority( struct process *process, int priority ) +void set_process_base_priority( struct process *process, int base_priority ) { struct thread *thread;
- process->priority = priority; + if (base_priority < LOW_PRIORITY + 1 || base_priority > HIGH_PRIORITY) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + process->base_priority = base_priority;
LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry ) { @@ -1646,6 +1654,39 @@ void set_process_priority( struct process *process, int priority ) } }
+static void set_process_priority( struct process *process, int priority ) +{ + int base_priority; + + process->priority = priority; + + switch (priority) + { + case PROCESS_PRIOCLASS_IDLE: + base_priority = 4; + break; + case PROCESS_PRIOCLASS_BELOW_NORMAL: + base_priority = 6; + break; + case PROCESS_PRIOCLASS_NORMAL: + base_priority = 8; + break; + case PROCESS_PRIOCLASS_ABOVE_NORMAL: + base_priority = 10; + break; + case PROCESS_PRIOCLASS_HIGH: + base_priority = 13; + break; + case PROCESS_PRIOCLASS_REALTIME: + base_priority = 24; + break; + default: + base_priority = 8; + } + + set_process_base_priority( process, base_priority ); +} + static void set_process_affinity( struct process *process, affinity_t affinity ) { struct thread *thread; diff --git a/server/process.h b/server/process.h index e49529b06fa..1648e46fe98 100644 --- a/server/process.h +++ b/server/process.h @@ -56,6 +56,7 @@ struct process timeout_t end_time; /* absolute time at process end */ affinity_t affinity; /* process affinity mask */ int priority; /* priority class */ + int base_priority; /* base priority to calculate thread priority */ int suspend; /* global process suspend count */ unsigned int is_system:1; /* is it a system process? */ unsigned int debug_children:1;/* also debug all child processes */ @@ -116,8 +117,7 @@ extern void kill_process( struct process *process, int violent_death ); extern void kill_console_processes( struct thread *renderer, int exit_code ); extern void detach_debugged_processes( struct debug_obj *debug_obj, int exit_code ); extern void enum_processes( int (*cb)(struct process*, void*), void *user); -extern int priority_from_class_and_level( int priority_class, int priority_level ); -extern void set_process_priority( struct process *process, int priority ); +extern void set_process_base_priority( struct process *process, int base_priority );
/* console functions */ extern struct thread *console_get_renderer( struct console *console );
From: Marc-Aurel Zent mzent@codeweavers.com
This also consolidates priority_from_class_and_level() and set_thread_base_priority(). --- server/thread.c | 56 +++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 32 deletions(-)
diff --git a/server/thread.c b/server/thread.c index ffc016bfa56..12b73d44353 100644 --- a/server/thread.c +++ b/server/thread.c @@ -789,48 +789,40 @@ unsigned int set_thread_priority( struct thread *thread, int priority ) return STATUS_SUCCESS; }
-int priority_from_class_and_level( int priority_class, int priority_level ) -{ - /* offsets taken from https://learn.microsoft.com/en-us/windows/win32/procthread/scheduling-priori... */ - static const int class_offsets[] = { 4, 8, 13, 24, 6, 10 }; - - if (priority_class == PROCESS_PRIOCLASS_REALTIME) - { - if (priority_level == THREAD_PRIORITY_IDLE) return LOW_REALTIME_PRIORITY; - if (priority_level == THREAD_PRIORITY_TIME_CRITICAL) return HIGH_PRIORITY; - } - else - { - if (priority_level == THREAD_PRIORITY_IDLE) return LOW_PRIORITY + 1; - if (priority_level == THREAD_PRIORITY_TIME_CRITICAL) return LOW_REALTIME_PRIORITY - 1; - } - - if (priority_class >= ARRAY_SIZE(class_offsets)) return LOW_REALTIME_PRIORITY / 2; - return class_offsets[priority_class - 1] + priority_level; -} - #define THREAD_PRIORITY_REALTIME_HIGHEST 6 #define THREAD_PRIORITY_REALTIME_LOWEST -7
-/* sets the thread base priority level, relative to its process base priority class */ +/* sets the thread base priority level, relative to its process base priority */ unsigned int set_thread_base_priority( struct thread *thread, int base_priority ) { - int priority_class = thread->process->priority; - int max = THREAD_PRIORITY_HIGHEST; - int min = THREAD_PRIORITY_LOWEST; + int priority; + int is_realtime = thread->process->priority == PROCESS_PRIOCLASS_REALTIME;
- if (priority_class == PROCESS_PRIOCLASS_REALTIME) + if (base_priority != THREAD_PRIORITY_IDLE && base_priority != THREAD_PRIORITY_TIME_CRITICAL) { - max = THREAD_PRIORITY_REALTIME_HIGHEST; - min = THREAD_PRIORITY_REALTIME_LOWEST; + int min = is_realtime ? THREAD_PRIORITY_REALTIME_LOWEST : THREAD_PRIORITY_LOWEST; + int max = is_realtime ? THREAD_PRIORITY_REALTIME_HIGHEST : THREAD_PRIORITY_HIGHEST; + + if (base_priority < min || base_priority > max) + return STATUS_INVALID_PARAMETER; } - if ((base_priority < min || base_priority > max) && - base_priority != THREAD_PRIORITY_IDLE && - base_priority != THREAD_PRIORITY_TIME_CRITICAL) - return STATUS_INVALID_PARAMETER;
thread->base_priority = base_priority; - return set_thread_priority( thread, priority_from_class_and_level( priority_class, base_priority ) ); + + switch (base_priority) + { + case THREAD_PRIORITY_IDLE: + priority = is_realtime ? LOW_REALTIME_PRIORITY : LOW_PRIORITY + 1; + break; + case THREAD_PRIORITY_TIME_CRITICAL: + priority = is_realtime ? HIGH_PRIORITY : LOW_REALTIME_PRIORITY - 1; + break; + default: + priority = thread->process->base_priority + base_priority; + break; + } + + return set_thread_priority( thread, priority ); }
/* set all information about a thread */
From: Marc-Aurel Zent mzent@codeweavers.com
--- dlls/ntdll/unix/process.c | 17 +++++++++++++++++ dlls/wow64/process.c | 1 + server/process.c | 1 + server/protocol.def | 8 +++++--- 4 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index e4e000d385a..c2217c505d6 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -1755,6 +1755,23 @@ NTSTATUS WINAPI NtSetInformationProcess( HANDLE handle, PROCESSINFOCLASS class, } break;
+ case ProcessBasePriority: + if (size != sizeof(KPRIORITY)) return STATUS_INVALID_PARAMETER; + else + { + KPRIORITY* base_priority = info; + + SERVER_START_REQ( set_process_info ) + { + req->handle = wine_server_obj_handle( handle ); + req->base_priority = *base_priority; + req->mask = SET_PROCESS_INFO_BASE_PRIORITY; + ret = wine_server_call( req ); + } + SERVER_END_REQ; + } + break; + case ProcessExecuteFlags: if ((is_win64 && !is_wow64()) || size != sizeof(ULONG)) return STATUS_INVALID_PARAMETER; if (execute_flags & MEM_EXECUTE_OPTION_PERMANENT) return STATUS_ACCESS_DENIED; diff --git a/dlls/wow64/process.c b/dlls/wow64/process.c index 1843bdf5e84..957ca0d2691 100644 --- a/dlls/wow64/process.c +++ b/dlls/wow64/process.c @@ -890,6 +890,7 @@ NTSTATUS WINAPI wow64_NtSetInformationProcess( UINT *args ) { case ProcessDefaultHardErrorMode: /* ULONG */ case ProcessPriorityClass: /* PROCESS_PRIORITY_CLASS */ + case ProcessBasePriority: /* ULONG */ case ProcessExecuteFlags: /* ULONG */ case ProcessPagePriority: /* MEMORY_PRIORITY_INFORMATION */ case ProcessPowerThrottlingState: /* PROCESS_POWER_THROTTLING_STATE */ diff --git a/server/process.c b/server/process.c index 4f6e429551a..139cadd0065 100644 --- a/server/process.c +++ b/server/process.c @@ -1713,6 +1713,7 @@ DECL_HANDLER(set_process_info) if ((process = get_process_from_handle( req->handle, PROCESS_SET_INFORMATION ))) { if (req->mask & SET_PROCESS_INFO_PRIORITY) set_process_priority( process, req->priority ); + if (req->mask & SET_PROCESS_INFO_BASE_PRIORITY) set_process_base_priority( process, req->base_priority ); if (req->mask & SET_PROCESS_INFO_AFFINITY) set_process_affinity( process, req->affinity ); if (req->mask & SET_PROCESS_INFO_TOKEN) { diff --git a/server/protocol.def b/server/protocol.def index 63bb0111473..a47075f7543 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1203,12 +1203,14 @@ struct obj_locator obj_handle_t handle; /* process handle */ int mask; /* setting mask (see below) */ int priority; /* priority class */ + int base_priority; /* process base priority */ affinity_t affinity; /* affinity mask */ obj_handle_t token; /* primary token */ @END -#define SET_PROCESS_INFO_PRIORITY 0x01 -#define SET_PROCESS_INFO_AFFINITY 0x02 -#define SET_PROCESS_INFO_TOKEN 0x04 +#define SET_PROCESS_INFO_PRIORITY 0x01 +#define SET_PROCESS_INFO_BASE_PRIORITY 0x02 +#define SET_PROCESS_INFO_AFFINITY 0x04 +#define SET_PROCESS_INFO_TOKEN 0x08
/* Retrieve information about a thread */
From: Marc-Aurel Zent mzent@codeweavers.com
--- dlls/ntdll/tests/info.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index 9b058eae20f..ac979760433 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -3337,7 +3337,7 @@ static void test_priority(void) NTSTATUS status; DWORD proc_priority; int thread_base_priority, expected_nt_priority; - ULONG nt_thread_priority; + ULONG nt_thread_priority, process_base_priority; THREAD_BASIC_INFORMATION tbi; DECLSPEC_ALIGN(8) PROCESS_PRIORITY_CLASS ppc; /* needs align, or STATUS_DATATYPE_MISALIGNMENT is returned */ PROCESS_BASIC_INFORMATION pbi; @@ -3447,6 +3447,28 @@ static void test_priority(void) expected_nt_priority = pbi.BasePriority + THREAD_PRIORITY_LOWEST; 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 a custom process base priority that does not correspond to + * any process priority class. */ + process_base_priority = 5; + status = pNtSetInformationProcess( GetCurrentProcess(), ProcessBasePriority, &process_base_priority, sizeof(ULONG) ); + ok( status == STATUS_SUCCESS, "NtSetInformationProcess failed after setting base priority: %08lx\n", status ); + memset( &pbi, 0xcd, sizeof(pbi) ); + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), NULL ); + ok( status == STATUS_SUCCESS, "NtQueryInformationProcess failed after setting base priority: %08lx\n", status ); + if (is_wow64) + { + todo_wine ok( pbi.BasePriority == 0xcdcdcdcd, "got %#lx\n", pbi.BasePriority ); + pbi.BasePriority = process_base_priority; + } + ok( process_base_priority == pbi.BasePriority, "After setting, effective base priority (%ld) does not match expected base priority %ld.\n", + pbi.BasePriority, process_base_priority ); + /* Effective thread priority should be now base priority 5 (and not 6 as before) + * + THREAD_PRIORITY_LOWEST (-2) = 3. */ + status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); + ok( status == STATUS_SUCCESS, "NtQueryInformationThread failed after setting process base priority: %08lx\n", status ); + expected_nt_priority = pbi.BasePriority + THREAD_PRIORITY_LOWEST; + ok( expected_nt_priority == tbi.Priority, "After setting process base priority, 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;
From: Marc-Aurel Zent mzent@codeweavers.com
--- dlls/ntdll/unix/thread.c | 18 +++++++++++++----- server/protocol.def | 7 ++++--- server/thread.c | 3 +++ server/thread.h | 1 + 4 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 1dd7faecb14..995498f8ff7 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -2296,12 +2296,20 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
case ThreadPriorityBoost: { - DWORD *value = data; - if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH; - if (ret_len) *ret_len = sizeof(ULONG); - *value = 0; - return STATUS_SUCCESS; + SERVER_START_REQ( get_thread_info ) + { + req->handle = wine_server_obj_handle( handle ); + status = wine_server_call( req ); + if (status == STATUS_SUCCESS) + { + ULONG disable_boost = !!(reply->flags & GET_THREAD_INFO_FLAG_DISABLE_BOOST); + if (data) memcpy( data, &disable_boost, sizeof(disable_boost) ); + if (ret_len) *ret_len = sizeof(disable_boost); + } + } + SERVER_END_REQ; + return status; }
case ThreadIdealProcessorEx: diff --git a/server/protocol.def b/server/protocol.def index a47075f7543..9a9f1baba50 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1231,9 +1231,10 @@ struct obj_locator data_size_t desc_len; /* description length in bytes */ VARARG(desc,unicode_str); /* description string */ @END -#define GET_THREAD_INFO_FLAG_DBG_HIDDEN 0x01 -#define GET_THREAD_INFO_FLAG_TERMINATED 0x02 -#define GET_THREAD_INFO_FLAG_LAST 0x04 +#define GET_THREAD_INFO_FLAG_DBG_HIDDEN 0x01 +#define GET_THREAD_INFO_FLAG_TERMINATED 0x02 +#define GET_THREAD_INFO_FLAG_LAST 0x04 +#define GET_THREAD_INFO_FLAG_DISABLE_BOOST 0x08
/* Retrieve information about thread times */ diff --git a/server/thread.c b/server/thread.c index 12b73d44353..29659d91f15 100644 --- a/server/thread.c +++ b/server/thread.c @@ -409,6 +409,7 @@ static inline void init_thread_structure( struct thread *thread ) thread->exit_code = 0; thread->priority = 0; thread->base_priority = 0; + thread->disable_boost = 0; thread->suspend = 0; thread->dbg_hidden = 0; thread->desktop_users = 0; @@ -1731,6 +1732,8 @@ DECL_HANDLER(get_thread_info) reply->flags |= GET_THREAD_INFO_FLAG_TERMINATED; if (thread->process->running_threads == 1) reply->flags |= GET_THREAD_INFO_FLAG_LAST; + if (thread->disable_boost) + reply->flags |= GET_THREAD_INFO_FLAG_DISABLE_BOOST;
if (thread->desc && get_reply_max_size()) { diff --git a/server/thread.h b/server/thread.h index 7fdae3a629f..03b0b547c2f 100644 --- a/server/thread.h +++ b/server/thread.h @@ -83,6 +83,7 @@ struct thread affinity_t affinity; /* affinity mask */ int priority; /* current thread priority */ int base_priority; /* base priority level (relative to process base priority class) */ + int disable_boost; /* disable thread priority boost */ int suspend; /* suspend count */ int dbg_hidden; /* hidden from debugger */ obj_handle_t desktop; /* desktop handle */
From: Marc-Aurel Zent mzent@codeweavers.com
--- dlls/ntdll/unix/thread.c | 16 ++++++++++++++-- server/protocol.def | 13 +++++++------ server/thread.c | 12 ++++++++++++ server/thread.h | 1 + 4 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 995498f8ff7..fb17bb61330 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -2550,8 +2550,20 @@ NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class, }
case ThreadPriorityBoost: - WARN("Unimplemented class ThreadPriorityBoost.\n"); - return STATUS_SUCCESS; + { + const DWORD *disable_boost = data; + if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER; + if (!disable_boost) return STATUS_ACCESS_VIOLATION; + SERVER_START_REQ( set_thread_info ) + { + req->handle = wine_server_obj_handle( handle ); + req->disable_boost = *disable_boost; + req->mask = SET_THREAD_INFO_DISABLE_BOOST; + status = wine_server_call( req ); + } + SERVER_END_REQ; + return status; + }
case ThreadManageWritesToExecutableMemory: { diff --git a/server/protocol.def b/server/protocol.def index 9a9f1baba50..542bf812a18 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1253,6 +1253,7 @@ struct obj_locator obj_handle_t handle; /* thread handle */ int priority; /* current thread priority */ int base_priority;/* base priority level (relative to process base priority class) */ + int disable_boost;/* disable thread priority boost */ affinity_t affinity; /* affinity mask */ client_ptr_t entry_point; /* thread entry point */ obj_handle_t token; /* impersonation token */ @@ -1261,12 +1262,12 @@ struct obj_locator @END #define SET_THREAD_INFO_PRIORITY 0x01 #define SET_THREAD_INFO_BASE_PRIORITY 0x02 -#define SET_THREAD_INFO_AFFINITY 0x04 -#define SET_THREAD_INFO_TOKEN 0x08 -#define SET_THREAD_INFO_ENTRYPOINT 0x10 -#define SET_THREAD_INFO_DESCRIPTION 0x20 -#define SET_THREAD_INFO_DBG_HIDDEN 0x40 - +#define SET_THREAD_INFO_DISABLE_BOOST 0x04 +#define SET_THREAD_INFO_AFFINITY 0x08 +#define SET_THREAD_INFO_TOKEN 0x10 +#define SET_THREAD_INFO_ENTRYPOINT 0x20 +#define SET_THREAD_INFO_DESCRIPTION 0x40 +#define SET_THREAD_INFO_DBG_HIDDEN 0x80
/* Suspend a thread */ @REQ(suspend_thread) diff --git a/server/thread.c b/server/thread.c index 29659d91f15..bc27bbcca57 100644 --- a/server/thread.c +++ b/server/thread.c @@ -826,6 +826,13 @@ unsigned int set_thread_base_priority( struct thread *thread, int base_priority return set_thread_priority( thread, priority ); }
+unsigned int set_thread_disable_boost( struct thread *thread, int disable_boost ) +{ + thread->disable_boost = disable_boost; + set_thread_priority( thread, thread->priority ); + return STATUS_SUCCESS; +} + /* set all information about a thread */ static void set_thread_info( struct thread *thread, const struct set_thread_info_request *req ) @@ -840,6 +847,11 @@ static void set_thread_info( struct thread *thread, unsigned int status = set_thread_base_priority( thread, req->base_priority ); if (status) set_error( status ); } + if (req->mask & SET_THREAD_INFO_DISABLE_BOOST) + { + unsigned int status = set_thread_disable_boost( thread, req->disable_boost ); + if (status) set_error( status ); + } if (req->mask & SET_THREAD_INFO_AFFINITY) { if ((req->affinity & thread->process->affinity) != req->affinity) diff --git a/server/thread.h b/server/thread.h index 03b0b547c2f..e4ac3b8050a 100644 --- a/server/thread.h +++ b/server/thread.h @@ -126,6 +126,7 @@ extern int thread_get_inflight_fd( struct thread *thread, int client ); extern struct token *thread_get_impersonation_token( struct thread *thread ); extern unsigned int set_thread_priority( struct thread *thread, int priority ); extern unsigned int set_thread_base_priority( struct thread *thread, int base_priority ); +extern unsigned int set_thread_disable_boost( struct thread *thread, int disable_boost ); extern int set_thread_affinity( struct thread *thread, affinity_t affinity ); extern int suspend_thread( struct thread *thread ); extern int resume_thread( struct thread *thread );
From: Marc-Aurel Zent mzent@codeweavers.com
--- dlls/ntdll/unix/process.c | 18 +++++++++++++++++- dlls/wow64/process.c | 1 + server/process.c | 2 ++ server/process.h | 1 + server/protocol.def | 3 ++- server/thread.c | 1 + 6 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index c2217c505d6..0f6f4fe7c4c 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -1134,7 +1134,6 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class UNIMPLEMENTED_INFO_CLASS(ProcessUserModeIOPL); UNIMPLEMENTED_INFO_CLASS(ProcessEnableAlignmentFaultFixup); UNIMPLEMENTED_INFO_CLASS(ProcessWx86Information); - UNIMPLEMENTED_INFO_CLASS(ProcessPriorityBoost); UNIMPLEMENTED_INFO_CLASS(ProcessDeviceMap); UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation); UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled); @@ -1331,6 +1330,23 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class } break;
+ case ProcessPriorityBoost: + len = sizeof(ULONG); + if (size != len) return STATUS_INFO_LENGTH_MISMATCH; + if (!info) ret = STATUS_ACCESS_VIOLATION; + else + { + ULONG *disable_boost = info; + SERVER_START_REQ(get_process_info) + { + req->handle = wine_server_obj_handle( handle ); + ret = wine_server_call( req ); + *disable_boost = reply->disable_boost; + } + SERVER_END_REQ; + } + break; + case ProcessDebugFlags: len = sizeof(DWORD); if (size == len) diff --git a/dlls/wow64/process.c b/dlls/wow64/process.c index 957ca0d2691..3b2cd22b712 100644 --- a/dlls/wow64/process.c +++ b/dlls/wow64/process.c @@ -577,6 +577,7 @@ NTSTATUS WINAPI wow64_NtQueryInformationProcess( UINT *args ) case ProcessTimes: /* KERNEL_USER_TIMES */ case ProcessDefaultHardErrorMode: /* ULONG */ case ProcessPriorityClass: /* PROCESS_PRIORITY_CLASS */ + case ProcessPriorityBoost: /* ULONG */ case ProcessHandleCount: /* ULONG */ case ProcessSessionInformation: /* ULONG */ case ProcessDebugFlags: /* ULONG */ diff --git a/server/process.c b/server/process.c index 139cadd0065..ace5d24b2ba 100644 --- a/server/process.c +++ b/server/process.c @@ -664,6 +664,7 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla process->running_threads = 0; process->priority = PROCESS_PRIOCLASS_NORMAL; process->base_priority = 8; + process->disable_boost = 0; process->suspend = 0; process->is_system = 0; process->debug_children = 1; @@ -1515,6 +1516,7 @@ DECL_HANDLER(get_process_info) reply->exit_code = process->exit_code; reply->priority = process->priority; reply->base_priority = process->base_priority; + reply->disable_boost = process->disable_boost; reply->affinity = process->affinity; reply->peb = process->peb; reply->start_time = process->start_time; diff --git a/server/process.h b/server/process.h index 1648e46fe98..c23a099ed50 100644 --- a/server/process.h +++ b/server/process.h @@ -57,6 +57,7 @@ struct process affinity_t affinity; /* process affinity mask */ int priority; /* priority class */ int base_priority; /* base priority to calculate thread priority */ + int disable_boost; /* disable priority boost */ int suspend; /* global process suspend count */ unsigned int is_system:1; /* is it a system process? */ unsigned int debug_children:1;/* also debug all child processes */ diff --git a/server/protocol.def b/server/protocol.def index 542bf812a18..1739b7059ac 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1157,8 +1157,9 @@ struct obj_locator timeout_t end_time; /* process end time */ unsigned int session_id; /* process session id */ int exit_code; /* process exit code */ - int priority; /* priority class */ + unsigned short priority; /* priority class */ unsigned short base_priority; /* process base priority */ + unsigned short disable_boost; /* disable process priority boost */ unsigned short machine; /* process architecture */ VARARG(image,pe_image_info); /* image info for main exe */ @END diff --git a/server/thread.c b/server/thread.c index bc27bbcca57..7824f9c2413 100644 --- a/server/thread.c +++ b/server/thread.c @@ -508,6 +508,7 @@ struct thread *create_thread( int fd, struct process *process, const struct secu thread->process = (struct process *)grab_object( process ); thread->desktop = 0; thread->affinity = process->affinity; + thread->disable_boost = process->disable_boost; if (!current) current = thread;
list_add_tail( &thread_list, &thread->entry );
From: Marc-Aurel Zent mzent@codeweavers.com
--- dlls/ntdll/unix/process.c | 17 +++++++++++++++++ dlls/wow64/process.c | 1 + server/process.c | 13 +++++++++++++ server/protocol.def | 6 ++++-- 4 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index 0f6f4fe7c4c..1cfc05df6ef 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -1788,6 +1788,23 @@ NTSTATUS WINAPI NtSetInformationProcess( HANDLE handle, PROCESSINFOCLASS class, } break;
+ case ProcessPriorityBoost: + if (size != sizeof(ULONG)) return STATUS_INVALID_PARAMETER; + else + { + ULONG* disable_boost = info; + + SERVER_START_REQ( set_process_info ) + { + req->handle = wine_server_obj_handle( handle ); + req->disable_boost = *disable_boost; + req->mask = SET_PROCESS_INFO_DISABLE_BOOST; + ret = wine_server_call( req ); + } + SERVER_END_REQ; + } + break; + case ProcessExecuteFlags: if ((is_win64 && !is_wow64()) || size != sizeof(ULONG)) return STATUS_INVALID_PARAMETER; if (execute_flags & MEM_EXECUTE_OPTION_PERMANENT) return STATUS_ACCESS_DENIED; diff --git a/dlls/wow64/process.c b/dlls/wow64/process.c index 3b2cd22b712..2790ce211ff 100644 --- a/dlls/wow64/process.c +++ b/dlls/wow64/process.c @@ -892,6 +892,7 @@ NTSTATUS WINAPI wow64_NtSetInformationProcess( UINT *args ) case ProcessDefaultHardErrorMode: /* ULONG */ case ProcessPriorityClass: /* PROCESS_PRIORITY_CLASS */ case ProcessBasePriority: /* ULONG */ + case ProcessPriorityBoost: /* ULONG */ case ProcessExecuteFlags: /* ULONG */ case ProcessPagePriority: /* MEMORY_PRIORITY_INFORMATION */ case ProcessPowerThrottlingState: /* PROCESS_POWER_THROTTLING_STATE */ diff --git a/server/process.c b/server/process.c index ace5d24b2ba..d54be71f2c0 100644 --- a/server/process.c +++ b/server/process.c @@ -1689,6 +1689,18 @@ static void set_process_priority( struct process *process, int priority ) set_process_base_priority( process, base_priority ); }
+static void set_process_disable_boost( struct process *process, int disable_boost ) +{ + struct thread *thread; + + process->disable_boost = disable_boost; + + LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry ) + { + set_thread_disable_boost( thread, disable_boost ); + } +} + static void set_process_affinity( struct process *process, affinity_t affinity ) { struct thread *thread; @@ -1716,6 +1728,7 @@ DECL_HANDLER(set_process_info) { if (req->mask & SET_PROCESS_INFO_PRIORITY) set_process_priority( process, req->priority ); if (req->mask & SET_PROCESS_INFO_BASE_PRIORITY) set_process_base_priority( process, req->base_priority ); + if (req->mask & SET_PROCESS_INFO_DISABLE_BOOST) set_process_disable_boost( process, req->disable_boost ); if (req->mask & SET_PROCESS_INFO_AFFINITY) set_process_affinity( process, req->affinity ); if (req->mask & SET_PROCESS_INFO_TOKEN) { diff --git a/server/protocol.def b/server/protocol.def index 1739b7059ac..361bd9c0a78 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1205,13 +1205,15 @@ struct obj_locator int mask; /* setting mask (see below) */ int priority; /* priority class */ int base_priority; /* process base priority */ + int disable_boost; /* disable process priority boost */ affinity_t affinity; /* affinity mask */ obj_handle_t token; /* primary token */ @END #define SET_PROCESS_INFO_PRIORITY 0x01 #define SET_PROCESS_INFO_BASE_PRIORITY 0x02 -#define SET_PROCESS_INFO_AFFINITY 0x04 -#define SET_PROCESS_INFO_TOKEN 0x08 +#define SET_PROCESS_INFO_DISABLE_BOOST 0x04 +#define SET_PROCESS_INFO_AFFINITY 0x08 +#define SET_PROCESS_INFO_TOKEN 0x10
/* Retrieve information about a thread */
From: Marc-Aurel Zent mzent@codeweavers.com
--- dlls/kernelbase/process.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index b75963fef1d..aba35190efd 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -900,9 +900,7 @@ BOOL WINAPI /* DECLSPEC_HOTPATCH */ GetProcessMitigationPolicy( HANDLE process, */ BOOL WINAPI DECLSPEC_HOTPATCH GetProcessPriorityBoost( HANDLE process, PBOOL disable ) { - FIXME( "(%p,%p): semi-stub\n", process, disable ); - *disable = FALSE; /* report that no boost is present */ - return TRUE; + return set_ntstatus( NtQueryInformationProcess( process, ProcessPriorityBoost, disable, sizeof(*disable), NULL )); }
From: Marc-Aurel Zent mzent@codeweavers.com
--- dlls/kernelbase/process.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index aba35190efd..0b803792790 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -1244,8 +1244,7 @@ BOOL WINAPI /* DECLSPEC_HOTPATCH */ SetProcessMitigationPolicy( PROCESS_MITIGATI */ BOOL WINAPI /* DECLSPEC_HOTPATCH */ SetProcessPriorityBoost( HANDLE process, BOOL disable ) { - FIXME( "(%p,%d): stub\n", process, disable ); - return TRUE; + return set_ntstatus( NtSetInformationProcess( process, ProcessPriorityBoost, &disable, sizeof(disable) )); }
From: Marc-Aurel Zent mzent@codeweavers.com
Also removes todo_wine for GetThreadPriorityBoost calls. --- dlls/kernel32/tests/thread.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c index fa25fd4e4a7..e09f6f29c65 100644 --- a/dlls/kernel32/tests/thread.c +++ b/dlls/kernel32/tests/thread.c @@ -77,9 +77,11 @@
static void (WINAPI *pGetCurrentThreadStackLimits)(PULONG_PTR,PULONG_PTR); static BOOL (WINAPI *pGetThreadPriorityBoost)(HANDLE,PBOOL); +static BOOL (WINAPI *pGetProcessPriorityBoost)(HANDLE,PBOOL); static HANDLE (WINAPI *pOpenThread)(DWORD,BOOL,DWORD); static BOOL (WINAPI *pQueueUserWorkItem)(LPTHREAD_START_ROUTINE,PVOID,ULONG); static BOOL (WINAPI *pSetThreadPriorityBoost)(HANDLE,BOOL); +static BOOL (WINAPI *pSetProcessPriorityBoost)(HANDLE,BOOL); static BOOL (WINAPI *pSetThreadStackGuarantee)(ULONG*); static BOOL (WINAPI *pRegisterWaitForSingleObject)(PHANDLE,HANDLE,WAITORTIMERCALLBACK,PVOID,ULONG,ULONG); static BOOL (WINAPI *pUnregisterWait)(HANDLE); @@ -777,17 +779,33 @@ static VOID test_thread_priority(void)
rc = pSetThreadPriorityBoost(curthread,1); ok( rc != 0, "error=%ld\n",GetLastError()); - todo_wine { - rc=pGetThreadPriorityBoost(curthread,&disabled); - ok(rc!=0 && disabled==1, - "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled); - } + rc=pGetThreadPriorityBoost(curthread,&disabled); + ok(rc!=0 && disabled==1, + "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled); + + rc = pSetThreadPriorityBoost(curthread,0); + ok( rc != 0, "error=%ld\n",GetLastError()); + rc=pGetThreadPriorityBoost(curthread,&disabled); + ok(rc!=0 && disabled==0, + "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled); + + rc = pSetProcessPriorityBoost(GetCurrentProcess(),1); + ok( rc != 0, "error=%ld\n",GetLastError()); + rc=pGetThreadPriorityBoost(curthread,&disabled); + ok(rc!=0 && disabled==1, + "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled); + rc=pGetProcessPriorityBoost(GetCurrentProcess(),&disabled); + ok(rc!=0 && disabled==1, + "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled);
rc = pSetThreadPriorityBoost(curthread,0); ok( rc != 0, "error=%ld\n",GetLastError()); rc=pGetThreadPriorityBoost(curthread,&disabled); ok(rc!=0 && disabled==0, "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled); + rc=pGetProcessPriorityBoost(GetCurrentProcess(),&disabled); + ok(rc!=0 && disabled==1, + "rc=%d error=%ld disabled=%d\n",rc,GetLastError(),disabled); }
/* check the GetThreadTimes function */ @@ -2583,9 +2601,11 @@ static void init_funcs(void) #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f) X(GetCurrentThreadStackLimits); X(GetThreadPriorityBoost); + X(GetProcessPriorityBoost); X(OpenThread); X(QueueUserWorkItem); X(SetThreadPriorityBoost); + X(SetProcessPriorityBoost); X(SetThreadStackGuarantee); X(RegisterWaitForSingleObject); X(UnregisterWait);
On Tue Apr 22 08:16:25 2025 +0000, William Horvath wrote:
The `ProcessPriorityBoost` and `ProcessBasePriority` cases should also be added to the `wow64_Nt{Set,Query}InformationProcess` functions.
Thanks, should be fixed now.
The actual boosting mechanism will be in part 2 to keep the size of this MR manageable.
It's already too large, and there doesn't seem to be a reason to do all these changes at once. Please split into separate MRs.
On Wed Apr 30 12:32:44 2025 +0000, Alexandre Julliard wrote:
The actual boosting mechanism will be in part 2 to keep the size of
this MR manageable. It's already too large, and there doesn't seem to be a reason to do all these changes at once. Please split into separate MRs.
I have split off the base priority process part (and that one is fairly self-contained) in https://gitlab.winehq.org/wine/wine/-/merge_requests/7939