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 7612fd69625..36ffe20f6dc 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;