Hi all,

I decided to dig through the sample documentation for rtkit and see if I could find a way to make it work for wine. There's still a few things missing: hardcoded libdbus soname, no checking if dbus is available, -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include should be added to ntdll/Makefile and SIGXCPU should demote all threads of the application back to normal priority

The server queues an APC to the target thread that signals it should try to acquire rt prio for it. the thread makes a request to rtkit over dbus to say it wants realtime. This is because rtkit requires the affected process to call dbus.

Any moral objections to this approach?

Cheers,
Maarten
>From aeace7baf8a926f162cbd96dfdb5c767b4346d26 Mon Sep 17 00:00:00 2001
From: Maarten Lankhorst <[email protected]>
Date: Fri, 20 Nov 2009 18:14:50 +0100
Subject: [PATCH 04/17] server: Thread prio patch based on rtkit

---
 dlls/ntdll/rtkit.c  |  201 +++++++++++++++++++++++++++++++++++++++++++++++++++
 dlls/ntdll/rtkit.h  |   22 ++++++
 dlls/ntdll/sync.c   |   11 +++
 server/protocol.def |    7 ++
 server/thread.c     |   14 ++++
 5 files changed, 255 insertions(+), 0 deletions(-)
 create mode 100644 dlls/ntdll/rtkit.c
 create mode 100644 dlls/ntdll/rtkit.h

diff --git a/dlls/ntdll/rtkit.c b/dlls/ntdll/rtkit.c
new file mode 100644
index 0000000..1eb8fc3
--- /dev/null
+++ b/dlls/ntdll/rtkit.c
@@ -0,0 +1,201 @@
+/*-*- 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>
+#include "rtkit.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;
+}
+
+static void set_rttime_limit(void)
+{
+    struct rlimit rlimit;
+    static int set;
+
+    if (set)
+        return;
+    set = 1;
+
+    rlimit.rlim_max = 60000000ULL;
+    rlimit.rlim_cur = rlimit.rlim_max - 10000000ULL;
+    setrlimit( RLIMIT_RTTIME, &rlimit );
+}
+
+int rtkit_make_realtime(pid_t thread, int priority) {
+    DBusConnection *bus = get_dbus();
+    DBusMessage *m = NULL, *r = NULL;
+    dbus_uint64_t u64;
+    dbus_uint32_t u32;
+    DBusError error;
+    int ret;
+
+    if (!bus)
+        return -ENOTSUP;
+
+    set_rttime_limit();
+
+    pdbus_error_init(&error);
+
+    if (!(m = pdbus_message_new_method_call(
+                          RTKIT_SERVICE_NAME,
+                          RTKIT_OBJECT_PATH,
+                          "org.freedesktop.RealtimeKit1",
+                          "MakeThreadRealtime"))) {
+            ret = -ENOMEM;
+            goto finish;
+    }
+
+    u64 = (dbus_uint64_t) thread;
+    u32 = (dbus_uint32_t) priority;
+
+    if (!pdbus_message_append_args(m, DBUS_TYPE_UINT64, &u64,
+                                   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 thread, int priority) {
+        return -ENOTSUP;
+}
+
+int rtkit_undo_realtime(pid_t thread) {
+        return -ENOTSUP;
+}
+
+#endif
diff --git a/dlls/ntdll/rtkit.h b/dlls/ntdll/rtkit.h
new file mode 100644
index 0000000..e84227e
--- /dev/null
+++ b/dlls/ntdll/rtkit.h
@@ -0,0 +1,22 @@
+/*
+ * realtime kit interface
+ *
+ * Copyright (C) 2010 Maarten Lankhorst
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+extern int rtkit_make_realtime(pid_t tid, int prio);
+extern int rtkit_undo_realtime(pid_t tid);
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 3e27d09..6318c6e 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -35,6 +35,7 @@
 #ifdef HAVE_SYS_POLL_H
 # include <sys/poll.h>
 #endif
+#include <sys/types.h>
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
@@ -51,6 +52,7 @@
 #define NONAMELESSSTRUCT
 
 #include "ntstatus.h"
+#include "rtkit.h"
 #define WIN32_NO_STATUS
 #include "windef.h"
 #include "winternl.h"
@@ -878,6 +880,15 @@ static BOOL invoke_apc( const apc_call_t *call, 
apc_result_t *result )
         }
         break;
     }
+    case APC_SET_RT:
+    {
+        int ret;
+        if (call->setrt.rt)
+            ret = rtkit_make_realtime(call->setrt.tid, 1);
+        else
+            ret = rtkit_undo_realtime(call->setrt.tid);
+        FIXME("setrt(%i) on %i returns %i\n", call->setrt.rt, call->setrt.tid, 
ret);
+    }
     case APC_VIRTUAL_ALLOC:
         result->type = call->type;
         addr = wine_server_get_ptr( call->virtual_alloc.addr );
diff --git a/server/protocol.def b/server/protocol.def
index 4aaff10..0c97021 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -373,6 +373,7 @@ enum apc_type
     APC_USER,
     APC_TIMER,
     APC_ASYNC_IO,
+    APC_SET_RT,
     APC_VIRTUAL_ALLOC,
     APC_VIRTUAL_FREE,
     APC_VIRTUAL_QUERY,
@@ -413,6 +414,12 @@ typedef union
     } async_io;
     struct
     {
+        enum apc_type    type;     /* APC_SET_RT */
+        int              rt;       /* should set or remove rt? */
+        thread_id_t      tid;      /* unix tid for thread */
+    } setrt;
+    struct
+    {
         enum apc_type    type;      /* APC_VIRTUAL_ALLOC */
         unsigned int     op_type;   /* type of operation */
         client_ptr_t     addr;      /* requested address */
diff --git a/server/thread.c b/server/thread.c
index a6bc55a..fd7dbf0 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -439,6 +439,16 @@ int set_thread_affinity( struct thread *thread, affinity_t 
affinity )
 #define THREAD_PRIORITY_REALTIME_HIGHEST 6
 #define THREAD_PRIORITY_REALTIME_LOWEST -7
 
+static void set_thread_priority( struct thread *thread, int ntprio )
+{
+    apc_call_t data;
+    data.type = APC_SET_RT;
+    data.setrt.rt = (ntprio == THREAD_PRIORITY_TIME_CRITICAL);
+    data.setrt.tid = thread->unix_tid;
+
+    thread_queue_apc( thread, NULL, &data );
+}
+
 /* set all information about a thread */
 static void set_thread_info( struct thread *thread,
                              const struct set_thread_info_request *req )
@@ -455,7 +465,11 @@ 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->priority != req->priority) && (thread->unix_tid != 
-1))
+                set_thread_priority( thread, req->priority );
             thread->priority = req->priority;
+        }
         else
             set_error( STATUS_INVALID_PARAMETER );
     }
-- 
1.7.0



Reply via email to