This does not really check for errors in order to avoid introducing
breaking changes.
Signed-off-by: Rémi Bernon <rbernon(a)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 );
--
2.20.1