This does not report permission errors in order to avoid any breaking change, only the parameter checks that were already there are returning errors.
We only call setpriority on Linux, as unix_tid is a Mach port on Mac OS.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- configure.ac | 19 ++++++ include/config.h.in | 6 ++ server/process.c | 20 +++++- server/thread.c | 154 ++++++++++++++++++++++++++++++++++++++++---- server/thread.h | 1 + 5 files changed, 186 insertions(+), 14 deletions(-)
diff --git a/configure.ac b/configure.ac index b9339b90aa7..47c1f7c5315 100644 --- a/configure.ac +++ b/configure.ac @@ -2285,6 +2285,25 @@ then AC_DEFINE(HAVE_SCHED_SETAFFINITY, 1, [Define to 1 if you have the `sched_setaffinity' function.]) fi
+AC_CACHE_CHECK([for sched_setscheduler],wine_cv_have_sched_setscheduler, + AC_LINK_IFELSE([AC_LANG_PROGRAM( +[[#define _GNU_SOURCE +#include <sched.h>]], [[sched_setscheduler(0, 0, 0);]])],[wine_cv_have_sched_setscheduler=yes],[wine_cv_have_sched_setscheduler=no])) +if test "$wine_cv_have_sched_setscheduler" = "yes" +then + AC_DEFINE(HAVE_SCHED_SETSCHEDULER, 1, [Define to 1 if you have the `sched_setscheduler' 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 + AC_CACHE_CHECK([for fallocate],wine_cv_have_fallocate, AC_LINK_IFELSE([AC_LANG_PROGRAM( [[#define _GNU_SOURCE diff --git a/include/config.h.in b/include/config.h.in index 9c7a49ae9a2..929b11a8754 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -785,6 +785,9 @@ /* Define to 1 if you have the `sched_setaffinity' function. */ #undef HAVE_SCHED_SETAFFINITY
+/* Define to 1 if you have the `sched_setscheduler' function. */ +#undef HAVE_SCHED_SETSCHEDULER + /* Define to 1 if you have the `sched_yield' function. */ #undef HAVE_SCHED_YIELD
@@ -809,6 +812,9 @@ /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT
+/* Define to 1 if you have the `setpriority' function. */ +#undef HAVE_SETPRIORITY + /* Define to 1 if you have the `setproctitle' function. */ #undef HAVE_SETPROCTITLE
diff --git a/server/process.c b/server/process.c index 16bb5d57e72..0c544b46096 100644 --- a/server/process.c +++ b/server/process.c @@ -1465,6 +1465,24 @@ DECL_HANDLER(get_process_vm_counters) release_object( process ); }
+static void set_process_priority( struct process *process, int priority ) +{ + struct thread *thread; + + if (!process->running_threads) + { + set_error( STATUS_PROCESS_IS_TERMINATING ); + return; + } + + LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry ) + { + set_thread_priority( thread, priority, thread->priority ); + } + + process->priority = priority; +} + static void set_process_affinity( struct process *process, affinity_t affinity ) { struct thread *thread; @@ -1490,7 +1508,7 @@ DECL_HANDLER(set_process_info)
if ((process = get_process_from_handle( req->handle, PROCESS_SET_INFORMATION ))) { - if (req->mask & SET_PROCESS_INFO_PRIORITY) process->priority = req->priority; + if (req->mask & SET_PROCESS_INFO_PRIORITY) set_process_priority( process, req->priority ); if (req->mask & SET_PROCESS_INFO_AFFINITY) set_process_affinity( process, req->affinity ); release_object( process ); } diff --git a/server/thread.c b/server/thread.c index e753c8d0dda..36bd41e977f 100644 --- a/server/thread.c +++ b/server/thread.c @@ -38,6 +38,12 @@ #ifdef HAVE_SCHED_H #include <sched.h> #endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -515,28 +521,149 @@ affinity_t get_thread_affinity( struct thread *thread ) return mask; }
+#if defined(HAVE_SCHED_SETSCHEDULER) || defined(HAVE_SETPRIORITY) +static int get_unix_priority( int priority_class, int priority ) +{ + switch (priority_class) { + case PROCESS_PRIOCLASS_IDLE: + switch (priority) { + case THREAD_PRIORITY_IDLE: return 15; + case THREAD_PRIORITY_LOWEST: return 10; + case THREAD_PRIORITY_BELOW_NORMAL: return 8; + case THREAD_PRIORITY_NORMAL: return 6; + case THREAD_PRIORITY_ABOVE_NORMAL: return 4; + case THREAD_PRIORITY_HIGHEST: return 2; + case THREAD_PRIORITY_TIME_CRITICAL: return -15; + } + case PROCESS_PRIOCLASS_BELOW_NORMAL: + switch (priority) { + case THREAD_PRIORITY_IDLE: return 15; + case THREAD_PRIORITY_LOWEST: return 8; + case THREAD_PRIORITY_BELOW_NORMAL: return 6; + case THREAD_PRIORITY_NORMAL: return 4; + case THREAD_PRIORITY_ABOVE_NORMAL: return 2; + case THREAD_PRIORITY_HIGHEST: return 0; + case THREAD_PRIORITY_TIME_CRITICAL: return -15; + } + case PROCESS_PRIOCLASS_NORMAL: + switch (priority) { + case THREAD_PRIORITY_IDLE: return 15; + case THREAD_PRIORITY_LOWEST: return 4; + case THREAD_PRIORITY_BELOW_NORMAL: return 2; + case THREAD_PRIORITY_NORMAL: return 0; + case THREAD_PRIORITY_ABOVE_NORMAL: return -2; + case THREAD_PRIORITY_HIGHEST: return -4; + case THREAD_PRIORITY_TIME_CRITICAL: return -15; + } + case PROCESS_PRIOCLASS_ABOVE_NORMAL: + switch (priority) { + case THREAD_PRIORITY_IDLE: return 15; + case THREAD_PRIORITY_LOWEST: return 0; + case THREAD_PRIORITY_BELOW_NORMAL: return -2; + case THREAD_PRIORITY_NORMAL: return -4; + case THREAD_PRIORITY_ABOVE_NORMAL: return -6; + case THREAD_PRIORITY_HIGHEST: return -8; + case THREAD_PRIORITY_TIME_CRITICAL: return -15; + } + case PROCESS_PRIOCLASS_HIGH: + switch (priority) { + case THREAD_PRIORITY_IDLE: return 15; + case THREAD_PRIORITY_LOWEST: return -2; + case THREAD_PRIORITY_BELOW_NORMAL: return -4; + case THREAD_PRIORITY_NORMAL: return -6; + case THREAD_PRIORITY_ABOVE_NORMAL: return -8; + case THREAD_PRIORITY_HIGHEST: return -10; + case THREAD_PRIORITY_TIME_CRITICAL: return -15; + } + case PROCESS_PRIOCLASS_REALTIME: + switch (priority) { + case THREAD_PRIORITY_IDLE: return 1; + case -7: + case -6: + case -5: + case -4: + case -3: + case THREAD_PRIORITY_LOWEST: + case THREAD_PRIORITY_BELOW_NORMAL: + case THREAD_PRIORITY_NORMAL: + case THREAD_PRIORITY_ABOVE_NORMAL: + case THREAD_PRIORITY_HIGHEST: + case 3: + case 4: + case 5: + case 6: + return priority + 9; + case THREAD_PRIORITY_TIME_CRITICAL: + return 16; + } + } + return 0; +} +#endif + #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; + if (priority_class == PROCESS_PRIOCLASS_REALTIME) + { + max = THREAD_PRIORITY_REALTIME_HIGHEST; + min = THREAD_PRIORITY_REALTIME_LOWEST; + } + + if ((priority < min || priority > max) && + priority != THREAD_PRIORITY_IDLE && + priority != THREAD_PRIORITY_TIME_CRITICAL) + { + errno = EINVAL; + return -1; + } + + if (thread->process->priority == priority_class && + thread->priority == priority) + return 0; + + thread->priority = priority; + if (thread->unix_tid == -1) + return 0; + +#ifdef __linux__ + if (priority_class == PROCESS_PRIOCLASS_REALTIME) + { +#ifdef HAVE_SCHED_SETSCHEDULER + struct sched_param param; + if (sched_getparam( thread->unix_tid, ¶m ) != 0) + return 0; /* ignore errors for now */ + + param.sched_priority = get_unix_priority( priority_class, priority ); + if (sched_setscheduler( thread->unix_tid, SCHED_RR|SCHED_RESET_ON_FORK, ¶m ) == 0) + return 0; +#endif + } + else + { +#ifdef HAVE_SETPRIORITY + if (setpriority( PRIO_PROCESS, thread->unix_tid, + get_unix_priority( priority_class, priority ) ) == 0) + return 0; +#endif + } +#endif + + return 0; /* ignore errors for now */ +} + /* set all information about a thread */ static void set_thread_info( struct thread *thread, const struct set_thread_info_request *req ) { if (req->mask & SET_THREAD_INFO_PRIORITY) { - int max = THREAD_PRIORITY_HIGHEST; - int min = THREAD_PRIORITY_LOWEST; - if (thread->process->priority == PROCESS_PRIOCLASS_REALTIME) - { - max = THREAD_PRIORITY_REALTIME_HIGHEST; - min = THREAD_PRIORITY_REALTIME_LOWEST; - } - if ((req->priority >= min && req->priority <= max) || - req->priority == THREAD_PRIORITY_IDLE || - req->priority == THREAD_PRIORITY_TIME_CRITICAL) - thread->priority = req->priority; - else - set_error( STATUS_INVALID_PARAMETER ); + if (set_thread_priority( thread, thread->process->priority, req->priority )) + file_set_error(); } if (req->mask & SET_THREAD_INFO_AFFINITY) { @@ -1367,6 +1494,7 @@ DECL_HANDLER(init_thread) process->unix_pid = -1; /* can happen with linuxthreads */ init_thread_context( current ); generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT, &req->entry ); + set_thread_priority( current, current->process->priority, current->priority ); set_thread_affinity( current, current->affinity ); } debug_level = max( debug_level, req->debug_level ); diff --git a/server/thread.h b/server/thread.h index e10120dcf6e..b81061aea11 100644 --- a/server/thread.h +++ b/server/thread.h @@ -125,6 +125,7 @@ extern int thread_add_inflight_fd( struct thread *thread, int client, int server extern int thread_get_inflight_fd( struct thread *thread, int client ); extern struct thread_snapshot *thread_snap( int *count ); extern struct token *thread_get_impersonation_token( struct thread *thread ); +extern int set_thread_priority( struct thread *thread, int priority_class, int priority ); extern int set_thread_affinity( struct thread *thread, affinity_t affinity ); extern int is_cpu_supported( enum cpu_type cpu ); extern unsigned int get_supported_cpu_mask(void);
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
We aren't handling errors so we don't need to check the errors or message replies checking in DBus calls either.
configure.ac | 2 +- include/config.h.in | 3 ++ server/Makefile.in | 3 +- server/thread.c | 84 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 89 insertions(+), 3 deletions(-)
diff --git a/configure.ac b/configure.ac index 47c1f7c5315..4d83d54823d 100644 --- a/configure.ac +++ b/configure.ac @@ -1403,7 +1403,7 @@ dnl **** Check for libdbus **** if test "x$with_dbus" != "xno" then WINE_PACKAGE_FLAGS(DBUS,[dbus-1],,,, - [AC_CHECK_HEADER([dbus/dbus.h], + [AC_CHECK_HEADERS([dbus/dbus.h], [WINE_CHECK_SONAME(dbus-1, dbus_connection_close,,[DBUS_CFLAGS=""],[$DBUS_LIBS])], [DBUS_CFLAGS=""])]) fi diff --git a/include/config.h.in b/include/config.h.in index 929b11a8754..559bd57d1c2 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -97,6 +97,9 @@ /* Define to 1 if you have the <curses.h> header file. */ #undef HAVE_CURSES_H
+/* Define to 1 if you have the <dbus/dbus.h> header file. */ +#undef HAVE_DBUS_DBUS_H + /* Define to 1 if you have the <dirent.h> header file. */ #undef HAVE_DIRENT_H
diff --git a/server/Makefile.in b/server/Makefile.in index b39bd30305b..114df2a8de3 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -50,4 +50,5 @@ MANPAGES = \ wineserver.fr.UTF-8.man.in \ wineserver.man.in
-EXTRALIBS = $(LDEXECFLAGS) -lwine $(POLL_LIBS) $(RT_LIBS) $(INOTIFY_LIBS) +EXTRAINCL = $(DBUS_CFLAGS) +EXTRALIBS = $(LDEXECFLAGS) -lwine $(POLL_LIBS) $(RT_LIBS) $(INOTIFY_LIBS) $(DBUS_LIBS) diff --git a/server/thread.c b/server/thread.c index 36bd41e977f..8d8d08ca172 100644 --- a/server/thread.c +++ b/server/thread.c @@ -58,6 +58,77 @@ #include "user.h" #include "security.h"
+#ifdef HAVE_DBUS_DBUS_H +#include <dbus/dbus.h> + +static int rtkit_set_realtime( dbus_uint64_t process, dbus_uint64_t thread, dbus_uint32_t priority ) +{ + DBusConnection* dbus; + DBusMessage *msg; + int ret = -1; + + if ((dbus = dbus_bus_get(DBUS_BUS_SYSTEM, NULL))) + { + dbus_connection_set_exit_on_disconnect(dbus, 0); + + if ((msg = dbus_message_new_method_call("org.freedesktop.RealtimeKit1", + "/org/freedesktop/RealtimeKit1", + "org.freedesktop.RealtimeKit1", + "MakeThreadRealtimeWithPID"))) + { + dbus_message_set_no_reply(msg, 1); + + if (dbus_message_append_args(msg, + DBUS_TYPE_UINT64, &process, + DBUS_TYPE_UINT64, &thread, + DBUS_TYPE_UINT32, &priority, + DBUS_TYPE_INVALID) && + dbus_connection_send(dbus, msg, NULL)) + ret = 0; + + dbus_message_unref(msg); + } + + dbus_connection_unref(dbus); + } + + return ret; +} + +static int rtkit_set_niceness( dbus_uint64_t process, dbus_uint64_t thread, dbus_int32_t niceness ) +{ + DBusConnection* dbus; + DBusMessage *msg; + int ret = -1; + + if ((dbus = dbus_bus_get(DBUS_BUS_SYSTEM, NULL))) + { + dbus_connection_set_exit_on_disconnect(dbus, 0); + + if ((msg = dbus_message_new_method_call("org.freedesktop.RealtimeKit1", + "/org/freedesktop/RealtimeKit1", + "org.freedesktop.RealtimeKit1", + "MakeThreadHighPriorityWithPID"))) + { + dbus_message_set_no_reply(msg, 1); + + if (dbus_message_append_args(msg, + DBUS_TYPE_UINT64, &process, + DBUS_TYPE_UINT64, &thread, + DBUS_TYPE_INT32, &niceness, + DBUS_TYPE_INVALID) && + dbus_connection_send(dbus, msg, NULL)) + ret = 0; + + dbus_message_unref(msg); + } + + dbus_connection_unref(dbus); + } + + return ret; +} +#endif
#ifdef __i386__ static const unsigned int supported_cpus = CPU_FLAG(CPU_x86); @@ -521,7 +592,8 @@ affinity_t get_thread_affinity( struct thread *thread ) return mask; }
-#if defined(HAVE_SCHED_SETSCHEDULER) || defined(HAVE_SETPRIORITY) +#if defined(HAVE_SCHED_SETSCHEDULER) || defined(HAVE_SETPRIORITY) || \ + defined(HAVE_DBUS_DBUS_H) static int get_unix_priority( int priority_class, int priority ) { switch (priority_class) { @@ -641,6 +713,11 @@ int set_thread_priority( struct thread* thread, int priority_class, int priority param.sched_priority = get_unix_priority( priority_class, priority ); if (sched_setscheduler( thread->unix_tid, SCHED_RR|SCHED_RESET_ON_FORK, ¶m ) == 0) return 0; +#endif +#ifdef HAVE_DBUS_DBUS_H + if (rtkit_set_realtime( thread->unix_pid, thread->unix_tid, + get_unix_priority( priority_class, priority ) ) == 0) + return 0; #endif } else @@ -649,6 +726,11 @@ int set_thread_priority( struct thread* thread, int priority_class, int priority if (setpriority( PRIO_PROCESS, thread->unix_tid, get_unix_priority( priority_class, priority ) ) == 0) return 0; +#endif +#ifdef HAVE_DBUS_DBUS_H + if (rtkit_set_niceness( thread->unix_pid, thread->unix_tid, + get_unix_priority( priority_class, priority ) ) == 0) + return 0; #endif } #endif -- 2.23.0