1/*
2 * Copyright (C) 2020 Jan-Michael Brummer <jan.brummer@tabos.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include <wtf/glib/RealTimeKit.h>
28
29#include <gio/gio.h>
30#include <sys/resource.h>
31#include <sys/time.h>
32#include <wtf/MainThread.h>
33#include <wtf/glib/GRefPtr.h>
34#include <wtf/glib/GUniquePtr.h>
35
36namespace WTF {
37
38static int64_t realTimeKitGetProperty(GDBusProxy* proxy, const char* propertyName, GError** error)
39{
40 GRefPtr<GVariant> result = adoptGRef(g_dbus_proxy_call_sync(proxy, "org.freedesktop.DBus.Properties.Get",
41 g_variant_new("(ss)", "org.freedesktop.RealtimeKit1", propertyName), G_DBUS_CALL_FLAGS_NONE, -1, nullptr, error));
42 if (!result)
43 return -1;
44
45 GRefPtr<GVariant> property;
46 g_variant_get(result.get(), "(v)", &property.outPtr());
47 if (g_variant_is_of_type(property.get(), G_VARIANT_TYPE_INT64))
48 return g_variant_get_int64(property.get());
49 if (g_variant_is_of_type(property.get(), G_VARIANT_TYPE_INT32))
50 return g_variant_get_int32(property.get());
51 RELEASE_ASSERT_NOT_REACHED();
52}
53
54void makeThreadRealTime(uint64_t processID, uint64_t threadID, uint32_t priority)
55{
56 ASSERT(!isMainThread());
57 GUniqueOutPtr<GError> error;
58 GRefPtr<GDBusProxy> proxy = adoptGRef(g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
59 static_cast<GDBusProxyFlags>(G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES), nullptr,
60 "org.freedesktop.RealtimeKit1", "/org/freedesktop/RealtimeKit1", "org.freedesktop.RealtimeKit1", nullptr, &error.outPtr()));
61 if (!proxy) {
62 LOG_ERROR("Failed to connect to RealtimeKit: %s", error->message);
63 return;
64 }
65
66#ifdef RLIMIT_RTTIME
67 // RealTimeKit requires the client to have RLIMIT_RTTIME set.
68 auto rttimeMax = realTimeKitGetProperty(proxy.get(), "RTTimeUSecMax", &error.outPtr());
69 if (error) {
70 LOG_ERROR("Failed to get RTTimeUSecMax from RealtimeKit: %s", error->message);
71 return;
72 }
73
74 struct rlimit rl;
75 if (getrlimit(RLIMIT_RTTIME, &rl) >= 0 && rl.rlim_max > static_cast<uint64_t>(rttimeMax)) {
76 rl.rlim_cur = rl.rlim_max = rttimeMax;
77 setrlimit(RLIMIT_RTTIME, &rl);
78 }
79#endif
80
81 GRefPtr<GVariant> result = adoptGRef(g_dbus_proxy_call_sync(proxy.get(), "MakeThreadRealtimeWithPID",
82 g_variant_new("(ttu)", processID, threadID, priority), G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &error.outPtr()));
83 if (!result)
84 LOG_ERROR("Failed to make thread real time: %s", error->message);
85}
86
87} // namespace WTF