]> git.tdb.fi Git - ext/openal.git/blob - core/rtkit.cpp
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / core / rtkit.cpp
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 /***
4         Copyright 2009 Lennart Poettering
5         Copyright 2010 David Henningsson <diwic@ubuntu.com>
6         Copyright 2021 Chris Robinson
7
8         Permission is hereby granted, free of charge, to any person
9         obtaining a copy of this software and associated documentation files
10         (the "Software"), to deal in the Software without restriction,
11         including without limitation the rights to use, copy, modify, merge,
12         publish, distribute, sublicense, and/or sell copies of the Software,
13         and to permit persons to whom the Software is furnished to do so,
14         subject to the following conditions:
15
16         The above copyright notice and this permission notice shall be
17         included in all copies or substantial portions of the Software.
18
19         THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20         EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21         MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22         NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23         BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24         ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25         CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26         SOFTWARE.
27 ***/
28
29 #include "config.h"
30
31 #include "rtkit.h"
32
33 #include <errno.h>
34
35 #ifndef _GNU_SOURCE
36 #define _GNU_SOURCE
37 #endif
38
39 #include <memory>
40 #include <string.h>
41 #include <unistd.h>
42 #include <sys/types.h>
43 #ifdef __linux__
44 #include <sys/syscall.h>
45 #elif defined(__FreeBSD__)
46 #include <sys/thr.h>
47 #endif
48
49
50 namespace dbus {
51
52 constexpr int TypeString{'s'};
53 constexpr int TypeVariant{'v'};
54 constexpr int TypeInt32{'i'};
55 constexpr int TypeUInt32{'u'};
56 constexpr int TypeInt64{'x'};
57 constexpr int TypeUInt64{'t'};
58 constexpr int TypeInvalid{'\0'};
59
60 struct MessageDeleter {
61     void operator()(DBusMessage *m) { dbus_message_unref(m); }
62 };
63 using MessagePtr = std::unique_ptr<DBusMessage,MessageDeleter>;
64
65 } // namespace dbus
66
67 namespace {
68
69 inline pid_t _gettid()
70 {
71 #ifdef __linux__
72     return static_cast<pid_t>(syscall(SYS_gettid));
73 #elif defined(__FreeBSD__)
74     long pid{};
75     thr_self(&pid);
76     return static_cast<pid_t>(pid);
77 #else
78 #warning gettid not available
79     return 0;
80 #endif
81 }
82
83 int translate_error(const char *name)
84 {
85     if(strcmp(name, DBUS_ERROR_NO_MEMORY) == 0)
86         return -ENOMEM;
87     if(strcmp(name, DBUS_ERROR_SERVICE_UNKNOWN) == 0
88         || strcmp(name, DBUS_ERROR_NAME_HAS_NO_OWNER) == 0)
89         return -ENOENT;
90     if(strcmp(name, DBUS_ERROR_ACCESS_DENIED) == 0
91         || strcmp(name, DBUS_ERROR_AUTH_FAILED) == 0)
92         return -EACCES;
93     return -EIO;
94 }
95
96 int rtkit_get_int_property(DBusConnection *connection, const char *propname, long long *propval)
97 {
98     dbus::MessagePtr m{dbus_message_new_method_call(RTKIT_SERVICE_NAME, RTKIT_OBJECT_PATH,
99         "org.freedesktop.DBus.Properties", "Get")};
100     if(!m) return -ENOMEM;
101
102     const char *interfacestr = RTKIT_SERVICE_NAME;
103     auto ready = dbus_message_append_args(m.get(),
104         dbus::TypeString, &interfacestr,
105         dbus::TypeString, &propname,
106         dbus::TypeInvalid);
107     if(!ready) return -ENOMEM;
108
109     dbus::Error error;
110     dbus::MessagePtr r{dbus_connection_send_with_reply_and_block(connection, m.get(), -1,
111         &error.get())};
112     if(!r) return translate_error(error->name);
113
114     if(dbus_set_error_from_message(&error.get(), r.get()))
115         return translate_error(error->name);
116
117     int ret{-EBADMSG};
118     DBusMessageIter iter{};
119     dbus_message_iter_init(r.get(), &iter);
120     while(int curtype{dbus_message_iter_get_arg_type(&iter)})
121     {
122         if(curtype == dbus::TypeVariant)
123         {
124             DBusMessageIter subiter{};
125             dbus_message_iter_recurse(&iter, &subiter);
126
127             while((curtype=dbus_message_iter_get_arg_type(&subiter)) != dbus::TypeInvalid)
128             {
129                 if(curtype == dbus::TypeInt32)
130                 {
131                     dbus_int32_t i32{};
132                     dbus_message_iter_get_basic(&subiter, &i32);
133                     *propval = i32;
134                     ret = 0;
135                 }
136
137                 if(curtype == dbus::TypeInt64)
138                 {
139                     dbus_int64_t i64{};
140                     dbus_message_iter_get_basic(&subiter, &i64);
141                     *propval = i64;
142                     ret = 0;
143                 }
144
145                 dbus_message_iter_next(&subiter);
146             }
147         }
148         dbus_message_iter_next(&iter);
149     }
150
151     return ret;
152 }
153
154 } // namespace
155
156 int rtkit_get_max_realtime_priority(DBusConnection *connection)
157 {
158     long long retval{};
159     int err{rtkit_get_int_property(connection, "MaxRealtimePriority", &retval)};
160     return err < 0 ? err : static_cast<int>(retval);
161 }
162
163 int rtkit_get_min_nice_level(DBusConnection *connection, int *min_nice_level)
164 {
165     long long retval{};
166     int err{rtkit_get_int_property(connection, "MinNiceLevel", &retval)};
167     if(err >= 0) *min_nice_level = static_cast<int>(retval);
168     return err;
169 }
170
171 long long rtkit_get_rttime_usec_max(DBusConnection *connection)
172 {
173     long long retval{};
174     int err{rtkit_get_int_property(connection, "RTTimeUSecMax", &retval)};
175     return err < 0 ? err : retval;
176 }
177
178 int rtkit_make_realtime(DBusConnection *connection, pid_t thread, int priority)
179 {
180     if(thread == 0)
181         thread = _gettid();
182     if(thread == 0)
183         return -ENOTSUP;
184
185     dbus::MessagePtr m{dbus_message_new_method_call(RTKIT_SERVICE_NAME, RTKIT_OBJECT_PATH,
186         "org.freedesktop.RealtimeKit1", "MakeThreadRealtime")};
187     if(!m) return -ENOMEM;
188
189     auto u64 = static_cast<dbus_uint64_t>(thread);
190     auto u32 = static_cast<dbus_uint32_t>(priority);
191     auto ready = dbus_message_append_args(m.get(),
192         dbus::TypeUInt64, &u64,
193         dbus::TypeUInt32, &u32,
194         dbus::TypeInvalid);
195     if(!ready) return -ENOMEM;
196
197     dbus::Error error;
198     dbus::MessagePtr r{dbus_connection_send_with_reply_and_block(connection, m.get(), -1,
199         &error.get())};
200     if(!r) return translate_error(error->name);
201
202     if(dbus_set_error_from_message(&error.get(), r.get()))
203         return translate_error(error->name);
204
205     return 0;
206 }
207
208 int rtkit_make_high_priority(DBusConnection *connection, pid_t thread, int nice_level)
209 {
210     if(thread == 0)
211         thread = _gettid();
212     if(thread == 0)
213         return -ENOTSUP;
214
215     dbus::MessagePtr m{dbus_message_new_method_call(RTKIT_SERVICE_NAME, RTKIT_OBJECT_PATH,
216         "org.freedesktop.RealtimeKit1", "MakeThreadHighPriority")};
217     if(!m) return -ENOMEM;
218
219     auto u64 = static_cast<dbus_uint64_t>(thread);
220     auto s32 = static_cast<dbus_int32_t>(nice_level);
221     auto ready = dbus_message_append_args(m.get(),
222         dbus::TypeUInt64, &u64,
223         dbus::TypeInt32, &s32,
224         dbus::TypeInvalid);
225     if(!ready) return -ENOMEM;
226
227     dbus::Error error;
228     dbus::MessagePtr r{dbus_connection_send_with_reply_and_block(connection, m.get(), -1,
229         &error.get())};
230     if(!r) return translate_error(error->name);
231
232     if(dbus_set_error_from_message(&error.get(), r.get()))
233         return translate_error(error->name);
234
235     return 0;
236 }