Title: [271560] trunk/Source
Revision
271560
Author
[email protected]
Date
2021-01-17 00:50:49 -0800 (Sun, 17 Jan 2021)

Log Message

Add JSC API configuring GC signals in Linux
https://bugs.webkit.org/show_bug.cgi?id=220641

Reviewed by Mark Lam.

Source/_javascript_Core:

Add JSConfigureSignalForGC function for Linux and FreeBSD (non Apple, non Windows platforms).

* API/JSBase.cpp:
(JSConfigureSignalForGC):
* API/JSBasePrivate.h:

Source/WTF:

In Linux and FreeBSD, we need to use signals to suspend and resume threads.
By default, we are using SIGUSR1, but it is possible that some embedders want to use
the other signals since they are using SIGUSR1 already. To work-around that, this
patch offers the way for embedders to configure signals.

* wtf/Threading.h:
* wtf/WTFConfig.h:
* wtf/posix/ThreadingPOSIX.cpp:
(WTF::Thread::signalHandlerSuspendResume):
(WTF::Thread::initializePlatformThreading):
(WTF::Thread::initializeCurrentThreadEvenIfNonWTFCreated):
(WTF::Thread::initializeCurrentTLS):
(WTF::Thread::suspend):
(WTF::Thread::resume):
* wtf/threads/Signals.cpp:
(WTF::addSignalHandler):
* wtf/win/ThreadingWin.cpp:
(WTF::Thread::initializeCurrentTLS):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/API/JSBase.cpp (271559 => 271560)


--- trunk/Source/_javascript_Core/API/JSBase.cpp	2021-01-17 00:26:19 UTC (rev 271559)
+++ trunk/Source/_javascript_Core/API/JSBase.cpp	2021-01-17 08:50:49 UTC (rev 271560)
@@ -182,6 +182,17 @@
     GCActivityCallback::s_shouldCreateGCTimer = false;
 }
 
+#if !OS(DARWIN) && !OS(WINDOWS)
+bool JSConfigureSignalForGC(int signal)
+{
+    if (g_wtfConfig.isThreadSuspendResumeSignalConfigured)
+        return false;
+    g_wtfConfig.sigThreadSuspendResume = signal;
+    g_wtfConfig.isUserSpecifiedThreadSuspendResumeSignalConfigured = true;
+    return true;
+}
+#endif
+
 JSObjectRef JSGetMemoryUsageStatistics(JSContextRef ctx)
 {
     if (!ctx) {

Modified: trunk/Source/_javascript_Core/API/JSBasePrivate.h (271559 => 271560)


--- trunk/Source/_javascript_Core/API/JSBasePrivate.h	2021-01-17 00:26:19 UTC (rev 271559)
+++ trunk/Source/_javascript_Core/API/JSBasePrivate.h	2021-01-17 08:50:49 UTC (rev 271560)
@@ -47,7 +47,18 @@
 
 JS_EXPORT void JSDisableGCTimer(void);
 
+#if !defined(__APPLE__) && !defined(WIN32) && !defined(_WIN32)
 /*!
+@function JSConfigureSignalForGC
+@abstract Configure signals for GC in non-Apple and non-Windows platforms.
+@param signal The signal number to use.
+@result true if the signal is successfully configured, otherwise false.
+@discussion Call this function before any of JSC initialization starts. Otherwise, it fails.
+*/
+JS_EXPORT bool JSConfigureSignalForGC(int signal);
+#endif
+
+/*!
 @function
 @abstract Produces an object with various statistics about current memory usage.
 @param ctx The execution context to use.

Modified: trunk/Source/_javascript_Core/ChangeLog (271559 => 271560)


--- trunk/Source/_javascript_Core/ChangeLog	2021-01-17 00:26:19 UTC (rev 271559)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-01-17 08:50:49 UTC (rev 271560)
@@ -1,3 +1,16 @@
+2021-01-17  Yusuke Suzuki  <[email protected]>
+
+        Add JSC API configuring GC signals in Linux
+        https://bugs.webkit.org/show_bug.cgi?id=220641
+
+        Reviewed by Mark Lam.
+
+        Add JSConfigureSignalForGC function for Linux and FreeBSD (non Apple, non Windows platforms).
+
+        * API/JSBase.cpp:
+        (JSConfigureSignalForGC):
+        * API/JSBasePrivate.h:
+
 2021-01-15  Alexey Proskuryakov  <[email protected]>
 
         Build fixes with newer clang

Modified: trunk/Source/WTF/ChangeLog (271559 => 271560)


--- trunk/Source/WTF/ChangeLog	2021-01-17 00:26:19 UTC (rev 271559)
+++ trunk/Source/WTF/ChangeLog	2021-01-17 08:50:49 UTC (rev 271560)
@@ -1,3 +1,29 @@
+2021-01-17  Yusuke Suzuki  <[email protected]>
+
+        Add JSC API configuring GC signals in Linux
+        https://bugs.webkit.org/show_bug.cgi?id=220641
+
+        Reviewed by Mark Lam.
+
+        In Linux and FreeBSD, we need to use signals to suspend and resume threads.
+        By default, we are using SIGUSR1, but it is possible that some embedders want to use
+        the other signals since they are using SIGUSR1 already. To work-around that, this
+        patch offers the way for embedders to configure signals.
+
+        * wtf/Threading.h:
+        * wtf/WTFConfig.h:
+        * wtf/posix/ThreadingPOSIX.cpp:
+        (WTF::Thread::signalHandlerSuspendResume):
+        (WTF::Thread::initializePlatformThreading):
+        (WTF::Thread::initializeCurrentThreadEvenIfNonWTFCreated):
+        (WTF::Thread::initializeCurrentTLS):
+        (WTF::Thread::suspend):
+        (WTF::Thread::resume):
+        * wtf/threads/Signals.cpp:
+        (WTF::addSignalHandler):
+        * wtf/win/ThreadingWin.cpp:
+        (WTF::Thread::initializeCurrentTLS):
+
 2021-01-15  Chris Dumez  <[email protected]>
 
         [GPUProcess] Move DOM / Canvas rendering off the main thread in the GPUProcess

Modified: trunk/Source/WTF/wtf/Threading.h (271559 => 271560)


--- trunk/Source/WTF/wtf/Threading.h	2021-01-17 00:26:19 UTC (rev 271559)
+++ trunk/Source/WTF/wtf/Threading.h	2021-01-17 08:50:49 UTC (rev 271560)
@@ -72,13 +72,6 @@
 
 WTF_EXPORT_PRIVATE void initialize();
 
-#if USE(PTHREADS)
-
-// We use SIGUSR1 to suspend and resume machine threads in _javascript_Core.
-constexpr const int SigThreadSuspendResume = SIGUSR1;
-
-#endif
-
 enum class GCThreadType : uint8_t {
     None = 0,
     Main,

Modified: trunk/Source/WTF/wtf/WTFConfig.h (271559 => 271560)


--- trunk/Source/WTF/wtf/WTFConfig.h	2021-01-17 00:26:19 UTC (rev 271559)
+++ trunk/Source/WTF/wtf/WTFConfig.h	2021-01-17 08:50:49 UTC (rev 271560)
@@ -70,6 +70,11 @@
 
     bool isPermanentlyFrozen;
 
+#if USE(PTHREADS)
+    bool isUserSpecifiedThreadSuspendResumeSignalConfigured;
+    bool isThreadSuspendResumeSignalConfigured;
+    int sigThreadSuspendResume;
+#endif
 #if OS(UNIX)
     SignalHandlers signalHandlers;
 #endif

Modified: trunk/Source/WTF/wtf/posix/ThreadingPOSIX.cpp (271559 => 271560)


--- trunk/Source/WTF/wtf/posix/ThreadingPOSIX.cpp	2021-01-17 00:26:19 UTC (rev 271559)
+++ trunk/Source/WTF/wtf/posix/ThreadingPOSIX.cpp	2021-01-17 08:50:49 UTC (rev 271560)
@@ -38,6 +38,7 @@
 #include <wtf/NeverDestroyed.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/ThreadingPrimitives.h>
+#include <wtf/WTFConfig.h>
 #include <wtf/WordLock.h>
 
 #if OS(LINUX)
@@ -158,11 +159,11 @@
     // http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_11
     globalSemaphoreForSuspendResume->post();
 
-    // Reaching here, SigThreadSuspendResume is blocked in this handler (this is configured by sigaction's sa_mask).
-    // So before calling sigsuspend, SigThreadSuspendResume to this thread is deferred. This ensures that the handler is not executed recursively.
+    // Reaching here, sigThreadSuspendResume is blocked in this handler (this is configured by sigaction's sa_mask).
+    // So before calling sigsuspend, sigThreadSuspendResume to this thread is deferred. This ensures that the handler is not executed recursively.
     sigset_t blockedSignalSet;
     sigfillset(&blockedSignalSet);
-    sigdelset(&blockedSignalSet, SigThreadSuspendResume);
+    sigdelset(&blockedSignalSet, g_wtfConfig.sigThreadSuspendResume);
     sigsuspend(&blockedSignalSet);
 
     thread->m_platformRegisters = nullptr;
@@ -175,19 +176,39 @@
 
 void Thread::initializePlatformThreading()
 {
+    if (!g_wtfConfig.isUserSpecifiedThreadSuspendResumeSignalConfigured)
+        g_wtfConfig.sigThreadSuspendResume = SIGUSR1;
+    g_wtfConfig.isThreadSuspendResumeSignalConfigured = true;
+
 #if !OS(DARWIN)
     globalSemaphoreForSuspendResume.construct(0);
 
     // Signal handlers are process global configuration.
-    // Intentionally block SigThreadSuspendResume in the handler.
-    // SigThreadSuspendResume will be allowed in the handler by sigsuspend.
-    struct sigaction action;
-    sigemptyset(&action.sa_mask);
-    sigaddset(&action.sa_mask, SigThreadSuspendResume);
+    // Intentionally block sigThreadSuspendResume in the handler.
+    // sigThreadSuspendResume will be allowed in the handler by sigsuspend.
+    auto attemptToSetSignal = [](int signal) -> bool {
+        struct sigaction action;
+        sigemptyset(&action.sa_mask);
+        sigaddset(&action.sa_mask, signal);
 
-    action.sa_sigaction = &signalHandlerSuspendResume;
-    action.sa_flags = SA_RESTART | SA_SIGINFO;
-    sigaction(SigThreadSuspendResume, &action, 0);
+        action.sa_sigaction = &signalHandlerSuspendResume;
+        action.sa_flags = SA_RESTART | SA_SIGINFO;
+
+        // Theoretically, this can have race conditions but currently, there is no way to deal with it,
+        // plus, we do not expect that this initialization is executed concurrently with the other
+        // initialization which also installs specific signals. If this is the problem, applications should
+        // change how to initialize things.
+        struct sigaction oldAction;
+        if (sigaction(signal, nullptr, &oldAction))
+            return false;
+        // It has signal already.
+        if (oldAction.sa_handler != SIG_DFL || bitwise_cast<void*>(oldAction.sa_sigaction) != bitwise_cast<void*>(SIG_DFL))
+            return false;
+        return !sigaction(signal, &action, 0);
+    };
+
+    bool signalIsInstalled = attemptToSetSignal(g_wtfConfig.sigThreadSuspendResume);
+    RELEASE_ASSERT(signalIsInstalled);
 #endif
 }
 
@@ -201,9 +222,10 @@
 void Thread::initializeCurrentThreadEvenIfNonWTFCreated()
 {
 #if !OS(DARWIN)
+    RELEASE_ASSERT(g_wtfConfig.isThreadSuspendResumeSignalConfigured);
     sigset_t mask;
     sigemptyset(&mask);
-    sigaddset(&mask, SigThreadSuspendResume);
+    sigaddset(&mask, g_wtfConfig.sigThreadSuspendResume);
     pthread_sigmask(SIG_UNBLOCK, &mask, 0);
 #endif
 }
@@ -323,6 +345,7 @@
 Thread& Thread::initializeCurrentTLS()
 {
     // Not a WTF-created thread, Thread is not established yet.
+    WTF::initialize();
     Ref<Thread> thread = adoptRef(*new Thread());
     thread->establishPlatformSpecificHandle(pthread_self());
     thread->initializeInThread();
@@ -362,13 +385,11 @@
     return { };
 #else
     if (!m_suspendCount) {
-        // Ideally, we would like to use pthread_sigqueue. It allows us to pass the argument to the signal handler.
-        // But it can be used in a few platforms, like Linux.
-        // Instead, we use Thread* stored in a global variable to pass it to the signal handler.
         targetThread.store(this);
 
         while (true) {
-            int result = pthread_kill(m_handle, SigThreadSuspendResume);
+            // We must use pthread_kill to avoid queue-overflow problem with real-time signals.
+            int result = pthread_kill(m_handle, g_wtfConfig.sigThreadSuspendResume);
             if (result)
                 return makeUnexpected(result);
             globalSemaphoreForSuspendResume->wait();
@@ -392,15 +413,16 @@
     thread_resume(m_platformThread);
 #else
     if (m_suspendCount == 1) {
-        // When allowing SigThreadSuspendResume interrupt in the signal handler by sigsuspend and SigThreadSuspendResume is actually issued,
+        // When allowing sigThreadSuspendResume interrupt in the signal handler by sigsuspend and SigThreadSuspendResume is actually issued,
         // the signal handler itself will be called once again.
         // There are several ways to distinguish the handler invocation for suspend and resume.
         // 1. Use different signal numbers. And check the signal number in the handler.
-        // 2. Use some arguments to distinguish suspend and resume in the handler. If pthread_sigqueue can be used, we can take this.
+        // 2. Use some arguments to distinguish suspend and resume in the handler.
         // 3. Use thread's flag.
         // In this implementaiton, we take (3). m_suspendCount is used to distinguish it.
+        // Note that we must use pthread_kill to avoid queue-overflow problem with real-time signals.
         targetThread.store(this);
-        if (pthread_kill(m_handle, SigThreadSuspendResume) == ESRCH)
+        if (pthread_kill(m_handle, g_wtfConfig.sigThreadSuspendResume) == ESRCH)
             return;
         globalSemaphoreForSuspendResume->wait();
     }

Modified: trunk/Source/WTF/wtf/threads/Signals.cpp (271559 => 271560)


--- trunk/Source/WTF/wtf/threads/Signals.cpp	2021-01-17 00:26:19 UTC (rev 271559)
+++ trunk/Source/WTF/wtf/threads/Signals.cpp	2021-01-17 08:50:49 UTC (rev 271560)
@@ -305,7 +305,8 @@
             auto result = sigfillset(&action.sa_mask);
             RELEASE_ASSERT(!result);
             // Do not block this signal since it is used on non-Darwin systems to suspend and resume threads.
-            result = sigdelset(&action.sa_mask, SigThreadSuspendResume);
+            RELEASE_ASSERT(g_wtfConfig.isThreadSuspendResumeSignalConfigured);
+            result = sigdelset(&action.sa_mask, g_wtfConfig.sigThreadSuspendResume);
             RELEASE_ASSERT(!result);
             action.sa_flags = SA_SIGINFO;
             auto systemSignals = toSystemSignal(signal);

Modified: trunk/Source/WTF/wtf/win/ThreadingWin.cpp (271559 => 271560)


--- trunk/Source/WTF/wtf/win/ThreadingWin.cpp	2021-01-17 00:26:19 UTC (rev 271559)
+++ trunk/Source/WTF/wtf/win/ThreadingWin.cpp	2021-01-17 08:50:49 UTC (rev 271560)
@@ -239,6 +239,7 @@
 Thread& Thread::initializeCurrentTLS()
 {
     // Not a WTF-created thread, ThreadIdentifier is not established yet.
+    WTF::initialize();
     Ref<Thread> thread = adoptRef(*new Thread());
 
     HANDLE handle;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to