Changeset 261538 in webkit


Ignore:
Timestamp:
May 11, 2020, 7:10:05 PM (5 years ago)
Author:
mark.lam@apple.com
Message:

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.

Source/JavaScriptCore:

  1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization.
  1. 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.

  1. 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:

Source/WTF:

  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.
  1. 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.
  1. 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.

  1. 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:

  1. allocating memory for the SignalHandler instances. See SignalHandlers::alloc().
  2. 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.

  1. 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:
Location:
trunk/Source
Files:
2 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r261504 r261538  
     12020-05-11  Mark Lam  <mark.lam@apple.com>
     2
     3        Introduce WTF::Config and put Signal.cpp's init-once globals in it.
     4        https://bugs.webkit.org/show_bug.cgi?id=211729
     5        <rdar://problem/62938878>
     6
     7        Reviewed by Keith Miller and Saam Barati.
     8
     9        1. Initialize VMTraps' signals early now that we'll be freezing signals at the end
     10           of the first VM initialization.
     11
     12        2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading()
     13           to the bottom of the function.  This way, we'll also catch bugs which may cause
     14           us to jump into the middle of the function.
     15
     16           Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed
     17           after all initialization is done.  This guarantees that it will only be executed
     18           at the end.
     19
     20        3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze()
     21           for obvious reasons: freezing one should freeze the other.
     22
     23        * runtime/InitializeThreading.cpp:
     24        (JSC::initializeThreading):
     25        * runtime/JSCConfig.cpp:
     26        (JSC::Config::permanentlyFreeze):
     27        * runtime/VMTraps.cpp:
     28        (JSC::VMTraps::initializeSignals):
     29        * runtime/VMTraps.h:
     30
    1312020-05-11  Keith Miller  <keith_miller@apple.com>
    232
  • trunk/Source/JavaScriptCore/runtime/InitializeThreading.cpp

    r260165 r261538  
    11/*
    2  * Copyright (C) 2008-2019 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008-2020 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    4545#include "StructureIDTable.h"
    4646#include "SuperSampler.h"
     47#include "VMTraps.h"
    4748#include "WasmCalleeRegistry.h"
    4849#include "WasmCapabilities.h"
     
    6566
    6667    std::call_once(initializeThreadingOnceFlag, []{
    67         RELEASE_ASSERT(!g_jscConfig.initializeThreadingHasBeenCalled);
    68         g_jscConfig.initializeThreadingHasBeenCalled = true;
    69 
    7068        WTF::initializeThreading();
    7169        Options::initialize();
     
    106104        WTF::startMachExceptionHandlerThread();
    107105#endif
     106        VMTraps::initializeSignals();
     107
     108        WTF::compilerFence();
     109        RELEASE_ASSERT(!g_jscConfig.initializeThreadingHasBeenCalled);
     110        g_jscConfig.initializeThreadingHasBeenCalled = true;
    108111    });
    109112}
  • trunk/Source/JavaScriptCore/runtime/JSCConfig.cpp

    r260913 r261538  
    3030#include <wtf/ResourceUsage.h>
    3131#include <wtf/StdLibExtras.h>
     32#include <wtf/WTFConfig.h>
    3233
    3334#if OS(DARWIN)
     
    5556void Config::permanentlyFreeze()
    5657{
     58    WTF::Config::permanentlyFreeze();
     59
    5760    static Lock configLock;
    5861    auto locker = holdLock(configLock);
  • trunk/Source/JavaScriptCore/runtime/VMTraps.cpp

    r260415 r261538  
    11/*
    2  * Copyright (C) 2017-2019 Apple Inc. All rights reserved.
     2 * Copyright (C) 2017-2020 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    199199        : Base(locker, vm.traps().m_lock, vm.traps().m_condition.copyRef())
    200200        , m_vm(vm)
     201    { }
     202
     203    static void initializeSignals()
    201204    {
    202205        static std::once_flag once;
     
    294297
    295298#endif // ENABLE(SIGNAL_BASED_VM_TRAPS)
     299
     300void VMTraps::initializeSignals()
     301{
     302#if ENABLE(SIGNAL_BASED_VM_TRAPS)
     303    if (!Options::usePollingTraps())
     304        SignalSender::initializeSignals();
     305#endif
     306}
    296307
    297308void VMTraps::willDestroyVM()
  • trunk/Source/JavaScriptCore/runtime/VMTraps.h

    r253613 r261538  
    11/*
    2  * Copyright (C) 2017-2019 Apple Inc. All rights reserved.
     2 * Copyright (C) 2017-2020 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    9999    VMTraps();
    100100
     101    static void initializeSignals();
     102
    101103    void willDestroyVM();
    102104
  • trunk/Source/WTF/ChangeLog

    r261537 r261538  
     12020-05-11  Mark Lam  <mark.lam@apple.com>
     2
     3        Introduce WTF::Config and put Signal.cpp's init-once globals in it.
     4        https://bugs.webkit.org/show_bug.cgi?id=211729
     5        <rdar://problem/62938878>
     6
     7        Reviewed by Keith Miller and Saam Barati.
     8
     9        1. Added WTF::Config for storing globals that effectively serve as constants i.e
     10           we'll be initializing them before or during the first VM instantiation, but
     11           should not have any reason to modify them later.  The WTF::Config will be frozen
     12           (along with JSC::Config) at the end of instantiating the first VM instance.
     13
     14        2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization
     15           operations that should only be called at initialization time, will not be
     16           called once the Config has been frozen.
     17
     18        3. Moved most of Signal.cpp's globals into WTF::Config.  The only globals (or
     19           statics) not moved are ones that cannot be moved because they require a
     20           non-trivial default constructor (once_flag), or need to be modifiable
     21           at runtime (e.g. Lock).
     22
     23           Instead of freezing the once_flag, we sanity check the call_once block with
     24           the Config::AssertNotFrozenScope.
     25
     26        4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in
     27           the WTF::Config.  The number of signal handlers we will ever install is always
     28           finite.  Hence, there's no reason to use a dynamic data structure like the
     29           LocklessBag to hold it.
     30
     31           We introduce a SignalHandlers struct to manage these arrays (and all the other
     32           Signal.cpp globals that we want to move to the WTF::Config).  Amongst other
     33           things, SignalHandlers provides the abstractions for:
     34
     35           a. allocating memory for the SignalHandler instances.  See SignalHandlers::alloc().
     36           b. iterating SignalHandler instances. See SignalHandlers::forEachHandler().
     37
     38           To maintain the synchronization properties of the LocklessBag,
     39           SignalHandlers::alloc() uses a mutex.  In practice, this mutex will never be
     40           contended on because all signal handlers are now installed at initialization
     41           time before any concurrency comes into play.
     42
     43        5. We now initialize activeThreads() eagerly via initializeThreading.  In
     44           production configurations, this does not matter because signal handler
     45           installations will always trigger its initialization.  However, in debugging
     46           configurations, we may end up disabling the use of all signal handlers.  As a
     47           result, we need to do this eager initialization to ensure that it is done
     48           before we freeze the WTF::Config.
     49
     50        * WTF.xcodeproj/project.pbxproj:
     51        * wtf/CMakeLists.txt:
     52        * wtf/Threading.cpp:
     53        (WTF::initializeThreading):
     54        * wtf/WTFConfig.cpp: Added.
     55        (WTF::Config::disableFreezingForTesting):
     56        (WTF::Config::permanentlyFreeze):
     57        * wtf/WTFConfig.h: Added.
     58        (WTF::Config::configureForTesting):
     59        (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope):
     60        * wtf/threads/Signals.cpp:
     61        (WTF::SignalHandlers::alloc):
     62        (WTF::SignalHandlers::forEachHandler const):
     63        (WTF::startMachExceptionHandlerThread):
     64        (WTF::handleSignalsWithMach):
     65        (WTF::setExceptionPorts):
     66        (WTF::activeThreads):
     67        (WTF::installSignalHandler):
     68        (WTF::jscSignalHandler):
     69        (WTF::SignalHandlers::initialize):
     70        * wtf/threads/Signals.h:
     71
    1722020-05-11  David Kilzer  <ddkilzer@apple.com>
    273
  • trunk/Source/WTF/WTF.xcodeproj/project.pbxproj

    r261179 r261538  
    183183                E4A0AD3D1A96253C00536DF6 /* WorkQueueCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A0AD3C1A96253C00536DF6 /* WorkQueueCocoa.cpp */; };
    184184                EB61EDC72409CCC1001EFE36 /* SystemTracingCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EB61EDC62409CCC0001EFE36 /* SystemTracingCocoa.cpp */; };
     185                FE032AD22463E43B0012D7C7 /* WTFConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE032AD02463E43B0012D7C7 /* WTFConfig.cpp */; };
    185186                FE05FAFF1FE5007500093230 /* WTFAssertions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE05FAFE1FE5007500093230 /* WTFAssertions.cpp */; };
    186187                FE1E2C3B2240C06600F6B729 /* PtrTag.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE1E2C392240C05400F6B729 /* PtrTag.cpp */; };
     
    739740                EF7D6CD59D8642A8A0DA86AD /* StackTrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackTrace.h; sourceTree = "<group>"; };
    740741                F72BBDB107FA424886178B9E /* SymbolImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolImpl.cpp; sourceTree = "<group>"; };
     742                FE032AD02463E43B0012D7C7 /* WTFConfig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WTFConfig.cpp; sourceTree = "<group>"; };
     743                FE032AD12463E43B0012D7C7 /* WTFConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WTFConfig.h; sourceTree = "<group>"; };
    741744                FE05FAE61FDB214300093230 /* DumbPtrTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumbPtrTraits.h; sourceTree = "<group>"; };
    742745                FE05FAFE1FE5007500093230 /* WTFAssertions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WTFAssertions.cpp; sourceTree = "<group>"; };
     
    13051308                                E4A0AD381A96245500536DF6 /* WorkQueue.h */,
    13061309                                FE05FAFE1FE5007500093230 /* WTFAssertions.cpp */,
     1310                                FE032AD02463E43B0012D7C7 /* WTFConfig.cpp */,
     1311                                FE032AD12463E43B0012D7C7 /* WTFConfig.h */,
    13071312                                A36E16F7216FF828008DD87E /* WTFSemaphore.h */,
    13081313                        );
     
    17621767                                7AFEC6B11EB22B5900DADE36 /* UUID.cpp in Sources */,
    17631768                                E3149A39228BB43500BFA6C7 /* Vector.cpp in Sources */,
     1769                                FE032AD22463E43B0012D7C7 /* WTFConfig.cpp in Sources */,
    17641770                                0F66B2921DC97BAB004A1D3F /* WallTime.cpp in Sources */,
    17651771                                1FA47C8A152502DA00568D1B /* WebCoreThread.cpp in Sources */,
  • trunk/Source/WTF/wtf/CMakeLists.txt

    r261179 r261538  
    285285    VectorHash.h
    286286    VectorTraits.h
     287    WTFConfig.h
    287288    WTFSemaphore.h
    288289    WallTime.h
     
    446447    Vector.cpp
    447448    WTFAssertions.cpp
     449    WTFConfig.cpp
    448450    WallTime.cpp
    449451    WordLock.cpp
  • trunk/Source/WTF/wtf/Threading.cpp

    r261328 r261538  
    3737#include <wtf/ThreadMessage.h>
    3838#include <wtf/ThreadingPrimitives.h>
     39#include <wtf/WTFConfig.h>
    3940#include <wtf/text/AtomStringTable.h>
    4041#include <wtf/text/StringView.h>
     42#include <wtf/threads/Signals.h>
    4143
    4244#if HAVE(QOS_CLASSES)
     
    361363    static std::once_flag onceKey;
    362364    std::call_once(onceKey, [] {
     365        Config::AssertNotFrozenScope assertScope;
    363366        initializeRandomNumberGenerator();
    364367#if !HAVE(FAST_TLS) && !OS(WINDOWS)
     
    367370        initializeDates();
    368371        Thread::initializePlatformThreading();
     372#if USE(PTHREADS) && HAVE(MACHINE_CONTEXT)
     373        SignalHandlers::initialize();
     374#endif
    369375    });
    370376}
  • trunk/Source/WTF/wtf/threads/Signals.cpp

    r260165 r261538  
    11/*
    2  * Copyright (C) 2017 Apple Inc. All rights reserved.
     2 * Copyright (C) 2017-2020 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    5252#include <wtf/ThreadMessage.h>
    5353#include <wtf/Threading.h>
    54 
     54#include <wtf/WTFConfig.h>
    5555
    5656namespace WTF {
    5757
    58    
    59 static LazyNeverDestroyed<LocklessBag<SignalHandler>> handlers[static_cast<size_t>(Signal::NumberOfSignals)] = { };
    60 static std::once_flag initializeOnceFlags[static_cast<size_t>(Signal::NumberOfSignals)];
    61 static struct sigaction oldActions[static_cast<size_t>(Signal::NumberOfSignals)];
     58void SignalHandlers::add(Signal signal, SignalHandler&& handler)
     59{
     60    Config::AssertNotFrozenScope assertScope;
     61    static Lock lock;
     62    auto locker = holdLock(lock);
     63
     64    size_t signalIndex = static_cast<size_t>(signal);
     65    size_t nextFree = numberOfHandlers[signalIndex];
     66    RELEASE_ASSERT(nextFree < maxNumberOfHandlers);
     67    SignalHandlerMemory* memory = &handlers[signalIndex][nextFree];
     68    new (memory) SignalHandler(WTFMove(handler));
     69
     70    // We deliberately do not want to increment the count until after we've
     71    // fully initialized the memory. This way, forEachHandler() won't see a
     72    // partially initialized handler.
     73    storeStoreFence();
     74    numberOfHandlers[signalIndex]++;
     75    loadLoadFence();
     76}
     77
     78template<typename Func>
     79inline void SignalHandlers::forEachHandler(Signal signal, const Func& func) const
     80{
     81    size_t signalIndex = static_cast<size_t>(signal);
     82    size_t handlerIndex = numberOfHandlers[signalIndex];
     83    while (handlerIndex--) {
     84        auto* memory = const_cast<SignalHandlerMemory*>(&handlers[signalIndex][handlerIndex]);
     85        const SignalHandler& handler = *bitwise_cast<SignalHandler*>(memory);
     86        func(handler);
     87    }
     88}
    6289
    6390#if HAVE(MACH_EXCEPTIONS)
     
    6794// http://www.cs.cmu.edu/afs/cs/project/mach/public/doc/unpublished/mig.ps
    6895
    69 static mach_port_t exceptionPort;
    7096static constexpr size_t maxMessageSize = 1 * KB;
    7197
     
    74100    static std::once_flag once;
    75101    std::call_once(once, [] {
    76         kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exceptionPort);
     102        Config::AssertNotFrozenScope assertScope;
     103        SignalHandlers& handlers = g_wtfConfig.signalHandlers;
     104        kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &handlers.exceptionPort);
    77105        RELEASE_ASSERT(kr == KERN_SUCCESS);
    78         kr = mach_port_insert_right(mach_task_self(), exceptionPort, exceptionPort, MACH_MSG_TYPE_MAKE_SEND);
     106        kr = mach_port_insert_right(mach_task_self(), handlers.exceptionPort, handlers.exceptionPort, MACH_MSG_TYPE_MAKE_SEND);
    79107        RELEASE_ASSERT(kr == KERN_SUCCESS);
    80108
    81109        dispatch_source_t source = dispatch_source_create(
    82             DISPATCH_SOURCE_TYPE_MACH_RECV, exceptionPort, 0, DISPATCH_TARGET_QUEUE_DEFAULT);
     110            DISPATCH_SOURCE_TYPE_MACH_RECV, handlers.exceptionPort, 0, DISPATCH_TARGET_QUEUE_DEFAULT);
    83111        RELEASE_ASSERT(source);
    84112
     
    87115
    88116            kern_return_t kr = mach_msg_server_once(
    89                 mach_exc_server, maxMessageSize, exceptionPort, MACH_MSG_TIMEOUT_NONE);
     117                mach_exc_server, maxMessageSize, handlers.exceptionPort, MACH_MSG_TIMEOUT_NONE);
    90118            RELEASE_ASSERT(kr == KERN_SUCCESS);
    91119        });
     
    146174    mach_msg_type_number_t* outStateCount)
    147175{
    148     RELEASE_ASSERT(port == exceptionPort);
     176    SignalHandlers& handlers = g_wtfConfig.signalHandlers;
     177    RELEASE_ASSERT(port == handlers.exceptionPort);
    149178    // If we wanted to distinguish between SIGBUS and SIGSEGV for EXC_BAD_ACCESS on Darwin we could do:
    150179    // if (exceptionData[0] == KERN_INVALID_ADDRESS)
     
    179208
    180209    bool didHandle = false;
    181     handlers[static_cast<size_t>(signal)]->iterate([&] (const SignalHandler& handler) {
     210    handlers.forEachHandler(signal, [&] (const SignalHandler& handler) {
    182211        SignalAction handlerResult = handler(signal, info, registers);
    183212        didHandle |= handlerResult == SignalAction::Handled;
     
    189218}
    190219
    191 };
    192 
    193 static bool useMach { false };
     220}; // extern "C"
     221
    194222void handleSignalsWithMach()
    195223{
    196     useMach = true;
    197 }
    198 
    199 
    200 exception_mask_t activeExceptions { 0 };
     224    Config::AssertNotFrozenScope assertScope;
     225    g_wtfConfig.signalHandlers.useMach = true;
     226}
    201227
    202228inline void setExceptionPorts(const AbstractLocker& threadGroupLocker, Thread& thread)
    203229{
    204230    UNUSED_PARAM(threadGroupLocker);
    205     kern_return_t result = thread_set_exception_ports(thread.machThread(), activeExceptions, exceptionPort, EXCEPTION_STATE | MACH_EXCEPTION_CODES, MACHINE_THREAD_STATE);
     231    SignalHandlers& handlers = g_wtfConfig.signalHandlers;
     232    kern_return_t result = thread_set_exception_ports(thread.machThread(), handlers.activeExceptions, handlers.exceptionPort, EXCEPTION_STATE | MACH_EXCEPTION_CODES, MACHINE_THREAD_STATE);
    206233    if (result != KERN_SUCCESS) {
    207234        dataLogLn("thread set port failed due to ", mach_error_string(result));
     
    215242    static ThreadGroup* activeThreadsPtr = nullptr;
    216243    std::call_once(initializeKey, [&] {
     244        Config::AssertNotFrozenScope assertScope;
    217245        static NeverDestroyed<std::shared_ptr<ThreadGroup>> activeThreads { ThreadGroup::create() };
    218246        activeThreadsPtr = activeThreads.get().get();
     
    243271void installSignalHandler(Signal signal, SignalHandler&& handler)
    244272{
     273    Config::AssertNotFrozenScope assertScope;
     274    SignalHandlers& handlers = g_wtfConfig.signalHandlers;
    245275    ASSERT(signal < Signal::Unknown);
    246276#if HAVE(MACH_EXCEPTIONS)
    247     ASSERT(!useMach || signal != Signal::Usr);
    248 
    249     if (useMach)
     277    ASSERT(!handlers.useMach || signal != Signal::Usr);
     278
     279    if (handlers.useMach)
    250280        startMachExceptionHandlerThread();
    251281#endif
    252282
     283    static std::once_flag initializeOnceFlags[static_cast<size_t>(Signal::NumberOfSignals)];
    253284    std::call_once(initializeOnceFlags[static_cast<size_t>(signal)], [&] {
    254         handlers[static_cast<size_t>(signal)].construct();
    255 
     285        Config::AssertNotFrozenScope assertScope;
     286#if HAVE(MACH_EXCEPTIONS)
     287        bool useMach = handlers.useMach;
     288#endif
    256289        if (!useMach) {
    257290            struct sigaction action;
     
    264297            action.sa_flags = SA_SIGINFO;
    265298            auto systemSignals = toSystemSignal(signal);
    266             result = sigaction(std::get<0>(systemSignals), &action, &oldActions[offsetForSystemSignal(std::get<0>(systemSignals))]);
     299            result = sigaction(std::get<0>(systemSignals), &action, &handlers.oldActions[offsetForSystemSignal(std::get<0>(systemSignals))]);
    267300            if (std::get<1>(systemSignals))
    268                 result |= sigaction(*std::get<1>(systemSignals), &action, &oldActions[offsetForSystemSignal(*std::get<1>(systemSignals))]);
     301                result |= sigaction(*std::get<1>(systemSignals), &action, &handlers.oldActions[offsetForSystemSignal(*std::get<1>(systemSignals))]);
    269302            RELEASE_ASSERT(!result);
    270303        }
    271 
    272     });
    273 
    274     handlers[static_cast<size_t>(signal)]->add(WTFMove(handler));
     304    });
     305
     306    handlers.add(signal, WTFMove(handler));
    275307
    276308#if HAVE(MACH_EXCEPTIONS)
    277309    auto locker = holdLock(activeThreads().getLock());
    278     if (useMach) {
    279         activeExceptions |= toMachMask(signal);
     310    if (handlers.useMach) {
     311        handlers.activeExceptions |= toMachMask(signal);
    280312
    281313        for (auto& thread : activeThreads().threads(locker))
     
    288320{
    289321    Signal signal = fromSystemSignal(sig);
     322    SignalHandlers& handlers = g_wtfConfig.signalHandlers;
    290323
    291324    auto restoreDefault = [&] {
     
    300333    // This shouldn't happen but we might as well be careful.
    301334    if (signal == Signal::Unknown) {
    302         dataLogLn("We somehow got called for an unknown signal ", sig, ", halp.");
     335        dataLogLn("We somehow got called for an unknown signal ", sig, ", help.");
    303336        restoreDefault();
    304337        return;
     
    313346    bool didHandle = false;
    314347    bool restoreDefaultHandler = false;
    315     handlers[static_cast<size_t>(signal)]->iterate([&] (const SignalHandler& handler) {
     348    handlers.forEachHandler(signal, [&] (const SignalHandler& handler) {
    316349        switch (handler(signal, sigInfo, registers)) {
    317350        case SignalAction::Handled:
     
    332365
    333366    unsigned oldActionIndex = static_cast<size_t>(signal) + (sig == SIGBUS);
    334     struct sigaction& oldAction = oldActions[static_cast<size_t>(oldActionIndex)];
     367    struct sigaction& oldAction = handlers.oldActions[static_cast<size_t>(oldActionIndex)];
    335368    if (signal == Signal::Usr) {
    336369        if (oldAction.sa_sigaction)
     
    350383}
    351384
     385void SignalHandlers::initialize()
     386{
     387#if HAVE(MACH_EXCEPTIONS)
     388    // In production configurations, this does not matter because signal handler
     389    // installations will always trigger this initialization. However, in debugging
     390    // configurations, we may end up disabling the use of all signal handlers but
     391    // we still need this to be initialized. Hence, we need to initialize it
     392    // eagerly to ensure that it is done before we freeze the WTF::Config.
     393    activeThreads();
     394#endif
     395}
     396
    352397} // namespace WTF
    353398
  • trunk/Source/WTF/wtf/threads/Signals.h

    r260165 r261538  
    11/*
    2  * Copyright (C) 2017 Apple Inc. All rights reserved.
     2 * Copyright (C) 2017-2020 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3131#include <tuple>
    3232#include <wtf/Function.h>
     33#include <wtf/Lock.h>
    3334#include <wtf/Optional.h>
    3435#include <wtf/PlatformRegisters.h>
     36
     37#if HAVE(MACH_EXCEPTIONS)
     38#include <mach/exception_types.h>
     39#endif
    3540
    3641namespace WTF {
     
    8388
    8489using SignalHandler = Function<SignalAction(Signal, SigInfo&, PlatformRegisters&)>;
     90using SignalHandlerMemory = std::aligned_storage<sizeof(SignalHandler), std::alignment_of<SignalHandler>::value>::type;
    8591
    86 // Call this method whenever you want to install a signal handler. It's ok to call this function lazily.
     92struct SignalHandlers {
     93    static void initialize();
     94
     95    void add(Signal, SignalHandler&&);
     96    template<typename Func>
     97    void forEachHandler(Signal, const Func&) const;
     98
     99    static constexpr size_t numberOfSignals = static_cast<size_t>(Signal::NumberOfSignals);
     100    static constexpr size_t maxNumberOfHandlers = 2;
     101
     102    static_assert(numberOfSignals < std::numeric_limits<uint8_t>::max());
     103
     104#if HAVE(MACH_EXCEPTIONS)
     105    mach_port_t exceptionPort;
     106    exception_mask_t activeExceptions;
     107    bool useMach;
     108#endif
     109    uint8_t numberOfHandlers[numberOfSignals];
     110    SignalHandlerMemory handlers[numberOfSignals][maxNumberOfHandlers];
     111    struct sigaction oldActions[numberOfSignals];
     112};
     113
     114// Call this method whenever you want to install a signal handler. This function needs to be called
     115// before g_wtfConfig is frozen. After the g_wtfConfig is frozen, no additional signal handlers may
     116// be installed. Any attempt to do so will trigger a crash.
    87117// Note: Your signal handler will be called every time the handler for the desired signal is called.
    88118// Thus it is your responsibility to discern if the signal fired was yours.
    89 // This function is currently a one way street i.e. once installed, a signal handler cannot be uninstalled.
     119// This function is a one way street i.e. once installed, a signal handler cannot be uninstalled.
    90120WTF_EXPORT_PRIVATE void installSignalHandler(Signal, SignalHandler&&);
    91121
Note: See TracChangeset for help on using the changeset viewer.