diff options
author | Chris Robinson <[email protected]> | 2021-04-18 00:34:36 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2021-04-18 00:43:01 -0700 |
commit | 5165b29b1945e1cff5e8c042bd371a5b2da9b492 (patch) | |
tree | 686d5edf04f9b33ca65ec3cf16c2bf536c73400a /core/rtkit.cpp | |
parent | 784dbd7d21f36b0dbf034e7ac5d46cdc5533b91b (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.cpp | 240 |
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 |