Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (261537 => 261538)
--- trunk/Source/_javascript_Core/ChangeLog 2020-05-12 01:58:39 UTC (rev 261537)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-05-12 02:10:05 UTC (rev 261538)
@@ -1,3 +1,33 @@
+2020-05-11 Mark Lam <[email protected]>
+
+ Introduce WTF::Config and put Signal.cpp's init-once globals in it.
+ https://bugs.webkit.org/show_bug.cgi?id=211729
+ <rdar://problem/62938878>
+
+ Reviewed by Keith Miller and Saam Barati.
+
+ 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end
+ of the first VM initialization.
+
+ 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading()
+ to the bottom of the function. This way, we'll also catch bugs which may cause
+ us to jump into the middle of the function.
+
+ Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed
+ after all initialization is done. This guarantees that it will only be executed
+ at the end.
+
+ 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze()
+ for obvious reasons: freezing one should freeze the other.
+
+ * runtime/InitializeThreading.cpp:
+ (JSC::initializeThreading):
+ * runtime/JSCConfig.cpp:
+ (JSC::Config::permanentlyFreeze):
+ * runtime/VMTraps.cpp:
+ (JSC::VMTraps::initializeSignals):
+ * runtime/VMTraps.h:
+
2020-05-11 Keith Miller <[email protected]>
Remove unused BytecodeKills.h
Modified: trunk/Source/_javascript_Core/runtime/InitializeThreading.cpp (261537 => 261538)
--- trunk/Source/_javascript_Core/runtime/InitializeThreading.cpp 2020-05-12 01:58:39 UTC (rev 261537)
+++ trunk/Source/_javascript_Core/runtime/InitializeThreading.cpp 2020-05-12 02:10:05 UTC (rev 261538)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -44,6 +44,7 @@
#include "SigillCrashAnalyzer.h"
#include "StructureIDTable.h"
#include "SuperSampler.h"
+#include "VMTraps.h"
#include "WasmCalleeRegistry.h"
#include "WasmCapabilities.h"
#include "WasmThunks.h"
@@ -64,9 +65,6 @@
static std::once_flag initializeThreadingOnceFlag;
std::call_once(initializeThreadingOnceFlag, []{
- RELEASE_ASSERT(!g_jscConfig.initializeThreadingHasBeenCalled);
- g_jscConfig.initializeThreadingHasBeenCalled = true;
-
WTF::initializeThreading();
Options::initialize();
@@ -105,6 +103,11 @@
// JSLock::lock() can call registerThreadForMachExceptionHandling() which crashes if this has not been called first.
WTF::startMachExceptionHandlerThread();
#endif
+ VMTraps::initializeSignals();
+
+ WTF::compilerFence();
+ RELEASE_ASSERT(!g_jscConfig.initializeThreadingHasBeenCalled);
+ g_jscConfig.initializeThreadingHasBeenCalled = true;
});
}
Modified: trunk/Source/_javascript_Core/runtime/JSCConfig.cpp (261537 => 261538)
--- trunk/Source/_javascript_Core/runtime/JSCConfig.cpp 2020-05-12 01:58:39 UTC (rev 261537)
+++ trunk/Source/_javascript_Core/runtime/JSCConfig.cpp 2020-05-12 02:10:05 UTC (rev 261538)
@@ -29,6 +29,7 @@
#include <wtf/Lock.h>
#include <wtf/ResourceUsage.h>
#include <wtf/StdLibExtras.h>
+#include <wtf/WTFConfig.h>
#if OS(DARWIN)
#include <mach/mach.h>
@@ -54,6 +55,8 @@
void Config::permanentlyFreeze()
{
+ WTF::Config::permanentlyFreeze();
+
static Lock configLock;
auto locker = holdLock(configLock);
Modified: trunk/Source/_javascript_Core/runtime/VMTraps.cpp (261537 => 261538)
--- trunk/Source/_javascript_Core/runtime/VMTraps.cpp 2020-05-12 01:58:39 UTC (rev 261537)
+++ trunk/Source/_javascript_Core/runtime/VMTraps.cpp 2020-05-12 02:10:05 UTC (rev 261538)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -198,6 +198,9 @@
SignalSender(const AbstractLocker& locker, VM& vm)
: Base(locker, vm.traps().m_lock, vm.traps().m_condition.copyRef())
, m_vm(vm)
+ { }
+
+ static void initializeSignals()
{
static std::once_flag once;
std::call_once(once, [] {
@@ -294,6 +297,14 @@
#endif // ENABLE(SIGNAL_BASED_VM_TRAPS)
+void VMTraps::initializeSignals()
+{
+#if ENABLE(SIGNAL_BASED_VM_TRAPS)
+ if (!Options::usePollingTraps())
+ SignalSender::initializeSignals();
+#endif
+}
+
void VMTraps::willDestroyVM()
{
m_isShuttingDown = true;
Modified: trunk/Source/_javascript_Core/runtime/VMTraps.h (261537 => 261538)
--- trunk/Source/_javascript_Core/runtime/VMTraps.h 2020-05-12 01:58:39 UTC (rev 261537)
+++ trunk/Source/_javascript_Core/runtime/VMTraps.h 2020-05-12 02:10:05 UTC (rev 261538)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -98,6 +98,8 @@
~VMTraps();
VMTraps();
+ static void initializeSignals();
+
void willDestroyVM();
bool needTrapHandling() { return m_needTrapHandling; }
Modified: trunk/Source/WTF/ChangeLog (261537 => 261538)
--- trunk/Source/WTF/ChangeLog 2020-05-12 01:58:39 UTC (rev 261537)
+++ trunk/Source/WTF/ChangeLog 2020-05-12 02:10:05 UTC (rev 261538)
@@ -1,3 +1,74 @@
+2020-05-11 Mark Lam <[email protected]>
+
+ Introduce WTF::Config and put Signal.cpp's init-once globals in it.
+ https://bugs.webkit.org/show_bug.cgi?id=211729
+ <rdar://problem/62938878>
+
+ Reviewed by Keith Miller and Saam Barati.
+
+ 1. Added WTF::Config for storing globals that effectively serve as constants i.e
+ we'll be initializing them before or during the first VM instantiation, but
+ should not have any reason to modify them later. The WTF::Config will be frozen
+ (along with JSC::Config) at the end of instantiating the first VM instance.
+
+ 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization
+ operations that should only be called at initialization time, will not be
+ called once the Config has been frozen.
+
+ 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or
+ statics) not moved are ones that cannot be moved because they require a
+ non-trivial default constructor (once_flag), or need to be modifiable
+ at runtime (e.g. Lock).
+
+ Instead of freezing the once_flag, we sanity check the call_once block with
+ the Config::AssertNotFrozenScope.
+
+ 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in
+ the WTF::Config. The number of signal handlers we will ever install is always
+ finite. Hence, there's no reason to use a dynamic data structure like the
+ LocklessBag to hold it.
+
+ We introduce a SignalHandlers struct to manage these arrays (and all the other
+ Signal.cpp globals that we want to move to the WTF::Config). Amongst other
+ things, SignalHandlers provides the abstractions for:
+
+ a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc().
+ b. iterating SignalHandler instances. See SignalHandlers::forEachHandler().
+
+ To maintain the synchronization properties of the LocklessBag,
+ SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be
+ contended on because all signal handlers are now installed at initialization
+ time before any concurrency comes into play.
+
+ 5. We now initialize activeThreads() eagerly via initializeThreading. In
+ production configurations, this does not matter because signal handler
+ installations will always trigger its initialization. However, in debugging
+ configurations, we may end up disabling the use of all signal handlers. As a
+ result, we need to do this eager initialization to ensure that it is done
+ before we freeze the WTF::Config.
+
+ * WTF.xcodeproj/project.pbxproj:
+ * wtf/CMakeLists.txt:
+ * wtf/Threading.cpp:
+ (WTF::initializeThreading):
+ * wtf/WTFConfig.cpp: Added.
+ (WTF::Config::disableFreezingForTesting):
+ (WTF::Config::permanentlyFreeze):
+ * wtf/WTFConfig.h: Added.
+ (WTF::Config::configureForTesting):
+ (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope):
+ * wtf/threads/Signals.cpp:
+ (WTF::SignalHandlers::alloc):
+ (WTF::SignalHandlers::forEachHandler const):
+ (WTF::startMachExceptionHandlerThread):
+ (WTF::handleSignalsWithMach):
+ (WTF::setExceptionPorts):
+ (WTF::activeThreads):
+ (WTF::installSignalHandler):
+ (WTF::jscSignalHandler):
+ (WTF::SignalHandlers::initialize):
+ * wtf/threads/Signals.h:
+
2020-05-11 David Kilzer <[email protected]>
[WTF] CStringBuffer::createUninitialized() should use Checked<size_t>
Modified: trunk/Source/WTF/WTF.xcodeproj/project.pbxproj (261537 => 261538)
--- trunk/Source/WTF/WTF.xcodeproj/project.pbxproj 2020-05-12 01:58:39 UTC (rev 261537)
+++ trunk/Source/WTF/WTF.xcodeproj/project.pbxproj 2020-05-12 02:10:05 UTC (rev 261538)
@@ -182,6 +182,7 @@
E4A0AD391A96245500536DF6 /* WorkQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A0AD371A96245500536DF6 /* WorkQueue.cpp */; };
E4A0AD3D1A96253C00536DF6 /* WorkQueueCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A0AD3C1A96253C00536DF6 /* WorkQueueCocoa.cpp */; };
EB61EDC72409CCC1001EFE36 /* SystemTracingCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EB61EDC62409CCC0001EFE36 /* SystemTracingCocoa.cpp */; };
+ FE032AD22463E43B0012D7C7 /* WTFConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE032AD02463E43B0012D7C7 /* WTFConfig.cpp */; };
FE05FAFF1FE5007500093230 /* WTFAssertions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE05FAFE1FE5007500093230 /* WTFAssertions.cpp */; };
FE1E2C3B2240C06600F6B729 /* PtrTag.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE1E2C392240C05400F6B729 /* PtrTag.cpp */; };
FE1E2C42224187C600F6B729 /* PlatformRegisters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE1E2C41224187C600F6B729 /* PlatformRegisters.cpp */; };
@@ -738,6 +739,8 @@
EBFF67FC240D7D660078FF1B /* OSVariantSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSVariantSPI.h; sourceTree = "<group>"; };
EF7D6CD59D8642A8A0DA86AD /* StackTrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackTrace.h; sourceTree = "<group>"; };
F72BBDB107FA424886178B9E /* SymbolImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolImpl.cpp; sourceTree = "<group>"; };
+ FE032AD02463E43B0012D7C7 /* WTFConfig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WTFConfig.cpp; sourceTree = "<group>"; };
+ FE032AD12463E43B0012D7C7 /* WTFConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WTFConfig.h; sourceTree = "<group>"; };
FE05FAE61FDB214300093230 /* DumbPtrTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumbPtrTraits.h; sourceTree = "<group>"; };
FE05FAFE1FE5007500093230 /* WTFAssertions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WTFAssertions.cpp; sourceTree = "<group>"; };
FE1D6D87237401CD007A5C26 /* StackCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackCheck.h; sourceTree = "<group>"; };
@@ -1304,6 +1307,8 @@
E4A0AD371A96245500536DF6 /* WorkQueue.cpp */,
E4A0AD381A96245500536DF6 /* WorkQueue.h */,
FE05FAFE1FE5007500093230 /* WTFAssertions.cpp */,
+ FE032AD02463E43B0012D7C7 /* WTFConfig.cpp */,
+ FE032AD12463E43B0012D7C7 /* WTFConfig.h */,
A36E16F7216FF828008DD87E /* WTFSemaphore.h */,
);
path = wtf;
@@ -1761,6 +1766,7 @@
A8A47469151A825B004123FF /* UTF8Conversion.cpp in Sources */,
7AFEC6B11EB22B5900DADE36 /* UUID.cpp in Sources */,
E3149A39228BB43500BFA6C7 /* Vector.cpp in Sources */,
+ FE032AD22463E43B0012D7C7 /* WTFConfig.cpp in Sources */,
0F66B2921DC97BAB004A1D3F /* WallTime.cpp in Sources */,
1FA47C8A152502DA00568D1B /* WebCoreThread.cpp in Sources */,
0FE4479C1B7AAA03009498EB /* WordLock.cpp in Sources */,
Modified: trunk/Source/WTF/wtf/CMakeLists.txt (261537 => 261538)
--- trunk/Source/WTF/wtf/CMakeLists.txt 2020-05-12 01:58:39 UTC (rev 261537)
+++ trunk/Source/WTF/wtf/CMakeLists.txt 2020-05-12 02:10:05 UTC (rev 261538)
@@ -284,6 +284,7 @@
Vector.h
VectorHash.h
VectorTraits.h
+ WTFConfig.h
WTFSemaphore.h
WallTime.h
WeakHashSet.h
@@ -445,6 +446,7 @@
UniqueArray.cpp
Vector.cpp
WTFAssertions.cpp
+ WTFConfig.cpp
WallTime.cpp
WordLock.cpp
WorkQueue.cpp
Modified: trunk/Source/WTF/wtf/Threading.cpp (261537 => 261538)
--- trunk/Source/WTF/wtf/Threading.cpp 2020-05-12 01:58:39 UTC (rev 261537)
+++ trunk/Source/WTF/wtf/Threading.cpp 2020-05-12 02:10:05 UTC (rev 261538)
@@ -36,8 +36,10 @@
#include <wtf/ThreadGroup.h>
#include <wtf/ThreadMessage.h>
#include <wtf/ThreadingPrimitives.h>
+#include <wtf/WTFConfig.h>
#include <wtf/text/AtomStringTable.h>
#include <wtf/text/StringView.h>
+#include <wtf/threads/Signals.h>
#if HAVE(QOS_CLASSES)
#include <bmalloc/bmalloc.h>
@@ -360,6 +362,7 @@
{
static std::once_flag onceKey;
std::call_once(onceKey, [] {
+ Config::AssertNotFrozenScope assertScope;
initializeRandomNumberGenerator();
#if !HAVE(FAST_TLS) && !OS(WINDOWS)
Thread::initializeTLSKey();
@@ -366,6 +369,9 @@
#endif
initializeDates();
Thread::initializePlatformThreading();
+#if USE(PTHREADS) && HAVE(MACHINE_CONTEXT)
+ SignalHandlers::initialize();
+#endif
});
}
Added: trunk/Source/WTF/wtf/WTFConfig.cpp (0 => 261538)
--- trunk/Source/WTF/wtf/WTFConfig.cpp (rev 0)
+++ trunk/Source/WTF/wtf/WTFConfig.cpp 2020-05-12 02:10:05 UTC (rev 261538)
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <wtf/WTFConfig.h>
+
+#include <wtf/Lock.h>
+#include <wtf/ResourceUsage.h>
+#include <wtf/StdLibExtras.h>
+
+#if OS(DARWIN)
+#include <mach/mach.h>
+#elif OS(LINUX)
+#include <sys/mman.h>
+#endif
+
+namespace WTF {
+
+alignas(ConfigSizeToProtect) WTF_EXPORT_PRIVATE Config g_wtfConfig;
+
+void Config::permanentlyFreeze()
+{
+ static Lock configLock;
+ auto locker = holdLock(configLock);
+
+ RELEASE_ASSERT(roundUpToMultipleOf(pageSize(), ConfigSizeToProtect) == ConfigSizeToProtect);
+
+ if (!g_wtfConfig.isPermanentlyFrozen)
+ g_wtfConfig.isPermanentlyFrozen = true;
+
+ int result = 0;
+#if OS(DARWIN)
+ enum {
+ AllowPermissionChangesAfterThis = false,
+ DisallowPermissionChangesAfterThis = true
+ };
+
+ // There's no going back now!
+ result = vm_protect(mach_task_self(), reinterpret_cast<vm_address_t>(&g_wtfConfig), ConfigSizeToProtect, DisallowPermissionChangesAfterThis, VM_PROT_READ);
+#elif OS(LINUX)
+ result = mprotect(&g_wtfConfig, ConfigSizeToProtect, PROT_READ);
+#elif OS(WINDOWS)
+ // FIXME: Implement equivalent, maybe with VirtualProtect.
+ // Also need to fix WebKitTestRunner.
+#endif
+ RELEASE_ASSERT(!result);
+ RELEASE_ASSERT(g_wtfConfig.isPermanentlyFrozen);
+}
+
+} // namespace WTF
Added: trunk/Source/WTF/wtf/WTFConfig.h (0 => 261538)
--- trunk/Source/WTF/wtf/WTFConfig.h (rev 0)
+++ trunk/Source/WTF/wtf/WTFConfig.h 2020-05-12 02:10:05 UTC (rev 261538)
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/Assertions.h>
+#include <wtf/Atomics.h>
+#include <wtf/ExportMacros.h>
+#include <wtf/PageBlock.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/threads/Signals.h>
+
+namespace WTF {
+
+constexpr size_t ConfigSizeToProtect = CeilingOnPageSize;
+
+struct Config {
+ WTF_EXPORT_PRIVATE static void permanentlyFreeze();
+
+ struct AssertNotFrozenScope {
+ AssertNotFrozenScope();
+ ~AssertNotFrozenScope();
+ };
+
+ union {
+ struct {
+ // All the fields in this struct should be chosen such that their
+ // initial value is 0 / null / falsy because Config is instantiated
+ // as a global singleton.
+
+ bool isPermanentlyFrozen;
+
+#if USE(PTHREADS) && HAVE(MACHINE_CONTEXT)
+ SignalHandlers signalHandlers;
+#endif
+ };
+ char ensureSize[ConfigSizeToProtect];
+ };
+};
+
+extern "C" alignas(ConfigSizeToProtect) WTF_EXPORT_PRIVATE Config g_wtfConfig;
+
+static_assert(sizeof(Config) == ConfigSizeToProtect);
+
+ALWAYS_INLINE Config::AssertNotFrozenScope::AssertNotFrozenScope()
+{
+ RELEASE_ASSERT(!g_wtfConfig.isPermanentlyFrozen);
+ compilerFence();
+};
+
+ALWAYS_INLINE Config::AssertNotFrozenScope::~AssertNotFrozenScope()
+{
+ compilerFence();
+ RELEASE_ASSERT(!g_wtfConfig.isPermanentlyFrozen);
+};
+
+} // namespace WTF
Modified: trunk/Source/WTF/wtf/threads/Signals.cpp (261537 => 261538)
--- trunk/Source/WTF/wtf/threads/Signals.cpp 2020-05-12 01:58:39 UTC (rev 261537)
+++ trunk/Source/WTF/wtf/threads/Signals.cpp 2020-05-12 02:10:05 UTC (rev 261538)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -51,15 +51,42 @@
#include <wtf/ThreadGroup.h>
#include <wtf/ThreadMessage.h>
#include <wtf/Threading.h>
+#include <wtf/WTFConfig.h>
-
namespace WTF {
-
-static LazyNeverDestroyed<LocklessBag<SignalHandler>> handlers[static_cast<size_t>(Signal::NumberOfSignals)] = { };
-static std::once_flag initializeOnceFlags[static_cast<size_t>(Signal::NumberOfSignals)];
-static struct sigaction oldActions[static_cast<size_t>(Signal::NumberOfSignals)];
+void SignalHandlers::add(Signal signal, SignalHandler&& handler)
+{
+ Config::AssertNotFrozenScope assertScope;
+ static Lock lock;
+ auto locker = holdLock(lock);
+ size_t signalIndex = static_cast<size_t>(signal);
+ size_t nextFree = numberOfHandlers[signalIndex];
+ RELEASE_ASSERT(nextFree < maxNumberOfHandlers);
+ SignalHandlerMemory* memory = &handlers[signalIndex][nextFree];
+ new (memory) SignalHandler(WTFMove(handler));
+
+ // We deliberately do not want to increment the count until after we've
+ // fully initialized the memory. This way, forEachHandler() won't see a
+ // partially initialized handler.
+ storeStoreFence();
+ numberOfHandlers[signalIndex]++;
+ loadLoadFence();
+}
+
+template<typename Func>
+inline void SignalHandlers::forEachHandler(Signal signal, const Func& func) const
+{
+ size_t signalIndex = static_cast<size_t>(signal);
+ size_t handlerIndex = numberOfHandlers[signalIndex];
+ while (handlerIndex--) {
+ auto* memory = const_cast<SignalHandlerMemory*>(&handlers[signalIndex][handlerIndex]);
+ const SignalHandler& handler = *bitwise_cast<SignalHandler*>(memory);
+ func(handler);
+ }
+}
+
#if HAVE(MACH_EXCEPTIONS)
// You can read more about mach exceptions here:
// http://www.cs.cmu.edu/afs/cs/project/mach/public/doc/unpublished/exception.ps
@@ -66,7 +93,6 @@
// and the Mach interface Generator (MiG) here:
// http://www.cs.cmu.edu/afs/cs/project/mach/public/doc/unpublished/mig.ps
-static mach_port_t exceptionPort;
static constexpr size_t maxMessageSize = 1 * KB;
void startMachExceptionHandlerThread()
@@ -73,13 +99,15 @@
{
static std::once_flag once;
std::call_once(once, [] {
- kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exceptionPort);
+ Config::AssertNotFrozenScope assertScope;
+ SignalHandlers& handlers = g_wtfConfig.signalHandlers;
+ kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &handlers.exceptionPort);
RELEASE_ASSERT(kr == KERN_SUCCESS);
- kr = mach_port_insert_right(mach_task_self(), exceptionPort, exceptionPort, MACH_MSG_TYPE_MAKE_SEND);
+ kr = mach_port_insert_right(mach_task_self(), handlers.exceptionPort, handlers.exceptionPort, MACH_MSG_TYPE_MAKE_SEND);
RELEASE_ASSERT(kr == KERN_SUCCESS);
dispatch_source_t source = dispatch_source_create(
- DISPATCH_SOURCE_TYPE_MACH_RECV, exceptionPort, 0, DISPATCH_TARGET_QUEUE_DEFAULT);
+ DISPATCH_SOURCE_TYPE_MACH_RECV, handlers.exceptionPort, 0, DISPATCH_TARGET_QUEUE_DEFAULT);
RELEASE_ASSERT(source);
dispatch_source_set_event_handler(source, ^{
@@ -86,7 +114,7 @@
UNUSED_PARAM(source); // Capture a pointer to source in user space to silence the leaks tool.
kern_return_t kr = mach_msg_server_once(
- mach_exc_server, maxMessageSize, exceptionPort, MACH_MSG_TIMEOUT_NONE);
+ mach_exc_server, maxMessageSize, handlers.exceptionPort, MACH_MSG_TIMEOUT_NONE);
RELEASE_ASSERT(kr == KERN_SUCCESS);
});
@@ -145,7 +173,8 @@
thread_state_t outState,
mach_msg_type_number_t* outStateCount)
{
- RELEASE_ASSERT(port == exceptionPort);
+ SignalHandlers& handlers = g_wtfConfig.signalHandlers;
+ RELEASE_ASSERT(port == handlers.exceptionPort);
// If we wanted to distinguish between SIGBUS and SIGSEGV for EXC_BAD_ACCESS on Darwin we could do:
// if (exceptionData[0] == KERN_INVALID_ADDRESS)
// signal = SIGSEGV;
@@ -178,7 +207,7 @@
}
bool didHandle = false;
- handlers[static_cast<size_t>(signal)]->iterate([&] (const SignalHandler& handler) {
+ handlers.forEachHandler(signal, [&] (const SignalHandler& handler) {
SignalAction handlerResult = handler(signal, info, registers);
didHandle |= handlerResult == SignalAction::Handled;
});
@@ -188,21 +217,19 @@
return KERN_FAILURE;
}
-};
+}; // extern "C"
-static bool useMach { false };
void handleSignalsWithMach()
{
- useMach = true;
+ Config::AssertNotFrozenScope assertScope;
+ g_wtfConfig.signalHandlers.useMach = true;
}
-
-exception_mask_t activeExceptions { 0 };
-
inline void setExceptionPorts(const AbstractLocker& threadGroupLocker, Thread& thread)
{
UNUSED_PARAM(threadGroupLocker);
- kern_return_t result = thread_set_exception_ports(thread.machThread(), activeExceptions, exceptionPort, EXCEPTION_STATE | MACH_EXCEPTION_CODES, MACHINE_THREAD_STATE);
+ SignalHandlers& handlers = g_wtfConfig.signalHandlers;
+ kern_return_t result = thread_set_exception_ports(thread.machThread(), handlers.activeExceptions, handlers.exceptionPort, EXCEPTION_STATE | MACH_EXCEPTION_CODES, MACHINE_THREAD_STATE);
if (result != KERN_SUCCESS) {
dataLogLn("thread set port failed due to ", mach_error_string(result));
CRASH();
@@ -214,6 +241,7 @@
static std::once_flag initializeKey;
static ThreadGroup* activeThreadsPtr = nullptr;
std::call_once(initializeKey, [&] {
+ Config::AssertNotFrozenScope assertScope;
static NeverDestroyed<std::shared_ptr<ThreadGroup>> activeThreads { ThreadGroup::create() };
activeThreadsPtr = activeThreads.get().get();
});
@@ -242,17 +270,22 @@
void installSignalHandler(Signal signal, SignalHandler&& handler)
{
+ Config::AssertNotFrozenScope assertScope;
+ SignalHandlers& handlers = g_wtfConfig.signalHandlers;
ASSERT(signal < Signal::Unknown);
#if HAVE(MACH_EXCEPTIONS)
- ASSERT(!useMach || signal != Signal::Usr);
+ ASSERT(!handlers.useMach || signal != Signal::Usr);
- if (useMach)
+ if (handlers.useMach)
startMachExceptionHandlerThread();
#endif
+ static std::once_flag initializeOnceFlags[static_cast<size_t>(Signal::NumberOfSignals)];
std::call_once(initializeOnceFlags[static_cast<size_t>(signal)], [&] {
- handlers[static_cast<size_t>(signal)].construct();
-
+ Config::AssertNotFrozenScope assertScope;
+#if HAVE(MACH_EXCEPTIONS)
+ bool useMach = handlers.useMach;
+#endif
if (!useMach) {
struct sigaction action;
action.sa_sigaction = jscSignalHandler;
@@ -263,20 +296,19 @@
RELEASE_ASSERT(!result);
action.sa_flags = SA_SIGINFO;
auto systemSignals = toSystemSignal(signal);
- result = sigaction(std::get<0>(systemSignals), &action, &oldActions[offsetForSystemSignal(std::get<0>(systemSignals))]);
+ result = sigaction(std::get<0>(systemSignals), &action, &handlers.oldActions[offsetForSystemSignal(std::get<0>(systemSignals))]);
if (std::get<1>(systemSignals))
- result |= sigaction(*std::get<1>(systemSignals), &action, &oldActions[offsetForSystemSignal(*std::get<1>(systemSignals))]);
+ result |= sigaction(*std::get<1>(systemSignals), &action, &handlers.oldActions[offsetForSystemSignal(*std::get<1>(systemSignals))]);
RELEASE_ASSERT(!result);
}
-
});
- handlers[static_cast<size_t>(signal)]->add(WTFMove(handler));
+ handlers.add(signal, WTFMove(handler));
#if HAVE(MACH_EXCEPTIONS)
auto locker = holdLock(activeThreads().getLock());
- if (useMach) {
- activeExceptions |= toMachMask(signal);
+ if (handlers.useMach) {
+ handlers.activeExceptions |= toMachMask(signal);
for (auto& thread : activeThreads().threads(locker))
setExceptionPorts(locker, thread.get());
@@ -287,6 +319,7 @@
void jscSignalHandler(int sig, siginfo_t* info, void* ucontext)
{
Signal signal = fromSystemSignal(sig);
+ SignalHandlers& handlers = g_wtfConfig.signalHandlers;
auto restoreDefault = [&] {
struct sigaction defaultAction;
@@ -299,7 +332,7 @@
// This shouldn't happen but we might as well be careful.
if (signal == Signal::Unknown) {
- dataLogLn("We somehow got called for an unknown signal ", sig, ", halp.");
+ dataLogLn("We somehow got called for an unknown signal ", sig, ", help.");
restoreDefault();
return;
}
@@ -312,7 +345,7 @@
bool didHandle = false;
bool restoreDefaultHandler = false;
- handlers[static_cast<size_t>(signal)]->iterate([&] (const SignalHandler& handler) {
+ handlers.forEachHandler(signal, [&] (const SignalHandler& handler) {
switch (handler(signal, sigInfo, registers)) {
case SignalAction::Handled:
didHandle = true;
@@ -331,7 +364,7 @@
}
unsigned oldActionIndex = static_cast<size_t>(signal) + (sig == SIGBUS);
- struct sigaction& oldAction = oldActions[static_cast<size_t>(oldActionIndex)];
+ struct sigaction& oldAction = handlers.oldActions[static_cast<size_t>(oldActionIndex)];
if (signal == Signal::Usr) {
if (oldAction.sa_sigaction)
oldAction.sa_sigaction(sig, info, ucontext);
@@ -349,6 +382,18 @@
}
}
+void SignalHandlers::initialize()
+{
+#if HAVE(MACH_EXCEPTIONS)
+ // In production configurations, this does not matter because signal handler
+ // installations will always trigger this initialization. However, in debugging
+ // configurations, we may end up disabling the use of all signal handlers but
+ // we still need this to be initialized. Hence, we need to initialize it
+ // eagerly to ensure that it is done before we freeze the WTF::Config.
+ activeThreads();
+#endif
+}
+
} // namespace WTF
#endif // USE(PTHREADS) && HAVE(MACHINE_CONTEXT)
Modified: trunk/Source/WTF/wtf/threads/Signals.h (261537 => 261538)
--- trunk/Source/WTF/wtf/threads/Signals.h 2020-05-12 01:58:39 UTC (rev 261537)
+++ trunk/Source/WTF/wtf/threads/Signals.h 2020-05-12 02:10:05 UTC (rev 261538)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,9 +30,14 @@
#include <signal.h>
#include <tuple>
#include <wtf/Function.h>
+#include <wtf/Lock.h>
#include <wtf/Optional.h>
#include <wtf/PlatformRegisters.h>
+#if HAVE(MACH_EXCEPTIONS)
+#include <mach/exception_types.h>
+#endif
+
namespace WTF {
// Note that SIGUSR1 is used in Pthread-based ports except for Darwin to suspend and resume threads.
@@ -82,11 +87,36 @@
};
using SignalHandler = Function<SignalAction(Signal, SigInfo&, PlatformRegisters&)>;
+using SignalHandlerMemory = std::aligned_storage<sizeof(SignalHandler), std::alignment_of<SignalHandler>::value>::type;
-// Call this method whenever you want to install a signal handler. It's ok to call this function lazily.
+struct SignalHandlers {
+ static void initialize();
+
+ void add(Signal, SignalHandler&&);
+ template<typename Func>
+ void forEachHandler(Signal, const Func&) const;
+
+ static constexpr size_t numberOfSignals = static_cast<size_t>(Signal::NumberOfSignals);
+ static constexpr size_t maxNumberOfHandlers = 2;
+
+ static_assert(numberOfSignals < std::numeric_limits<uint8_t>::max());
+
+#if HAVE(MACH_EXCEPTIONS)
+ mach_port_t exceptionPort;
+ exception_mask_t activeExceptions;
+ bool useMach;
+#endif
+ uint8_t numberOfHandlers[numberOfSignals];
+ SignalHandlerMemory handlers[numberOfSignals][maxNumberOfHandlers];
+ struct sigaction oldActions[numberOfSignals];
+};
+
+// Call this method whenever you want to install a signal handler. This function needs to be called
+// before g_wtfConfig is frozen. After the g_wtfConfig is frozen, no additional signal handlers may
+// be installed. Any attempt to do so will trigger a crash.
// Note: Your signal handler will be called every time the handler for the desired signal is called.
// Thus it is your responsibility to discern if the signal fired was yours.
-// This function is currently a one way street i.e. once installed, a signal handler cannot be uninstalled.
+// This function is a one way street i.e. once installed, a signal handler cannot be uninstalled.
WTF_EXPORT_PRIVATE void installSignalHandler(Signal, SignalHandler&&);