>From aeace7baf8a926f162cbd96dfdb5c767b4346d26 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst 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 +#include +#ifdef HAVE_SYS_SCHED_H +#include +#endif +#include +#include "rtkit.h" + +#if defined(HAVE_SETRLIMIT) && defined(__linux__) + +#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("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 #endif +#include #ifdef HAVE_UNISTD_H # include #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