Source/WTF/wtf/PlatformGTK.cmake

@@list(APPEND WTF_SOURCES
3333 glib/GLibUtilities.cpp
3434 glib/GRefPtr.cpp
3535 glib/GSocketMonitor.cpp
 36 glib/RealTimeKit.cpp
3637 glib/RunLoopGLib.cpp
3738 glib/SocketConnection.cpp
3839 glib/URLGLib.cpp

Source/WTF/wtf/PlatformWPE.cmake

@@list(APPEND WTF_SOURCES
2424 glib/GLibUtilities.cpp
2525 glib/GRefPtr.cpp
2626 glib/GSocketMonitor.cpp
 27 glib/RealTimeKit.cpp
2728 glib/RunLoopGLib.cpp
2829 glib/SocketConnection.cpp
2930 glib/URLGLib.cpp

Source/WTF/wtf/Threading.cpp

3939#include <bmalloc/bmalloc.h>
4040#endif
4141
 42#if OS(LINUX)
 43#include <sched.h>
 44#ifndef SCHED_RESET_ON_FORK
 45#define SCHED_RESET_ON_FORK 0x40000000
 46#endif
 47#if USE(GLIB)
 48#include <wtf/glib/RealTimeKit.h>
 49#endif
 50#endif
 51
4252namespace WTF {
4353
4454Lock Thread::s_allThreadsLock;

@@std::atomic<uint32_t> Thread::s_uid { 0 };
7484
7585struct Thread::NewThreadContext : public ThreadSafeRefCounted<NewThreadContext> {
7686public:
77  NewThreadContext(const char* name, Function<void()>&& entryPoint, Ref<Thread>&& thread)
 87 NewThreadContext(const char* name, QOS qos, Function<void()>&& entryPoint, Ref<Thread>&& thread)
7888 : name(name)
 89 , qos(qos)
7990 , entryPoint(WTFMove(entryPoint))
8091 , thread(WTFMove(thread))
8192 {

@@public:
8495 enum class Stage { Start, EstablishedHandle, Initialized };
8596 Stage stage { Stage::Start };
8697 const char* name;
 98 QOS qos;
8799 Function<void()> entryPoint;
88100 Ref<Thread> thread;
89101 Mutex mutex;

@@const char* Thread::normalizeThreadName(const char* threadName)
135147#endif
136148}
137149
138 void Thread::initializeInThread()
 150void Thread::initializeInThread(QOS qos)
139151{
140152 if (m_stack.isEmpty())
141153 m_stack = StackBounds::currentThreadStackBounds();

@@void Thread::initializeInThread()
156168
157169#if OS(LINUX)
158170 m_id = currentID();
 171 if (qos == QOS::UserInteractive)
 172 setCurrentThreadIsUserInteractive();
 173#else
 174 UNUSED_PARAM(qos);
159175#endif
160176}
161177

@@void Thread::entryPoint(NewThreadContext* newThreadContext)
171187
172188 Thread::initializeCurrentThreadInternal(context->name);
173189 function = WTFMove(context->entryPoint);
174  context->thread->initializeInThread();
 190 context->thread->initializeInThread(context->qos);
175191
176192 Thread::initializeTLS(WTFMove(context->thread));
177193

@@Ref<Thread> Thread::create(const char* name, Function<void()>&& entryPoint, Thre
190206{
191207 WTF::initialize();
192208 Ref<Thread> thread = adoptRef(*new Thread());
193  Ref<NewThreadContext> context = adoptRef(*new NewThreadContext { name, WTFMove(entryPoint), thread.copyRef() });
 209 Ref<NewThreadContext> context = adoptRef(*new NewThreadContext { name, qos, WTFMove(entryPoint), thread.copyRef() });
194210 // Increment the context ref on behalf of the created thread. We do not just use a unique_ptr and leak it to the created thread because both the creator and created thread has a need to keep the context alive:
195211 // 1. the created thread needs to keep it alive because Thread::create() can exit before the created thread has a chance to use the context.
196212 // 2. the creator thread (if HAVE(STACK_BOUNDS_FOR_NEW_THREAD) is false) needs to keep it alive because the created thread may exit before the creator has a chance to wake up from waiting for the completion of the created thread's initialization. This waiting uses a condition variable in the context.

@@void Thread::setCurrentThreadIsUserInteractive(int relativePriority)
329345 ASSERT(relativePriority <= 0);
330346 ASSERT(relativePriority >= QOS_MIN_RELATIVE_PRIORITY);
331347 pthread_set_qos_class_self_np(adjustedQOSClass(QOS_CLASS_USER_INTERACTIVE), relativePriority);
 348#elif OS(LINUX)
 349 // We don't allow to make the main thread real time.
 350 if (isMainThread())
 351 return;
 352
 353 struct sched_param param;
 354 param.sched_priority = std::clamp(5 + relativePriority, sched_get_priority_min(SCHED_RR), sched_get_priority_max(SCHED_RR));
 355 auto error = pthread_setschedparam(pthread_self(), SCHED_RR | SCHED_RESET_ON_FORK, &param);
 356#if USE(GLIB)
 357 if (error)
 358 makeThreadRealTime(getpid(), currentID(), param.sched_priority);
 359#else
 360 LOG_ERROR("Failed to set current thread as real time: %s", strerror(error));
 361#endif
332362#else
333363 UNUSED_PARAM(relativePriority);
334364#endif

Source/WTF/wtf/Threading.h

@@public:
257257protected:
258258 Thread();
259259
260  void initializeInThread();
 260 void initializeInThread(QOS);
261261
262262 // Internal platform-specific Thread establishment implementation.
263263 bool establishHandle(NewThreadContext*, std::optional<size_t> stackSize, QOS);

Source/WTF/wtf/generic/WorkQueueGeneric.cpp

@@WorkQueue::WorkQueue(RunLoop& runLoop)
4242{
4343}
4444
45 void WorkQueue::platformInitialize(const char* name, Type, QOS)
 45void WorkQueue::platformInitialize(const char* name, Type, QOS qos)
4646{
4747 BinarySemaphore semaphore;
4848 Thread::create(name, [&] {
4949 m_runLoop = &RunLoop::current();
5050 semaphore.signal();
5151 m_runLoop->run();
52  })->detach();
 52 }, ThreadType::Unknown, qos)->detach();
5353 semaphore.wait();
5454}
5555

Source/WTF/wtf/glib/RealTimeKit.cpp

 1/*
 2 * Copyright (C) 2021 Igalia S.L.
 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

Source/WTF/wtf/glib/RealTimeKit.h

 1/*
 2 * Copyright (C) 2021 Igalia S.L.
 3 *
 4 * This library is free software; you can redistribute it and/or
 5 * modify it under the terms of the GNU Library General Public
 6 * License as published by the Free Software Foundation; either
 7 * version 2 of the License, or (at your option) any later version.
 8 *
 9 * This library is distributed in the hope that it will be useful,
 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 12 * Library General Public License for more details.
 13 *
 14 * You should have received a copy of the GNU Library General Public License
 15 * along with this library; see the file COPYING.LIB. If not, write to
 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 17 * Boston, MA 02110-1301, USA.
 18 */
 19
 20#pragma once
 21
 22namespace WTF {
 23
 24WTF_EXPORT_PRIVATE void makeThreadRealTime(uint64_t processID, uint64_t threadID, uint32_t priority);
 25
 26} // namespace WTF
 27
 28using WTF::makeThreadRealTime;

Source/WTF/wtf/posix/ThreadingPOSIX.cpp

4242#include <wtf/WordLock.h>
4343
4444#if OS(LINUX)
 45#include <sched.h>
4546#include <sys/prctl.h>
 47#include <sys/syscall.h>
 48#ifndef SCHED_RESET_ON_FORK
 49#define SCHED_RESET_ON_FORK 0x40000000
 50#endif
4651#endif
4752
4853#if !COMPILER(MSVC)

6974#include <mach/thread_switch.h>
7075#endif
7176
72 #if OS(LINUX)
73 #include <sys/syscall.h>
74 #endif
75 
7677namespace WTF {
7778
7879static Lock globalSuspendLock;

@@dispatch_qos_class_t Thread::dispatchQOSClass(QOS qos)
260261}
261262#endif
262263
 264#if OS(LINUX)
 265static int schedPolicy(Thread::QOS qos)
 266{
 267 switch (qos) {
 268 case Thread::QOS::UserInteractive:
 269 return SCHED_RR;
 270 case Thread::QOS::UserInitiated:
 271 case Thread::QOS::Default:
 272 return SCHED_OTHER;
 273 case Thread::QOS::Utility:
 274 return SCHED_BATCH;
 275 case Thread::QOS::Background:
 276 return SCHED_IDLE;
 277 }
 278 RELEASE_ASSERT_NOT_REACHED();
 279}
 280#endif
 281
263282bool Thread::establishHandle(NewThreadContext* context, std::optional<size_t> stackSize, QOS qos)
264283{
265284 pthread_t threadHandle;

@@bool Thread::establishHandle(NewThreadContext* context, std::optional<size_t> st
267286 pthread_attr_init(&attr);
268287#if HAVE(QOS_CLASSES)
269288 pthread_attr_set_qos_class_np(&attr, dispatchQOSClass(qos), 0);
270 #else
271  UNUSED_PARAM(qos);
272289#endif
273290 if (stackSize)
274291 pthread_attr_setstacksize(&attr, stackSize.value());

@@bool Thread::establishHandle(NewThreadContext* context, std::optional<size_t> st
278295 LOG_ERROR("Failed to create pthread at entry point %p with context %p", wtfThreadEntryPoint, context);
279296 return false;
280297 }
 298
 299#if OS(LINUX)
 300 int policy = schedPolicy(qos);
 301 if (policy != SCHED_RR) {
 302 // RealTime policy will be handled in Thread::initializeInThread.
 303 struct sched_param param = { 0 };
 304 error = pthread_setschedparam(threadHandle, policy | SCHED_RESET_ON_FORK, &param);
 305 if (error)
 306 LOG_ERROR("Failed to set sched policy %d for thread %d: %s", policy, threadHandle, strerror(error));
 307 }
 308#elif !HAVE(QOS_CLASSES)
 309 UNUSED_PARAM(qos);
 310#endif
 311
281312 establishPlatformSpecificHandle(threadHandle);
282313 return true;
283314}

@@Thread& Thread::initializeCurrentTLS()
354385 WTF::initialize();
355386 Ref<Thread> thread = adoptRef(*new Thread());
356387 thread->establishPlatformSpecificHandle(pthread_self());
357  thread->initializeInThread();
 388 thread->initializeInThread(QOS::Default);
358389 initializeCurrentThreadEvenIfNonWTFCreated();
359390
360391 return initializeTLS(WTFMove(thread));