WIP: rtkit support

This commit is contained in:
Oystein Kristoffer Tveit 2024-11-25 08:52:41 +01:00
parent 1adc5e6495
commit 06c56eb047
Signed by: oysteikt
GPG Key ID: 9F2F7D8250F35146
3 changed files with 240 additions and 3 deletions

View File

@ -192,6 +192,7 @@ option('solaris_output', type: 'feature', description: 'Solaris /dev/audio suppo
#
option('dbus', type: 'feature', description: 'D-Bus support')
option('rtkit', type: 'feature', description: 'Use RealtimeKit for requesting realtime scheduling')
option('expat', type: 'feature', description: 'Expat XML support')
option('icu', type: 'feature', description: 'Use libicu for Unicode')
option('iconv', type: 'feature', description: 'Use iconv() for character set conversion')

View File

@ -8,10 +8,206 @@
#include <sched.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <dbus/dbus.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#elif defined(_WIN32)
#include <windows.h>
#endif
#ifdef __linux__
const char* RTKIT_SERVICE_NAME = "org.freedesktop.RealtimeKit1";
const char* RTKIT_OBJECT_PATH = "/org/freedesktop/RealtimeKit1";
// static int
// rtkit_get_max_realtime_priority(DBusConnection &connection)
// {
// // TODO: Implement this function
// DBusError error;
// }
// static void
// rtkit_make_realtime(DBusConnection &connection, pid_t thread, int priority)
// {
// // TODO: Implement this function
// }
#endif
// TODO: minimize and drop
#ifdef __linux__
#define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1"
#define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1"
static pid_t _gettid(void) {
return (pid_t) syscall(SYS_gettid);
}
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 long long rtkit_get_int_property(DBusConnection *connection, const char* propname, long long* propval) {
DBusMessage *m = NULL, *r = NULL;
DBusMessageIter iter, subiter;
dbus_int64_t i64;
dbus_int32_t i32;
DBusError error;
int current_type;
long long ret;
const char * interfacestr = "org.freedesktop.RealtimeKit1";
dbus_error_init(&error);
if (!(m = dbus_message_new_method_call(
RTKIT_SERVICE_NAME,
RTKIT_OBJECT_PATH,
"org.freedesktop.DBus.Properties",
"Get"))) {
ret = -ENOMEM;
goto finish;
}
if (!dbus_message_append_args(
m,
DBUS_TYPE_STRING, &interfacestr,
DBUS_TYPE_STRING, &propname,
DBUS_TYPE_INVALID)) {
ret = -ENOMEM;
goto finish;
}
if (!(r = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
ret = translate_error(error.name);
goto finish;
}
if (dbus_set_error_from_message(&error, r)) {
ret = translate_error(error.name);
goto finish;
}
ret = -EBADMSG;
dbus_message_iter_init(r, &iter);
while ((current_type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID) {
if (current_type == DBUS_TYPE_VARIANT) {
dbus_message_iter_recurse(&iter, &subiter);
while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID) {
if (current_type == DBUS_TYPE_INT32) {
dbus_message_iter_get_basic(&subiter, &i32);
*propval = i32;
ret = 0;
}
if (current_type == DBUS_TYPE_INT64) {
dbus_message_iter_get_basic(&subiter, &i64);
*propval = i64;
ret = 0;
}
dbus_message_iter_next (&subiter);
}
}
dbus_message_iter_next (&iter);
}
finish:
if (m)
dbus_message_unref(m);
if (r)
dbus_message_unref(r);
dbus_error_free(&error);
return ret;
}
static int rtkit_get_max_realtime_priority(DBusConnection *connection) {
long long retval;
int err;
err = rtkit_get_int_property(connection, "MaxRealtimePriority", &retval);
return err < 0 ? err : retval;
}
static int rtkit_make_realtime(DBusConnection *connection, pid_t thread, int priority) {
DBusMessage *m = NULL, *r = NULL;
dbus_uint64_t u64;
dbus_uint32_t u32;
DBusError error;
int ret;
dbus_error_init(&error);
if (thread == 0)
thread = _gettid();
if (!(m = dbus_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 (!dbus_message_append_args(
m,
DBUS_TYPE_UINT64, &u64,
DBUS_TYPE_UINT32, &u32,
DBUS_TYPE_INVALID)) {
ret = -ENOMEM;
goto finish;
}
if (!(r = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
ret = translate_error(error.name);
goto finish;
}
if (dbus_set_error_from_message(&error, r)) {
ret = translate_error(error.name);
goto finish;
}
ret = 0;
finish:
if (m)
dbus_message_unref(m);
if (r)
dbus_message_unref(r);
dbus_error_free(&error);
return ret;
}
#endif
#ifdef __linux__
#ifndef ANDROID
@ -82,7 +278,39 @@ SetThreadRealtime()
policy |= SCHED_RESET_ON_FORK;
#endif
if (linux_sched_setscheduler(0, policy, &sched_param) < 0)
throw MakeErrno("sched_setscheduler failed");
int res = linux_sched_setscheduler(0, policy, &sched_param);
if (res < 0 && errno == EPERM) {
DBusError error;
DBusConnection *system_bus;
if (!(system_bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
throw MakeErrno("could not connect to dbus");
}
int max_realtime_priority;
if ((max_realtime_priority = rtkit_get_max_realtime_priority(system_bus)) < 0) {
dbus_connection_unref(system_bus);
throw MakeErrno("could not retrieve maximum realtime priority allowed");
}
if (max_realtime_priority < sched_param.sched_priority) {
dbus_connection_unref(system_bus);
throw MakeErrno("maximum realtime priority is below 40");
}
pid_t pid = getpid();
if (rtkit_make_realtime(system_bus, pid, sched_param.sched_priority) < 0) {
dbus_connection_unref(system_bus);
throw MakeErrno("failed to request realtime scheduling");
}
dbus_connection_unref(system_bus);
res = 0;
}
// if (res < 0) {
// throw MakeErrno("sched_setscheduler failed");
// }
#endif // __linux__
}

View File

@ -7,6 +7,13 @@ else
threads_dep = dependency('threads')
endif
if is_linux
dbus_dep = dependency('dbus-1', required: get_option('dbus'))
conf.set('ENABLE_DBUS', dbus_dep.found())
else
dbus_dep = []
endif
conf.set('HAVE_PTHREAD_SETNAME_NP', compiler.has_function('pthread_setname_np', dependencies: threads_dep))
thread = static_library(
@ -16,6 +23,7 @@ thread = static_library(
include_directories: inc,
dependencies: [
threads_dep,
dbus_dep,
],
)