aboutsummaryrefslogtreecommitdiffstats
path: root/core/rtkit.cpp
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2021-04-18 00:34:36 -0700
committerChris Robinson <[email protected]>2021-04-18 00:43:01 -0700
commit5165b29b1945e1cff5e8c042bd371a5b2da9b492 (patch)
tree686d5edf04f9b33ca65ec3cf16c2bf536c73400a /core/rtkit.cpp
parent784dbd7d21f36b0dbf034e7ac5d46cdc5533b91b (diff)
Optionally use RTKit/D-Bus to set elevated priority
If pthread_setschedparam fails or is unavailable.
Diffstat (limited to 'core/rtkit.cpp')
-rw-r--r--core/rtkit.cpp240
1 files changed, 240 insertions, 0 deletions
diff --git a/core/rtkit.cpp b/core/rtkit.cpp
new file mode 100644
index 00000000..8b489e71
--- /dev/null
+++ b/core/rtkit.cpp
@@ -0,0 +1,240 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+ Copyright 2009 Lennart Poettering
+ Copyright 2010 David Henningsson <[email protected]>
+ Copyright 2021 Chris Robinson
+
+ 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 "rtkit.h"
+
+#include <errno.h>
+
+#ifdef __linux__
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <memory>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+
+
+namespace dbus {
+ constexpr int TypeString{'s'};
+ constexpr int TypeVariant{'v'};
+ constexpr int TypeInt32{'i'};
+ constexpr int TypeUInt32{'u'};
+ constexpr int TypeInt64{'x'};
+ constexpr int TypeUInt64{'t'};
+ constexpr int TypeInvalid{'\0'};
+
+ struct MessageDeleter {
+ void operator()(DBusMessage *m) { (*pdbus_message_unref)(m); }
+ };
+ using MessagePtr = std::unique_ptr<DBusMessage,MessageDeleter>;
+} // namespace dbus
+
+namespace {
+
+inline pid_t _gettid()
+{ return static_cast<pid_t>(syscall(SYS_gettid)); }
+
+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;
+}
+
+int rtkit_get_int_property(DBusConnection *connection, const char *propname, long long *propval)
+{
+ dbus::MessagePtr m{(*pdbus_message_new_method_call)(RTKIT_SERVICE_NAME, RTKIT_OBJECT_PATH,
+ "org.freedesktop.DBus.Properties", "Get")};
+ if(!m) return -ENOMEM;
+
+ const char *interfacestr = RTKIT_SERVICE_NAME;
+ auto ready = (*pdbus_message_append_args)(m.get(),
+ dbus::TypeString, &interfacestr,
+ dbus::TypeString, &propname,
+ dbus::TypeInvalid);
+ if(!ready) return -ENOMEM;
+
+ dbus::Error error;
+ dbus::MessagePtr r{(*pdbus_connection_send_with_reply_and_block)(connection, m.get(), -1,
+ &error.get())};
+ if(!r) return translate_error(error->name);
+
+ if((*pdbus_set_error_from_message)(&error.get(), r.get()))
+ return translate_error(error->name);
+
+ int ret{-EBADMSG};
+ DBusMessageIter iter{};
+ (*pdbus_message_iter_init)(r.get(), &iter);
+ while(int curtype{(*pdbus_message_iter_get_arg_type)(&iter)})
+ {
+ if(curtype == dbus::TypeVariant)
+ {
+ DBusMessageIter subiter{};
+ (*pdbus_message_iter_recurse)(&iter, &subiter);
+
+ while((curtype=(*pdbus_message_iter_get_arg_type)(&subiter)) != dbus::TypeInvalid)
+ {
+ if(curtype == dbus::TypeInt32)
+ {
+ dbus_int32_t i32{};
+ (*pdbus_message_iter_get_basic)(&subiter, &i32);
+ *propval = i32;
+ ret = 0;
+ }
+
+ if(curtype == dbus::TypeInt64)
+ {
+ dbus_int64_t i64{};
+ (*pdbus_message_iter_get_basic)(&subiter, &i64);
+ *propval = i64;
+ ret = 0;
+ }
+
+ (*pdbus_message_iter_next)(&subiter);
+ }
+ }
+ (*pdbus_message_iter_next)(&iter);
+ }
+
+ return ret;
+}
+
+} // namespace
+
+extern "C" {
+int rtkit_get_max_realtime_priority(DBusConnection *connection)
+{
+ long long retval{};
+ int err{rtkit_get_int_property(connection, "MaxRealtimePriority", &retval)};
+ return err < 0 ? err : static_cast<int>(retval);
+}
+
+int rtkit_get_min_nice_level(DBusConnection *connection, int *min_nice_level)
+{
+ long long retval{};
+ int err{rtkit_get_int_property(connection, "MinNiceLevel", &retval)};
+ if(err >= 0) *min_nice_level = static_cast<int>(retval);
+ return err;
+}
+
+long long rtkit_get_rttime_usec_max(DBusConnection *connection)
+{
+ long long retval{};
+ int err{rtkit_get_int_property(connection, "RTTimeUSecMax", &retval)};
+ return err < 0 ? err : retval;
+}
+
+int rtkit_make_realtime(DBusConnection *connection, pid_t thread, int priority)
+{
+ if(thread == 0)
+ thread = _gettid();
+
+ dbus::MessagePtr m{(*pdbus_message_new_method_call)(RTKIT_SERVICE_NAME, RTKIT_OBJECT_PATH,
+ "org.freedesktop.RealtimeKit1", "MakeThreadRealtime")};
+ if(!m) return -ENOMEM;
+
+ auto u64 = static_cast<dbus_uint64_t>(thread);
+ auto u32 = static_cast<dbus_uint32_t>(priority);
+ auto ready = (*pdbus_message_append_args)(m.get(),
+ dbus::TypeUInt64, &u64,
+ dbus::TypeUInt32, &u32,
+ dbus::TypeInvalid);
+ if(!ready) return -ENOMEM;
+
+ dbus::Error error;
+ dbus::MessagePtr r{(*pdbus_connection_send_with_reply_and_block)(connection, m.get(), -1,
+ &error.get())};
+ if(!r) return translate_error(error->name);
+
+ if((*pdbus_set_error_from_message)(&error.get(), r.get()))
+ return translate_error(error->name);
+
+ return 0;
+}
+
+int rtkit_make_high_priority(DBusConnection *connection, pid_t thread, int nice_level)
+{
+ if(thread == 0)
+ thread = _gettid();
+
+ dbus::MessagePtr m{(*pdbus_message_new_method_call)(RTKIT_SERVICE_NAME, RTKIT_OBJECT_PATH,
+ "org.freedesktop.RealtimeKit1", "MakeThreadHighPriority")};
+ if(!m) return -ENOMEM;
+
+ auto u64 = static_cast<dbus_uint64_t>(thread);
+ auto s32 = static_cast<dbus_int32_t>(nice_level);
+ auto ready = (*pdbus_message_append_args)(m.get(),
+ dbus::TypeUInt64, &u64,
+ dbus::TypeInt32, &s32,
+ dbus::TypeInvalid);
+ if(!ready) return -ENOMEM;
+
+ dbus::Error error;
+ dbus::MessagePtr r{(*pdbus_connection_send_with_reply_and_block)(connection, m.get(), -1,
+ &error.get())};
+ if(!r) return translate_error(error->name);
+
+ if((*pdbus_set_error_from_message)(&error.get(), r.get()))
+ return translate_error(error->name);
+
+ return 0;
+}
+} // extern "C"
+
+#else
+
+extern "C" {
+int rtkit_make_realtime(DBusConnection *connection, pid_t thread, int priority)
+{ return -ENOTSUP; }
+
+int rtkit_make_high_priority(DBusConnection *connection, pid_t thread, int nice_level)
+{ return -ENOTSUP; }
+
+int rtkit_get_max_realtime_priority(DBusConnection *connection)
+{ return -ENOTSUP; }
+
+int rtkit_get_min_nice_level(DBusConnection *connection, int *min_nice_level)
+{ return -ENOTSUP; }
+
+long long rtkit_get_rttime_usec_max(DBusConnection *connection)
+{ return -ENOTSUP; }
+} // extern "C"
+
+#endif