commit 81c8e1b77790258fcb3dd59c6b692c126261ac27
Author: Maarten Lankhorst <m.b.lankhorst@gmail.com>
Date:   Fri Apr 23 23:21:37 2010 +0200

    rtkit try 2

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..abcd257 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -5,6 +5,7 @@ SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = none
 EXTRALIBS = @LIBPOLL@
+MODCFLAGS = @HALINCL@
 
 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..13e25f5
--- /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 <errno.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_SCHED_H
+#include <sys/sched.h>
+#endif
+#include <sys/resource.h>
+
+#if defined(HAVE_SETRLIMIT) && defined(__linux__)
+
+#include <sched.h>
+#include <string.h>
+#include <unistd.h>
+#include <dbus/dbus.h>
+#include <sys/syscall.h>
+
+#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("libdbus-glib-1.so.2", 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",
+                          "MakeThreadRealtime2"))) {
+            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;
