From f1dfa9797bd8542c5b629ab4f651b9e1253206ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hubert=20Figui=C3=A8re?= Date: Tue, 19 Jul 2022 00:02:37 -0400 Subject: [PATCH] Issue #2570 - Use the xdg-portal-destkop of rtkit - If the xdg-desktop-portal is there, use it instead of rtkit - This allow setting the rt priorities within Flatpak --- src/modules/module-rt.c | 142 +++++++++++++++++++++++++++++----------- 1 file changed, 103 insertions(+), 39 deletions(-) diff --git a/src/modules/module-rt.c b/src/modules/module-rt.c index 8da628e9e..b1c963079 100644 --- a/src/modules/module-rt.c +++ b/src/modules/module-rt.c @@ -153,6 +153,11 @@ static const struct spa_dict_item module_props[] = { #ifdef HAVE_DBUS #define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1" #define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1" +#define RTKIT_INTERFACE "org.freedesktop.RealtimeKit1" + +#define XDG_PORTAL_SERVICE_NAME "org.freedesktop.portal.Desktop" +#define XDG_PORTAL_OBJECT_PATH "/org/freedesktop/portal/desktop" +#define XDG_PORTAL_INTERFACE "org.freedesktop.portal.Realtime" /** \cond */ struct pw_rtkit_bus { @@ -184,7 +189,11 @@ struct impl { #ifdef HAVE_DBUS bool use_rtkit; - struct pw_rtkit_bus *system_bus; + /* For D-Bus. These are const static. */ + const char* service_name; + const char* object_path; + const char* interface; + struct pw_rtkit_bus *rtkit_bus; /* These are only for the RTKit implementation to fill in the `thread` * struct. Since there's barely any overhead here we'll do this @@ -215,7 +224,7 @@ static pid_t _gettid(void) } #ifdef HAVE_DBUS -struct pw_rtkit_bus *pw_rtkit_bus_get_system(void) +struct pw_rtkit_bus *pw_rtkit_bus_get(DBusBusType bus_type) { struct pw_rtkit_bus *bus; DBusError error; @@ -231,7 +240,7 @@ struct pw_rtkit_bus *pw_rtkit_bus_get_system(void) if (bus == NULL) return NULL; - bus->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); + bus->bus = dbus_bus_get_private(bus_type, &error); if (bus->bus == NULL) goto error; @@ -241,12 +250,41 @@ struct pw_rtkit_bus *pw_rtkit_bus_get_system(void) error: free(bus); - pw_log_error("Failed to connect to system bus: %s", error.message); + pw_log_error("Failed to connect to %s bus: %s", + bus_type == DBUS_BUS_SYSTEM ? "system" : "session", error.message); dbus_error_free(&error); errno = ECONNREFUSED; return NULL; } +struct pw_rtkit_bus *pw_rtkit_bus_get_system(void) +{ + return pw_rtkit_bus_get(DBUS_BUS_SYSTEM); +} + +struct pw_rtkit_bus *pw_rtkit_bus_get_session(void) +{ + return pw_rtkit_bus_get(DBUS_BUS_SESSION); +} + +bool pw_rtkit_check_xdg_portal(struct pw_rtkit_bus *system_bus) +{ + DBusError error; + bool ret = true; + + dbus_error_init(&error); + + if (!dbus_bus_name_has_owner(system_bus->bus, XDG_PORTAL_SERVICE_NAME, &error)) { + pw_log_warn("Can't find xdg-portal: %s", error.name); + ret = false; + goto finish; + } +finish: + dbus_error_free(&error); + + return ret; +} + void pw_rtkit_bus_free(struct pw_rtkit_bus *system_bus) { dbus_connection_close(system_bus->bus); @@ -270,7 +308,7 @@ static int translate_error(const char *name) return -EIO; } -static long long rtkit_get_int_property(struct pw_rtkit_bus *connection, const char *propname, +static long long rtkit_get_int_property(struct impl *impl, const char *propname, long long *propval) { DBusMessage *m = NULL, *r = NULL; @@ -280,19 +318,19 @@ static long long rtkit_get_int_property(struct pw_rtkit_bus *connection, const c DBusError error; int current_type; long long ret; - const char *interfacestr = "org.freedesktop.RealtimeKit1"; + struct pw_rtkit_bus *connection = impl->rtkit_bus; dbus_error_init(&error); - if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME, - RTKIT_OBJECT_PATH, + if (!(m = dbus_message_new_method_call(impl->service_name, + impl->object_path, "org.freedesktop.DBus.Properties", "Get"))) { ret = -ENOMEM; goto finish; } if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &interfacestr, + DBUS_TYPE_STRING, &impl->interface, DBUS_TYPE_STRING, &propname, DBUS_TYPE_INVALID)) { ret = -ENOMEM; goto finish; @@ -349,60 +387,63 @@ finish: return ret; } -int pw_rtkit_get_max_realtime_priority(struct pw_rtkit_bus *connection) +int pw_rtkit_get_max_realtime_priority(struct impl *impl) { long long retval; int err; - err = rtkit_get_int_property(connection, "MaxRealtimePriority", &retval); + err = rtkit_get_int_property(impl, "MaxRealtimePriority", &retval); return err < 0 ? err : retval; } -int pw_rtkit_get_min_nice_level(struct pw_rtkit_bus *connection, int *min_nice_level) +int pw_rtkit_get_min_nice_level(struct impl *impl, int *min_nice_level) { long long retval; int err; - err = rtkit_get_int_property(connection, "MinNiceLevel", &retval); + err = rtkit_get_int_property(impl, "MinNiceLevel", &retval); if (err >= 0) *min_nice_level = retval; return err; } -long long pw_rtkit_get_rttime_usec_max(struct pw_rtkit_bus *connection) +long long pw_rtkit_get_rttime_usec_max(struct impl *impl) { long long retval; int err; - err = rtkit_get_int_property(connection, "RTTimeUSecMax", &retval); + err = rtkit_get_int_property(impl, "RTTimeUSecMax", &retval); return err < 0 ? err : retval; } -int pw_rtkit_make_realtime(struct pw_rtkit_bus *connection, pid_t thread, int priority) +int pw_rtkit_make_realtime(struct impl *impl, pid_t thread, int priority) { DBusMessage *m = NULL, *r = NULL; + dbus_uint64_t pid; dbus_uint64_t u64; dbus_uint32_t u32; DBusError error; int ret; + struct pw_rtkit_bus *connection = impl->rtkit_bus; 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"))) { + if (!(m = dbus_message_new_method_call(impl->service_name, + impl->object_path, impl->interface, + "MakeThreadRealtimeWithPID"))) { ret = -ENOMEM; goto finish; } + pid = (dbus_uint64_t) getpid(); u64 = (dbus_uint64_t) thread; u32 = (dbus_uint32_t) priority; if (!dbus_message_append_args(m, + DBUS_TYPE_UINT64, &pid, DBUS_TYPE_UINT64, &u64, DBUS_TYPE_UINT32, &u32, DBUS_TYPE_INVALID)) { ret = -ENOMEM; @@ -435,31 +476,34 @@ finish: return ret; } -int pw_rtkit_make_high_priority(struct pw_rtkit_bus *connection, pid_t thread, int nice_level) +int pw_rtkit_make_high_priority(struct impl *impl, pid_t thread, int nice_level) { DBusMessage *m = NULL, *r = NULL; + dbus_uint64_t pid; dbus_uint64_t u64; dbus_int32_t s32; DBusError error; int ret; + struct pw_rtkit_bus *connection = impl->rtkit_bus; 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", - "MakeThreadHighPriority"))) { + if (!(m = dbus_message_new_method_call(impl->service_name, + impl->object_path, impl->interface, + "MakeThreadHighPriorityWithPID"))) { ret = -ENOMEM; goto finish; } + pid = (dbus_uint64_t) getpid(); u64 = (dbus_uint64_t) thread; s32 = (dbus_int32_t) nice_level; if (!dbus_message_append_args(m, + DBUS_TYPE_UINT64, &pid, DBUS_TYPE_UINT64, &u64, DBUS_TYPE_INT32, &s32, DBUS_TYPE_INVALID)) { ret = -ENOMEM; @@ -502,8 +546,8 @@ static void module_destroy(void *data) spa_hook_remove(&impl->module_listener); #ifdef HAVE_DBUS - if (impl->system_bus) - pw_rtkit_bus_free(impl->system_bus); + if (impl->rtkit_bus) + pw_rtkit_bus_free(impl->rtkit_bus); #endif free(impl); @@ -566,7 +610,7 @@ static int set_nice(struct impl *impl, int nice_level) #ifdef HAVE_DBUS if (impl->use_rtkit) - res = pw_rtkit_make_high_priority(impl->system_bus, 0, nice_level); + res = pw_rtkit_make_high_priority(impl, 0, nice_level); else res = sched_set_nice(nice_level); #else @@ -596,7 +640,7 @@ static int set_rlimit(struct impl *impl) #ifdef HAVE_DBUS if (impl->use_rtkit) { long long rttime; - rttime = pw_rtkit_get_rttime_usec_max(impl->system_bus); + rttime = pw_rtkit_get_rttime_usec_max(impl); if (rttime >= 0) { if ((rlim_t)rttime < rl.rlim_cur) { pw_log_debug("clamping rt.time.soft from %llu to %lld because of RTKit", @@ -741,7 +785,7 @@ static int impl_get_rt_range(void *object, const struct spa_dict *props, if (min) *min = 1; if (max) - *max = pw_rtkit_get_max_realtime_priority(impl->system_bus); + *max = pw_rtkit_get_max_realtime_priority(impl); } else { if (min) *min = sched_get_priority_min(REALTIME_POLICY); @@ -782,7 +826,7 @@ static int impl_acquire_rt(void *object, struct spa_thread *thread, int priority if (impl->use_rtkit) { pid = impl_gettid(impl, pt); - rtprio_limit = pw_rtkit_get_max_realtime_priority(impl->system_bus); + rtprio_limit = pw_rtkit_get_max_realtime_priority(impl); if (rtprio_limit >= 0 && rtprio_limit < priority) { pw_log_info("dropping requested priority %d for thread %d down to %d because of RTKit limits", priority, pid, rtprio_limit); priority = rtprio_limit; @@ -795,7 +839,7 @@ static int impl_acquire_rt(void *object, struct spa_thread *thread, int priority pw_log_debug("SCHED_OTHER|SCHED_RESET_ON_FORK worked."); } - if ((err = pw_rtkit_make_realtime(impl->system_bus, pid, priority)) < 0) { + if ((err = pw_rtkit_make_realtime(impl, pid, priority)) < 0) { pw_log_warn("could not make thread %d realtime using RTKit: %s", pid, spa_strerror(err)); return err; } @@ -931,11 +975,31 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) } if (impl->use_rtkit) { - impl->system_bus = pw_rtkit_bus_get_system(); - if (impl->system_bus == NULL) { - res = -errno; - pw_log_warn("could not get system bus: %m"); - goto error; + // Checking xdg-desktop-portal. It works fine in all situations. + impl->rtkit_bus = pw_rtkit_bus_get_session(); + if (impl->rtkit_bus != NULL) { + if (pw_rtkit_check_xdg_portal(impl->rtkit_bus)) { + impl->service_name = XDG_PORTAL_SERVICE_NAME; + impl->object_path = XDG_PORTAL_OBJECT_PATH; + impl->interface = XDG_PORTAL_INTERFACE; + } else { + pw_log_warn("found session bus but no portal"); + pw_rtkit_bus_free(impl->rtkit_bus); + impl->rtkit_bus = NULL; + } + } + // Failed to get xdg-desktop-portal, try to use rtkit. + if (impl->rtkit_bus == NULL) { + impl->rtkit_bus = pw_rtkit_bus_get_system(); + if (impl->rtkit_bus != NULL) { + impl->service_name = RTKIT_SERVICE_NAME; + impl->object_path = RTKIT_OBJECT_PATH; + impl->interface = RTKIT_INTERFACE; + } else { + res = -errno; + pw_log_warn("could not get system bus: %m"); + goto error; + } } } #else @@ -977,8 +1041,8 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) error: #ifdef HAVE_DBUS - if (impl->system_bus) - pw_rtkit_bus_free(impl->system_bus); + if (impl->rtkit_bus) + pw_rtkit_bus_free(impl->rtkit_bus); #endif free(impl); done: