This does not report permission errors in order to avoid any breaking change, only the parameter checks that were already there are returning errors.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- configure.ac | 19 ++++++ include/config.h.in | 6 ++ server/process.c | 20 +++++- server/thread.c | 152 ++++++++++++++++++++++++++++++++++++++++---- server/thread.h | 1 + 5 files changed, 184 insertions(+), 14 deletions(-)
diff --git a/configure.ac b/configure.ac index a7c45ace738..4eca35b06f5 100644 --- a/configure.ac +++ b/configure.ac @@ -2234,6 +2234,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 ce5c1570541..1acc02b7173 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -788,6 +788,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
@@ -812,6 +815,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 b67bd88da47..bf216a76f78 100644 --- a/server/process.c +++ b/server/process.c @@ -1464,6 +1464,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; @@ -1489,7 +1507,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 d5742a1bf96..1b8819bf93f 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 @@ -516,28 +522,147 @@ 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; + + 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 + } + + 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) { @@ -1368,6 +1493,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 40f0eecbf1b..5e58a1bc683 100644 --- a/server/thread.h +++ b/server/thread.h @@ -126,6 +126,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 --- configure.ac | 2 +- include/config.h.in | 3 ++ server/Makefile.in | 3 +- server/thread.c | 118 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 123 insertions(+), 3 deletions(-)
diff --git a/configure.ac b/configure.ac index 4eca35b06f5..91702d4e54a 100644 --- a/configure.ac +++ b/configure.ac @@ -1386,7 +1386,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 1acc02b7173..6c279f932cf 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 1b8819bf93f..c473b18c8ea 100644 --- a/server/thread.c +++ b/server/thread.c @@ -58,6 +58,111 @@ #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 = NULL; + DBusMessage *msg = NULL, *rep = NULL; + DBusError err; + int ret = -1; + + dbus_error_init(&err); + + dbus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err); + if (dbus_error_is_set(&err)) + goto error; + + 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"))) + goto error; + + if (!dbus_message_append_args(msg, + DBUS_TYPE_UINT64, &process, + DBUS_TYPE_UINT64, &thread, + DBUS_TYPE_UINT32, &priority, + DBUS_TYPE_INVALID)) + goto error; + + if (!(rep = dbus_connection_send_with_reply_and_block(dbus, msg, -1, &err))) + goto error; + + if (dbus_error_is_set(&err)) + goto error; + + if (dbus_set_error_from_message(&err, rep)) + goto error; + + ret = 0; + +error: + if (rep) dbus_message_unref(rep); + if (msg) dbus_message_unref(msg); + if (dbus) + { + dbus_connection_close(dbus); + dbus_connection_unref(dbus); + } + dbus_error_free(&err); + return ret; +} + +static int rtkit_set_niceness( dbus_uint64_t process, dbus_uint64_t thread, dbus_int32_t niceness ) +{ + DBusConnection* dbus = NULL; + DBusMessage *msg = NULL, *rep = NULL; + DBusError err; + int ret = -1; + + dbus_error_init(&err); + + dbus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err); + if (dbus_error_is_set(&err)) + goto error; + + 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"))) + goto error; + + if (!dbus_message_append_args(msg, + DBUS_TYPE_UINT64, &process, + DBUS_TYPE_UINT64, &thread, + DBUS_TYPE_INT32, &niceness, + DBUS_TYPE_INVALID)) + goto error; + + if (!(rep = dbus_connection_send_with_reply_and_block(dbus, msg, -1, &err))) + goto error; + + if (dbus_error_is_set(&err)) + goto error; + + if (dbus_set_error_from_message(&err, rep)) + goto error; + + ret = 0; + +error: + if (rep) dbus_message_unref(rep); + if (msg) dbus_message_unref(msg); + if (dbus) + { + dbus_connection_close(dbus); + dbus_connection_unref(dbus); + } + dbus_error_free(&err); + return ret; +} +#endif
#ifdef __i386__ static const unsigned int supported_cpus = CPU_FLAG(CPU_x86); @@ -522,7 +627,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 +747,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 +760,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 }