From: Rémi Bernon rbernon@codeweavers.com
--- configure.ac | 10 +++++++++ server/main.c | 1 + server/object.h | 4 ++++ server/thread.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+)
diff --git a/configure.ac b/configure.ac index 074086c586b..b50f1d162aa 100644 --- a/configure.ac +++ b/configure.ac @@ -2090,6 +2090,16 @@ then AC_DEFINE(HAVE_SCHED_SETAFFINITY, 1, [Define to 1 if you have the `sched_setaffinity' function.]) fi
+AC_CACHE_CHECK([for setpriority],wine_cv_have_setpriority, + AC_LINK_IFELSE([AC_LANG_PROGRAM( +[[#define _GNU_SOURCE +#include <sys/resource.h> +#include <sys/time.h>]], [[setpriority(0, 0, 0);]])],[wine_cv_have_setpriority=yes],[wine_cv_have_setpriority=no])) +if test "$wine_cv_have_setpriority" = "yes" +then + AC_DEFINE(HAVE_SETPRIORITY, 1, [Define to 1 if you have the `setpriority' function.]) +fi + dnl **** Check for types ****
AC_C_INLINE 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 dfdd691601f..66012fbc4af 100644 --- a/server/object.h +++ b/server/object.h @@ -277,6 +277,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 dcc90aded09..1d6bc1e7d5b 100644 --- a/server/thread.c +++ b/server/thread.c @@ -221,6 +221,27 @@ static const struct fd_ops thread_fd_ops = };
static struct list thread_list = LIST_INIT(thread_list); +#ifdef __linux__ +static int nice_limit; +#endif + +void init_threading(void) +{ +#ifdef __linux__ +#ifdef RLIMIT_NICE + 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"); + } +#endif + if (nice_limit < 0 && debug_level) fprintf(stderr, "wine: Using setpriority to control niceness in the [%d,%d] range\n", nice_limit, -nice_limit ); +#endif +}
/* initialize the structure for a newly allocated thread */ static inline void init_thread_structure( struct thread *thread ) @@ -609,9 +630,46 @@ affinity_t get_thread_affinity( struct thread *thread ) return mask; }
+static int get_base_priority( int priority_class, int priority ) +{ + static const int class_offsets[] = { 4, 8, 13, 24, 6, 10 }; + assert(priority_class <= ARRAY_SIZE(class_offsets)); + if (priority == THREAD_PRIORITY_IDLE) return (priority_class == PROCESS_PRIOCLASS_REALTIME ? 16 : 1); + else if (priority == THREAD_PRIORITY_TIME_CRITICAL) return (priority_class == PROCESS_PRIOCLASS_REALTIME ? 31 : 15); + else return class_offsets[priority_class - 1] + priority; +} + +#ifdef __linux__ +static int get_unix_niceness( int base_priority, int limit ) +{ + int min = -limit, max = limit, range = max - min; + return min + (base_priority - 1) * range / 14; +} +#endif + #define THREAD_PRIORITY_REALTIME_HIGHEST 6 #define THREAD_PRIORITY_REALTIME_LOWEST -7
+static void apply_thread_priority( struct thread *thread, int priority_class, int priority, int delayed ) +{ + int base_priority = get_base_priority( priority_class, priority ); +#ifdef __linux__ + int niceness, limit = min( nice_limit, thread->process->nice_limit ); + + /* FIXME: handle REALTIME class using SCHED_RR if possible, for now map it to highest non-realtime band */ + if (priority_class == PROCESS_PRIOCLASS_REALTIME) base_priority = 15; +#ifdef HAVE_SETPRIORITY + if (limit < 0) + { + niceness = get_unix_niceness( base_priority, limit ); + if (setpriority( PRIO_PROCESS, thread->unix_tid, niceness ) != 0) + fprintf( stderr, "wine: setpriority %d for pid %d failed: %d\n", niceness, thread->unix_tid, errno ); + return; + } +#endif +#endif +} + int set_thread_priority( struct thread *thread, int priority_class, int priority ) { int max = THREAD_PRIORITY_HIGHEST;