From 9e494e4a1587cc07752897a787f626b99f711756 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Fri, 23 Apr 2010 23:21:37 +0200 Subject: [PATCH 03/10] server: Use rtkit to set realtime priority, try 3 --- configure | 117 ++++++++++++++++++++++++-------- configure.ac | 41 +++++++++--- include/config.h.in | 3 + libs/wine/loader.c | 27 +++++++ server/Makefile.in | 2 + server/rtkit.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++++++ server/thread.c | 16 +++++ 7 files changed, 354 insertions(+), 39 deletions(-) create mode 100644 server/rtkit.c diff --git a/configure b/configure index 52410fb..d732d9d 100755 --- a/configure +++ b/configure @@ -634,6 +634,7 @@ gphoto2_devel SANEINCL sane_devel GNUTLSINCL +DBUSINCL HALINCL XSLTINCL XML2INCL @@ -772,6 +773,7 @@ with_cms with_coreaudio with_cups with_curses +with_dbus with_esd with_fontconfig with_freetype @@ -1459,6 +1461,7 @@ Optional Packages: --without-coreaudio do not use the CoreAudio sound support --without-cups do not use CUPS --without-curses do not use (n)curses + --without-dbus do not use dbus (will also disable HAL support) --without-esd do not use the EsounD sound support --without-fontconfig do not use fontconfig --without-freetype do not use the FreeType library @@ -2539,6 +2542,12 @@ if test "${with_curses+set}" = set; then : fi +# Check whether --with-dbus was given. +if test "${with_dbus+set}" = set; then : + withval=$with_dbus; +fi + + # Check whether --with-esd was given. if test "${with_esd+set}" = set; then : withval=$with_esd; @@ -9260,39 +9269,40 @@ fi HALINCL="" -if test "x$with_hal" != "xno" +DBUSINCL="" + + +if test "x$with_dbus" != "xno" then ac_save_CPPFLAGS="$CPPFLAGS" if test "$PKG_CONFIG" != "false" then - ac_hal_libs="`$PKG_CONFIG --libs hal 2>/dev/null`" - ac_hal_cflags="`$PKG_CONFIG --cflags hal 2>/dev/null`" - CPPFLAGS="$CPPFLAGS $ac_hal_cflags" + ac_dbus_libs="`$PKG_CONFIG --libs dbus-1 2>/dev/null`" + ac_dbus_cflags="`$PKG_CONFIG --cflags dbus-1 2>/dev/null`" + CPPFLAGS="$CPPFLAGS $ac_dbus_cflags" fi - for ac_header in dbus/dbus.h hal/libhal.h + for ac_header in dbus/dbus.h do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : + 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" = x""yes; then : cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +#define HAVE_DBUS_DBUS_H 1 _ACEOF fi done - if test "$ac_cv_header_dbus_dbus_h" = "yes" -a "$ac_cv_header_hal_libhal_h" = "yes" + if test "$ac_cv_header_dbus_dbus_h" = "yes" then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dbus_connection_close in -ldbus-1" >&5 -$as_echo_n "checking for dbus_connection_close in -ldbus-1... " >&6; } -if test "${ac_cv_lib_dbus_1_dbus_connection_close+set}" = set; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -ldbus-1" >&5 +$as_echo_n "checking for -ldbus-1... " >&6; } +if test "${ac_cv_lib_soname_dbus_1+set}" = set; then : $as_echo_n "(cached) " >&6 else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldbus-1 $ac_hal_libs $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext + ac_check_soname_save_LIBS=$LIBS +LIBS="-ldbus-1 $ac_dbus_libs $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -9311,18 +9321,67 @@ return dbus_connection_close (); } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dbus_1_dbus_connection_close=yes -else - ac_cv_lib_dbus_1_dbus_connection_close=no + case "$LIBEXT" in + dll) ac_cv_lib_soname_dbus_1=`$ac_cv_path_LDD conftest.exe | grep "dbus-1" | sed -e "s/dll.*/dll/"';2,$d'` ;; + dylib) ac_cv_lib_soname_dbus_1=`otool -L conftest$ac_exeext | grep "libdbus-1\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libdbus-1\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; + *) ac_cv_lib_soname_dbus_1=`$ac_cv_path_LDD conftest$ac_exeext | grep "libdbus-1\\.$LIBEXT" | sed -e "s/^.*\(libdbus-1\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` ;; + esac fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS + LIBS=$ac_check_soname_save_LIBS +fi +if test "x$ac_cv_lib_soname_dbus_1" = "x"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_dbus_1" >&5 +$as_echo "$ac_cv_lib_soname_dbus_1" >&6; } + +cat >>confdefs.h <<_ACEOF +#define SONAME_LIBDBUS_1 "$ac_cv_lib_soname_dbus_1" +_ACEOF + + DBUSINCL="$ac_dbus_cflags" +fi + fi + + CPPFLAGS="$ac_save_CPPFLAGS" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dbus_1_dbus_connection_close" >&5 -$as_echo "$ac_cv_lib_dbus_1_dbus_connection_close" >&6; } -if test "x$ac_cv_lib_dbus_1_dbus_connection_close" = x""yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -lhal" >&5 +if test "x$ac_cv_lib_soname_dbus_1" = "x" -a "x$ac_cv_header_DiskArbitration_DiskArbitration_h" != "xyes"; then : + case "x$with_dbus" in + x) as_fn_append wine_notices "|libdbus and libhal ${notice_platform}development files not found, HAL and rtkit support disabled" ;; + xno) ;; + *) as_fn_error "libdbus and libhal ${notice_platform}development files not found, HAL and rtkit support disabled +This is an error since --with-dbus was requested." "$LINENO" 5 ;; +esac +fi + +if test "x$with_hal" != "xno" -a "x$ac_cv_lib_soname_dbus_1" != "x" +then + ac_save_CPPFLAGS="$CPPFLAGS" + if test "$PKG_CONFIG" != "false" + then + ac_hal_libs="`$PKG_CONFIG --libs hal 2>/dev/null`" + ac_hal_cflags="`$PKG_CONFIG --cflags hal 2>/dev/null`" + CPPFLAGS="$CPPFLAGS $ac_hal_cflags" + fi + for ac_header in hal/libhal.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "hal/libhal.h" "ac_cv_header_hal_libhal_h" "$ac_includes_default" +if test "x$ac_cv_header_hal_libhal_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_HAL_LIBHAL_H 1 +_ACEOF + +fi + +done + + if test "$ac_cv_header_hal_libhal_h" = "yes" + then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -lhal" >&5 $as_echo_n "checking for -lhal... " >&6; } if test "${ac_cv_lib_soname_hal+set}" = set; then : $as_echo_n "(cached) " >&6 @@ -9372,16 +9431,14 @@ _ACEOF HALINCL="$ac_hal_cflags" fi -fi - fi CPPFLAGS="$ac_save_CPPFLAGS" fi -if test "x$ac_cv_lib_soname_hal" = "x" -a "x$ac_cv_header_DiskArbitration_DiskArbitration_h" != "xyes"; then : +if test "x$ac_cv_lib_soname_hal" = "x" -a "x$ac_cv_header_DiskArbitration_DiskArbitration_h" != "xyes" -a "x$ac_cv_lib_soname_dbus_1" != "x"; then : case "x$with_hal" in - x) as_fn_append wine_notices "|libhal/libdbus ${notice_platform}development files not found, no dynamic device support." ;; + x) as_fn_append wine_notices "|libhal ${notice_platform}development files not found, no dynamic device support." ;; xno) ;; - *) as_fn_error "libhal/libdbus ${notice_platform}development files not found, no dynamic device support. + *) as_fn_error "libhal ${notice_platform}development files not found, no dynamic device support. This is an error since --with-hal was requested." "$LINENO" 5 ;; esac fi diff --git a/configure.ac b/configure.ac index 227dee5..179bcc3 100644 --- a/configure.ac +++ b/configure.ac @@ -36,6 +36,7 @@ AC_ARG_WITH(coreaudio, AS_HELP_STRING([--without-coreaudio],[do not use the Core AC_ARG_WITH(cups, AS_HELP_STRING([--without-cups],[do not use CUPS])) AC_ARG_WITH(curses, AS_HELP_STRING([--without-curses],[do not use (n)curses]), [if test "x$withval" = "xno"; then ac_cv_header_ncurses_h=no; ac_cv_header_curses_h=no; fi]) +AC_ARG_WITH(dbus, AS_HELP_STRING([--without-dbus],[do not use dbus (will also disable HAL support)])) AC_ARG_WITH(esd, AS_HELP_STRING([--without-esd],[do not use the EsounD sound support])) AC_ARG_WITH(fontconfig,AS_HELP_STRING([--without-fontconfig],[do not use fontconfig]), [if test "x$withval" = "xno"; then ac_cv_header_fontconfig_fontconfig_h=no; fi]) @@ -1113,9 +1114,32 @@ fi WINE_WARNING_WITH(xslt,[test "x$ac_cv_lib_soname_xslt" = "x"], [libxslt ${notice_platform}development files not found, xslt won't be supported.]) -dnl **** Check for libhal **** +dnl **** Check for libdbus-1 and libhal **** AC_SUBST(HALINCL,"") -if test "x$with_hal" != "xno" +AC_SUBST(DBUSINCL,"") + +if test "x$with_dbus" != "xno" +then + ac_save_CPPFLAGS="$CPPFLAGS" + if test "$PKG_CONFIG" != "false" + then + ac_dbus_libs="`$PKG_CONFIG --libs dbus-1 2>/dev/null`" + ac_dbus_cflags="`$PKG_CONFIG --cflags dbus-1 2>/dev/null`" + CPPFLAGS="$CPPFLAGS $ac_dbus_cflags" + fi + AC_CHECK_HEADERS([dbus/dbus.h]) + if test "$ac_cv_header_dbus_dbus_h" = "yes" + then + WINE_CHECK_SONAME(dbus-1, dbus_connection_close, + [DBUSINCL="$ac_dbus_cflags"],,[$ac_dbus_libs]) + fi + + CPPFLAGS="$ac_save_CPPFLAGS" +fi +WINE_NOTICE_WITH(dbus,[test "x$ac_cv_lib_soname_dbus_1" = "x" -a "x$ac_cv_header_DiskArbitration_DiskArbitration_h" != "xyes"], + [libdbus and libhal ${notice_platform}development files not found, HAL and rtkit support disabled]) + +if test "x$with_hal" != "xno" -a "x$ac_cv_lib_soname_dbus_1" != "x" then ac_save_CPPFLAGS="$CPPFLAGS" if test "$PKG_CONFIG" != "false" @@ -1124,17 +1148,16 @@ then ac_hal_cflags="`$PKG_CONFIG --cflags hal 2>/dev/null`" CPPFLAGS="$CPPFLAGS $ac_hal_cflags" fi - AC_CHECK_HEADERS([dbus/dbus.h hal/libhal.h]) - if test "$ac_cv_header_dbus_dbus_h" = "yes" -a "$ac_cv_header_hal_libhal_h" = "yes" + AC_CHECK_HEADERS([hal/libhal.h]) + if test "$ac_cv_header_hal_libhal_h" = "yes" then - AC_CHECK_LIB(dbus-1, dbus_connection_close, - [WINE_CHECK_SONAME(hal, libhal_ctx_new, - [HALINCL="$ac_hal_cflags"],,[$ac_hal_libs])],,[$ac_hal_libs]) + WINE_CHECK_SONAME(hal, libhal_ctx_new, + [HALINCL="$ac_hal_cflags"],,[$ac_hal_libs]) fi CPPFLAGS="$ac_save_CPPFLAGS" fi -WINE_NOTICE_WITH(hal,[test "x$ac_cv_lib_soname_hal" = "x" -a "x$ac_cv_header_DiskArbitration_DiskArbitration_h" != "xyes"], - [libhal/libdbus ${notice_platform}development files not found, no dynamic device support.]) +WINE_NOTICE_WITH(hal,[test "x$ac_cv_lib_soname_hal" = "x" -a "x$ac_cv_header_DiskArbitration_DiskArbitration_h" != "xyes" -a "x$ac_cv_lib_soname_dbus_1" != "x"], + [libhal ${notice_platform}development files not found, no dynamic device support.]) dnl **** Check for libgnutls **** if test "x$with_gnutls" != "xno" diff --git a/include/config.h.in b/include/config.h.in index 0faf127..60e12a4 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -1181,6 +1181,9 @@ /* Define to the soname of the libcurses library. */ #undef SONAME_LIBCURSES +/* Define to the soname of the libdbus-1 library. */ +#undef SONAME_LIBDBUS_1 + /* Define to the soname of the libfontconfig library. */ #undef SONAME_LIBFONTCONFIG diff --git a/libs/wine/loader.c b/libs/wine/loader.c index 37c603e..69a9292 100644 --- a/libs/wine/loader.c +++ b/libs/wine/loader.c @@ -669,6 +669,32 @@ static void set_max_limit( int limit ) /*********************************************************************** + * set_rttime_limit + * + * set a limit on the cpu time used + */ +static void set_rttime_limit(void) +{ +#if defined(HAVE_SETRLIMIT) && defined(__linux__) +#ifndef RLIMIT_RTTIME +#define RLIMIT_RTTIME 15 +#endif + struct rlimit rlimit; + + if (!getrlimit( RLIMIT_RTTIME, &rlimit )) + { + /* 50 ms realtime, then 10 ms to undo realtime */ + if (rlimit.rlim_max > 60000000ULL) + rlimit.rlim_max = 60000000ULL; + rlimit.rlim_cur = rlimit.rlim_max - 10000000ULL; + + setrlimit( RLIMIT_RTTIME, &rlimit ); + } +#endif +} + + +/*********************************************************************** * wine_init * * Main Wine initialisation. @@ -687,6 +713,7 @@ void wine_init( int argc, char *argv[], char *error, int error_size ) #ifdef RLIMIT_AS set_max_limit( RLIMIT_AS ); #endif + set_rttime_limit(); wine_init_argv0_path( argv[0] ); build_dll_path(); diff --git a/server/Makefile.in b/server/Makefile.in index 7a67707..1197066 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -5,6 +5,7 @@ SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = none EXTRALIBS = @LIBPOLL@ +MODCFLAGS = @DBUSINCL@ C_SRCS = \ async.c \ @@ -36,6 +37,7 @@ C_SRCS = \ region.c \ registry.c \ request.c \ + rtkit.c \ semaphore.c \ serial.c \ signal.c \ diff --git a/server/rtkit.c b/server/rtkit.c new file mode 100644 index 0000000..890c8a6 --- /dev/null +++ b/server/rtkit.c @@ -0,0 +1,187 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + Copyright 2009 Lennart Poettering + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +***/ + +#include "config.h" +#include "wine/port.h" +#include "wine/library.h" + +#include +#include +#ifdef HAVE_SYS_SCHED_H +#include +#endif +#include + +#if defined(HAVE_SETRLIMIT) && defined(__linux__) && defined(SONAME_LIBDBUS_1) + +#include +#include +#include +#include +#include + +#ifndef RLIMIT_RTTIME +#define RLIMIT_RTTIME 15 +#endif + +#define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1" +#define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1" + +#define FUNCPTR(fn) static typeof(fn) *p ##fn + +FUNCPTR(dbus_error_init); +FUNCPTR(dbus_error_free); +FUNCPTR(dbus_bus_get); +FUNCPTR(dbus_message_new_method_call); +FUNCPTR(dbus_message_append_args); +FUNCPTR(dbus_connection_send_with_reply_and_block); +FUNCPTR(dbus_message_unref); +FUNCPTR(dbus_set_error_from_message); +#undef FUNCPTR + +static int translate_error(const char *name) { + if (strcmp(name, DBUS_ERROR_NO_MEMORY) == 0) + return -ENOMEM; + if (strcmp(name, DBUS_ERROR_SERVICE_UNKNOWN) == 0 || + strcmp(name, DBUS_ERROR_NAME_HAS_NO_OWNER) == 0) + return -ENOENT; + if (strcmp(name, DBUS_ERROR_ACCESS_DENIED) == 0 || + strcmp(name, DBUS_ERROR_AUTH_FAILED) == 0) + return -EACCES; + + return -EIO; +} + +static void init_dbus(void) { +#define FUNCPTR(fn) p ##fn = wine_dlsym(libdbus, #fn, NULL, 0); + char error[512]; + void *libdbus = wine_dlopen(SONAME_LIBDBUS_1, RTLD_NOW, error, sizeof(error)); + FUNCPTR(dbus_error_init); + FUNCPTR(dbus_error_free); + FUNCPTR(dbus_bus_get); + FUNCPTR(dbus_message_new_method_call); + FUNCPTR(dbus_message_append_args); + FUNCPTR(dbus_connection_send_with_reply_and_block); + FUNCPTR(dbus_message_unref); + FUNCPTR(dbus_set_error_from_message); +#undef FUNCPTR +} + +static DBusConnection *get_dbus(void) { + static DBusConnection *bus; + DBusError error; + + if (bus) + return bus; + init_dbus(); + pdbus_error_init(&error); + + bus = pdbus_bus_get(DBUS_BUS_SYSTEM, &error); + return bus; +} + +int rtkit_make_realtime(pid_t process, pid_t thread, int priority) { + DBusConnection *bus = get_dbus(); + DBusMessage *m = NULL, *r = NULL; + dbus_uint64_t pid, tid; + dbus_uint32_t u32; + DBusError error; + int ret; + + if (!bus) + return -ENOTSUP; + + pdbus_error_init(&error); + + if (!(m = pdbus_message_new_method_call( + RTKIT_SERVICE_NAME, + RTKIT_OBJECT_PATH, + "org.freedesktop.RealtimeKit1", + "MakeThreadRealtimeWithPID"))) { + ret = -ENOMEM; + goto finish; + } + + pid = (dbus_uint64_t) process; + tid = (dbus_uint64_t) thread; + u32 = (dbus_uint32_t) priority; + + if (!pdbus_message_append_args(m, DBUS_TYPE_UINT64, &pid, + DBUS_TYPE_UINT64, &tid, + DBUS_TYPE_UINT32, &u32, + DBUS_TYPE_INVALID)) { + ret = -ENOMEM; + goto finish; + } + + if (!(r = pdbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + ret = translate_error(error.name); + goto finish; + } + + + if (pdbus_set_error_from_message(&error, r)) { + ret = translate_error(error.name); + goto finish; + } + + ret = 0; + +finish: + + if (m) + pdbus_message_unref(m); + + if (r) + pdbus_message_unref(r); + + pdbus_error_free(&error); + + return ret; +} + +int rtkit_undo_realtime(pid_t thread) { + struct sched_param parm; + int ret; + memset(&parm, 0, sizeof(parm)); + ret = sched_setscheduler(thread, SCHED_OTHER, &parm); + if (ret < 0) + return -errno; + return ret; +} + +#else + +int rtkit_make_realtime(pid_t process, pid_t thread, int priority) { + return -ENOTSUP; +} + +int rtkit_undo_realtime(pid_t thread) { + return -ENOTSUP; +} + +#endif + diff --git a/server/thread.c b/server/thread.c index a6bc55a..40dd6f0 100644 --- a/server/thread.c +++ b/server/thread.c @@ -52,6 +52,8 @@ #include "user.h" #include "security.h" +extern int rtkit_make_realtime(pid_t process, pid_t thread, int priority); +extern int rtkit_undo_realtime(pid_t thread); #define CPU_FLAG(cpu) (1 << (cpu)) #ifdef __i386__ @@ -455,7 +457,17 @@ static void set_thread_info( struct thread *thread, if ((req->priority >= min && req->priority <= max) || req->priority == THREAD_PRIORITY_IDLE || req->priority == THREAD_PRIORITY_TIME_CRITICAL) + { + if (thread->unix_tid == -1) + {} + else if (thread->priority == THREAD_PRIORITY_TIME_CRITICAL && + req->priority != THREAD_PRIORITY_TIME_CRITICAL) + rtkit_undo_realtime(thread->unix_tid); + else if (thread->priority != THREAD_PRIORITY_TIME_CRITICAL && + req->priority == THREAD_PRIORITY_TIME_CRITICAL) + rtkit_make_realtime(thread->unix_pid, thread->unix_tid, 1); thread->priority = req->priority; + } else set_error( STATUS_INVALID_PARAMETER ); } @@ -1167,6 +1179,10 @@ DECL_HANDLER(init_thread) debug_level = max( debug_level, req->debug_level ); set_thread_affinity( current, current->affinity ); + /* Raced with SetThreadPriority */ + if (current->priority == THREAD_PRIORITY_TIME_CRITICAL) + rtkit_make_realtime(current->unix_pid, current->unix_tid, 1); + reply->pid = get_process_id( process ); reply->tid = get_thread_id( current ); reply->version = SERVER_PROTOCOL_VERSION; -- 1.7.0.4