This does not really check for errors in order to avoid introducing breaking changes.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- configure | 69 ++++++++++++++++++++ configure.ac | 19 ++++++ include/config.h.in | 6 ++ server/thread.c | 149 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 230 insertions(+), 13 deletions(-)
diff --git a/configure b/configure index 3b6d744c391..e89be467e2e 100755 --- a/configure +++ b/configure @@ -18065,6 +18065,75 @@ $as_echo "#define HAVE_SCHED_SETAFFINITY 1" >>confdefs.h
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sched_setscheduler" >&5 +$as_echo_n "checking for sched_setscheduler... " >&6; } +if ${wine_cv_have_sched_setscheduler+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _GNU_SOURCE +#include <sched.h> +int +main () +{ +sched_setscheduler(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + wine_cv_have_sched_setscheduler=yes +else + wine_cv_have_sched_setscheduler=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $wine_cv_have_sched_setscheduler" >&5 +$as_echo "$wine_cv_have_sched_setscheduler" >&6; } +if test "$wine_cv_have_sched_setscheduler" = "yes" +then + +$as_echo "#define HAVE_SCHED_SETSCHEDULER 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for setpriority" >&5 +$as_echo_n "checking for setpriority... " >&6; } +if ${wine_cv_have_setpriority+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _GNU_SOURCE +#include <sys/resource.h> +#include <sys/time.h> +int +main () +{ +setpriority(0, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + wine_cv_have_setpriority=yes +else + wine_cv_have_setpriority=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $wine_cv_have_setpriority" >&5 +$as_echo "$wine_cv_have_setpriority" >&6; } +if test "$wine_cv_have_setpriority" = "yes" +then + +$as_echo "#define HAVE_SETPRIORITY 1" >>confdefs.h + +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fallocate" >&5 $as_echo_n "checking for fallocate... " >&6; } if ${wine_cv_have_fallocate+:} false; then : diff --git a/configure.ac b/configure.ac index 709b43b9478..4a3ff36e6b7 100644 --- a/configure.ac +++ b/configure.ac @@ -2233,6 +2233,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/thread.c b/server/thread.c index 7057c9bbd0c..5b5f3cde617 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 @@ -517,28 +523,144 @@ 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 ) +{ + 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 ((priority < min || priority > max) && + priority != THREAD_PRIORITY_IDLE && + priority != THREAD_PRIORITY_TIME_CRITICAL) + { + errno = EINVAL; + return -1; + } + + thread->priority = priority; + if (thread->unix_tid == -1) + return 0; + + if (thread->process->priority == PROCESS_PRIOCLASS_REALTIME) + { +#ifdef HAVE_SCHED_SETSCHEDULER + struct sched_param param; + if (sched_getparam( thread->unix_tid, ¶m ) != 0) + goto error; + + param.sched_priority = get_unix_priority( thread->process->priority, 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( thread->process->priority, priority ) ) == 0) + return 0; +#endif + } + +error: + return 0; +} + /* 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, req->priority )) + file_set_error(); } if (req->mask & SET_THREAD_INFO_AFFINITY) { @@ -1402,6 +1524,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->priority ); set_thread_affinity( current, current->affinity ); } debug_level = max( debug_level, req->debug_level );
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- configure | 10 +++- configure.ac | 2 +- include/config.h.in | 3 + server/Makefile.in | 3 +- server/thread.c | 135 +++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 148 insertions(+), 5 deletions(-)
diff --git a/configure b/configure index e89be467e2e..f9df2f55c69 100755 --- a/configure +++ b/configure @@ -13172,9 +13172,14 @@ $as_echo "$as_me:${as_lineno-$LINENO}: dbus-1 cflags: $DBUS_CFLAGS" >&5 $as_echo "$as_me:${as_lineno-$LINENO}: dbus-1 libs: $DBUS_LIBS" >&5 ac_save_CPPFLAGS=$CPPFLAGS CPPFLAGS="$CPPFLAGS $DBUS_CFLAGS" -ac_fn_c_check_header_mongrel "$LINENO" "dbus/dbus.h" "ac_cv_header_dbus_dbus_h" "$ac_includes_default" +for ac_header in dbus/dbus.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "dbus/dbus.h" "ac_cv_header_dbus_dbus_h" "$ac_includes_default" if test "x$ac_cv_header_dbus_dbus_h" = xyes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -ldbus-1" >&5 + cat >>confdefs.h <<_ACEOF +#define HAVE_DBUS_DBUS_H 1 +_ACEOF + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -ldbus-1" >&5 $as_echo_n "checking for -ldbus-1... " >&6; } if ${ac_cv_lib_soname_dbus_1+:} false; then : $as_echo_n "(cached) " >&6 @@ -13233,6 +13238,7 @@ else DBUS_CFLAGS="" fi
+done
CPPFLAGS=$ac_save_CPPFLAGS test -z "$DBUS_CFLAGS" || DBUS_CFLAGS=`echo " $DBUS_CFLAGS" | sed 's/ -I([^/])/ -I$(top_builddir)/\1/g'` diff --git a/configure.ac b/configure.ac index 4a3ff36e6b7..71d6da3537d 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 5b5f3cde617..77a01b1e693 100644 --- a/server/thread.c +++ b/server/thread.c @@ -58,6 +58,128 @@ #include "user.h" #include "security.h"
+#ifdef HAVE_DBUS_DBUS_H +#include <dbus/dbus.h> + +static int dbus_error_to_errno( DBusError* err ) +{ + if (!err) + return EINVAL; + if (strcmp(err->name, DBUS_ERROR_NO_MEMORY) == 0) + return ENOMEM; + if (strcmp(err->name, DBUS_ERROR_SERVICE_UNKNOWN) == 0 || + strcmp(err->name, DBUS_ERROR_NAME_HAS_NO_OWNER) == 0) + return ENOENT; + if (strcmp(err->name, DBUS_ERROR_ACCESS_DENIED) == 0 || + strcmp(err->name, DBUS_ERROR_AUTH_FAILED) == 0) + return EACCES; + return EIO; +} + +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 (ret) errno = dbus_error_to_errno(&err); + 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 (ret) errno = dbus_error_to_errno(&err); + 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); @@ -523,7 +645,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) { @@ -638,6 +761,11 @@ int set_thread_priority( struct thread* thread, int priority ) param.sched_priority = get_unix_priority( thread->process->priority, 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( thread->process->priority, priority ) ) == 0) + return 0; #endif } else @@ -646,6 +774,11 @@ int set_thread_priority( struct thread* thread, int priority ) if (setpriority( PRIO_PROCESS, thread->unix_tid, get_unix_priority( thread->process->priority, priority ) ) == 0) return 0; +#endif +#ifdef HAVE_DBUS_DBUS_H + if (rtkit_set_niceness( thread->unix_pid, thread->unix_tid, + get_unix_priority( thread->process->priority, priority ) ) == 0) + return 0; #endif }
Rémi Bernon rbernon@codeweavers.com wrote:
diff --git a/configure b/configure index 3b6d744c391..e89be467e2e 100755 --- a/configure +++ b/configure
There is no need to include a diff for auto-generated file.
- if (thread->process->priority == PROCESS_PRIOCLASS_REALTIME)
- {
+#ifdef HAVE_SCHED_SETSCHEDULER
struct sched_param param;
if (sched_getparam( thread->unix_tid, ¶m ) != 0)
goto error;
This 'goto' is useless.
On Wed, 2019-07-03 at 18:03 +0800, Dmitry Timoshkov wrote:
Rémi Bernon rbernon@codeweavers.com wrote:
diff --git a/configure b/configure index 3b6d744c391..e89be467e2e 100755 --- a/configure +++ b/configure
There is no need to include a diff for auto-generated file.
Alright but the file is committed and only regenerated with autoreconf -fi, right? I believe I had to do it manually.
- if (thread->process->priority == PROCESS_PRIOCLASS_REALTIME)
- {
+#ifdef HAVE_SCHED_SETSCHEDULER
struct sched_param param;
if (sched_getparam( thread->unix_tid, ¶m ) != 0)
goto error;
This 'goto' is useless.
The error handling code path currently returns 0 in order not to introduce any behavior change, but it should perhaps return an error code instead. This goto was there to indicate the error codepath is used in opposition to the other return 0 statements which are the "success" codepath. Maybe a return 0 with a comment would make it more clear, as for the last return 0 as well.
Rémi Bernon rbernon@codeweavers.com wrote:
diff --git a/configure b/configure index 3b6d744c391..e89be467e2e 100755 --- a/configure +++ b/configure
There is no need to include a diff for auto-generated file.
Alright but the file is committed and only regenerated with autoreconf -fi, right? I believe I had to do it manually.
Somebody else (read: Julliard) will do that for you.
- if (thread->process->priority == PROCESS_PRIOCLASS_REALTIME)
- {
+#ifdef HAVE_SCHED_SETSCHEDULER
struct sched_param param;
if (sched_getparam( thread->unix_tid, ¶m ) != 0)
goto error;
This 'goto' is useless.
The error handling code path currently returns 0 in order not to introduce any behavior change, but it should perhaps return an error code instead. This goto was there to indicate the error codepath is used in opposition to the other return 0 statements which are the "success" codepath. Maybe a return 0 with a comment would make it more clear, as for the last return 0 as well.
You are free to change 'return 0;' to a proper error handling in a patch that actually intruduces it, until that it's purely confusing and looks like a bad coding style.