aboutsummaryrefslogtreecommitdiffstats
path: root/core/rtkit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/rtkit.cpp')
-rw-r--r--core/rtkit.cpp236
1 files changed, 236 insertions, 0 deletions
diff --git a/core/rtkit.cpp b/core/rtkit.cpp
new file mode 100644
index 00000000..ff944ebf
--- /dev/null
+++ b/core/rtkit.cpp
@@ -0,0 +1,236 @@
+/*-*- 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>
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <memory>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#ifdef __linux__
+#include <sys/syscall.h>
+#elif defined(__FreeBSD__)
+#include <sys/thr.h>
+#endif
+
+
+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) { dbus_message_unref(m); }
+};
+using MessagePtr = std::unique_ptr<DBusMessage,MessageDeleter>;
+
+} // namespace dbus
+
+namespace {
+
+inline pid_t _gettid()
+{
+#ifdef __linux__
+ return static_cast<pid_t>(syscall(SYS_gettid));
+#elif defined(__FreeBSD__)
+ long pid{};
+ thr_self(&pid);
+ return static_cast<pid_t>(pid);
+#else
+#warning gettid not available
+ return 0;
+#endif
+}
+
+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{dbus_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 = dbus_message_append_args(m.get(),
+ dbus::TypeString, &interfacestr,
+ dbus::TypeString, &propname,
+ dbus::TypeInvalid);
+ if(!ready) return -ENOMEM;
+
+ dbus::Error error;
+ dbus::MessagePtr r{dbus_connection_send_with_reply_and_block(connection, m.get(), -1,
+ &error.get())};
+ if(!r) return translate_error(error->name);
+
+ if(dbus_set_error_from_message(&error.get(), r.get()))
+ return translate_error(error->name);
+
+ int ret{-EBADMSG};
+ DBusMessageIter iter{};
+ dbus_message_iter_init(r.get(), &iter);
+ while(int curtype{dbus_message_iter_get_arg_type(&iter)})
+ {
+ if(curtype == dbus::TypeVariant)
+ {
+ DBusMessageIter subiter{};
+ dbus_message_iter_recurse(&iter, &subiter);
+
+ while((curtype=dbus_message_iter_get_arg_type(&subiter)) != dbus::TypeInvalid)
+ {
+ if(curtype == dbus::TypeInt32)
+ {
+ dbus_int32_t i32{};
+ dbus_message_iter_get_basic(&subiter, &i32);
+ *propval = i32;
+ ret = 0;
+ }
+
+ if(curtype == dbus::TypeInt64)
+ {
+ dbus_int64_t i64{};
+ dbus_message_iter_get_basic(&subiter, &i64);
+ *propval = i64;
+ ret = 0;
+ }
+
+ dbus_message_iter_next(&subiter);
+ }
+ }
+ dbus_message_iter_next(&iter);
+ }
+
+ return ret;
+}
+
+} // namespace
+
+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();
+ if(thread == 0)
+ return -ENOTSUP;
+
+ dbus::MessagePtr m{dbus_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 = dbus_message_append_args(m.get(),
+ dbus::TypeUInt64, &u64,
+ dbus::TypeUInt32, &u32,
+ dbus::TypeInvalid);
+ if(!ready) return -ENOMEM;
+
+ dbus::Error error;
+ dbus::MessagePtr r{dbus_connection_send_with_reply_and_block(connection, m.get(), -1,
+ &error.get())};
+ if(!r) return translate_error(error->name);
+
+ if(dbus_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();
+ if(thread == 0)
+ return -ENOTSUP;
+
+ dbus::MessagePtr m{dbus_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 = dbus_message_append_args(m.get(),
+ dbus::TypeUInt64, &u64,
+ dbus::TypeInt32, &s32,
+ dbus::TypeInvalid);
+ if(!ready) return -ENOMEM;
+
+ dbus::Error error;
+ dbus::MessagePtr r{dbus_connection_send_with_reply_and_block(connection, m.get(), -1,
+ &error.get())};
+ if(!r) return translate_error(error->name);
+
+ if(dbus_set_error_from_message(&error.get(), r.get()))
+ return translate_error(error->name);
+
+ return 0;
+}