|
|
- /*-*- Mode: C; c-basic-offset: 8 -*-*/
-
- /***
- Copyright 2009 Lennart Poettering
- Copyright 2010 David Henningsson <diwic@ubuntu.com>
- 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>
- #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) { 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;
- }
|