From: Marc-Aurel Zent mzent@codeweavers.com
--- server/main.c | 1 + server/object.h | 4 ++++ server/thread.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/server/main.c b/server/main.c index 1248b92f24d..e014ec535ff 100644 --- a/server/main.c +++ b/server/main.c @@ -234,6 +234,7 @@ int main( int argc, char *argv[] ) init_signals(); init_memory(); init_directories( load_intl_file() ); + init_threading(); init_registry(); main_loop(); return 0; diff --git a/server/object.h b/server/object.h index 6222e3352ed..2268c997437 100644 --- a/server/object.h +++ b/server/object.h @@ -287,6 +287,10 @@ extern struct object *get_directory_obj( struct process *process, obj_handle_t h extern int directory_link_name( struct object *obj, struct object_name *name, struct object *parent ); extern void init_directories( struct fd *intl_fd );
+/* thread functions */ + +extern void init_threading(void); + /* symbolic link functions */
extern struct object *create_root_symlink( struct object *root, const struct unicode_str *name, diff --git a/server/thread.c b/server/thread.c index 21b3b130a9a..c07a2338c50 100644 --- a/server/thread.c +++ b/server/thread.c @@ -37,6 +37,9 @@ #define _WITH_CPU_SET_T #include <sched.h> #endif +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -216,6 +219,45 @@ static const struct fd_ops thread_fd_ops =
static struct list thread_list = LIST_INIT(thread_list);
+#if defined(__linux__) && defined(RLIMIT_NICE) +static int nice_limit; + +void init_threading(void) +{ + struct rlimit rlimit; + if (!getrlimit( RLIMIT_NICE, &rlimit )) + { + rlimit.rlim_cur = rlimit.rlim_max; + setrlimit( RLIMIT_NICE, &rlimit ); + if (rlimit.rlim_max <= 40) nice_limit = 20 - rlimit.rlim_max; + else if (rlimit.rlim_max == -1) nice_limit = -20; + if (nice_limit >= 0 && debug_level) fprintf(stderr, "wine: RLIMIT_NICE is <= 20, unable to use setpriority safely\n"); + } + if (nice_limit < 0 && debug_level) fprintf(stderr, "wine: Using setpriority to control niceness in the [%d,%d] range\n", nice_limit, -nice_limit ); +} + +static void apply_thread_priority( struct thread *thread, int base_priority ) +{ + int min = -nice_limit, max = nice_limit, range = max - min, niceness; + /* FIXME: handle realtime priorities using SCHED_RR if possible */ + if (base_priority > THREAD_BASE_PRIORITY_LOWRT) base_priority = THREAD_BASE_PRIORITY_LOWRT; + /* map an NT application band [1,15] base priority to [-nice_limit, nice_limit] */ + niceness = (min + (base_priority - 1) * range / 14); + setpriority( PRIO_PROCESS, thread->unix_tid, niceness ); +} + +#else + +void init_threading(void) +{ +} + +static void apply_thread_priority( struct thread *thread, int base_priority ) +{ +} + +#endif + /* initialize the structure for a newly allocated thread */ static inline void init_thread_structure( struct thread *thread ) { @@ -605,13 +647,23 @@ affinity_t get_thread_affinity( struct thread *thread ) return mask; }
+static int get_base_priority( int priority_class, int priority ) +{ + /* 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 == THREAD_PRIORITY_IDLE) return (priority_class == PROCESS_PRIOCLASS_REALTIME ? 16 : 1); + if (priority == THREAD_PRIORITY_TIME_CRITICAL) return (priority_class == PROCESS_PRIOCLASS_REALTIME ? 31 : 15); + if (priority_class >= ARRAY_SIZE(class_offsets)) return 8; + return class_offsets[priority_class - 1] + priority; +} + #define THREAD_PRIORITY_REALTIME_HIGHEST 6 #define THREAD_PRIORITY_REALTIME_LOWEST -7
int set_thread_priority( struct thread *thread, int priority_class, int priority ) { - int max = THREAD_PRIORITY_HIGHEST; - int min = THREAD_PRIORITY_LOWEST; + int min = THREAD_PRIORITY_LOWEST, max = THREAD_PRIORITY_HIGHEST, base_priority; + if (priority_class == PROCESS_PRIOCLASS_REALTIME) { max = THREAD_PRIORITY_REALTIME_HIGHEST; @@ -626,6 +678,13 @@ int set_thread_priority( struct thread *thread, int priority_class, int priority return STATUS_THREAD_IS_TERMINATING;
thread->priority = priority; + + /* if unix_tid == -1, thread is gone or hasn't started yet, this will be called again from init_thread with a unix_tid */ + if (thread->unix_tid == -1) + return STATUS_SUCCESS; + + base_priority = get_base_priority( priority_class, priority ); + apply_thread_priority( thread, base_priority ); return STATUS_SUCCESS; }