Changeset 261591 in webkit


Ignore:
Timestamp:
May 12, 2020 5:17:19 PM (4 years ago)
Author:
mark.lam@apple.com
Message:

Cherry-pick r260165, r261538. rdar://problem/63156083

2020-04-15 Robin Morisset <rmorisset@apple.com>

Flaky Test: fetch/fetch-worker-crash.html
https://bugs.webkit.org/show_bug.cgi?id=187257
<rdar://problem/48527526>

Reviewed by Yusuke Suzuki.

Source/JavaScriptCore:

The crash is coming from setExceptionPorts which is inlined in WTF::registerThreadForMachExceptionHandling.
From the error message we know that the problem is an "invalid port right".
http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_set_exception_ports.html tells us that the "port right" is the third parameter to thread_set_exception_ports, which is exceptionPort in our case.
exceptionPort is a global variable defined at the top of Signals.cpp:

static mach_port_t exceptionPort;

It is set in exactly one place:

kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exceptionPort);

in a std::call_once, in startMachExceptionHandlerThread().
Note that startMachExceptionHandlerThread() is called from the main thread just before the point where we are stuck.. and there is no synchronization to make sure it completed and its effect is visible to the worker thread before it uses exceptionPort.

So I think the crash is due to this race between allocating exceptionPort and using it, resulting in an invalid exceptionPort being sometimes passed to the kernel.
So this patch is a simple speculative fix, by running startMachExceptionHandlerThread() in initializeThreading(), before JSLock()::lock() can be run.

  • runtime/InitializeThreading.cpp: (JSC::initializeThreading):

2020-05-11 Mark Lam <mark.lam@apple.com>

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

Make startMachExceptionHandlerThread visible so that we can make sure it is called whenever initializing JSC.

  • wtf/threads/Signals.cpp: (WTF::startMachExceptionHandlerThread):
  • wtf/threads/Signals.h:

2020-05-11 Mark Lam <mark.lam@apple.com>

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.
  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:
branches/safari-609-branch/Source
Files:
11 edited
2 copied

Legend:

Unmodified
Added
Removed
  • branches/safari-609-branch/Source/JavaScriptCore/ChangeLog

    r260329 r261591  
     12020-05-12  Mark Lam  <mark.lam@apple.com>
     2
     3        Cherry-pick r260165, r261538. rdar://problem/63156083
     4
     5    2020-04-15  Robin Morisset  <rmorisset@apple.com>
     6
     7            Flaky Test: fetch/fetch-worker-crash.html
     8            https://bugs.webkit.org/show_bug.cgi?id=187257
     9            <rdar://problem/48527526>
     10
     11            Reviewed by Yusuke Suzuki.
     12
     13            The crash is coming from setExceptionPorts which is inlined in WTF::registerThreadForMachExceptionHandling.
     14            From the error message we know that the problem is an "invalid port right".
     15            http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_set_exception_ports.html tells us that the "port right" is the third parameter to thread_set_exception_ports, which is exceptionPort in our case.
     16            exceptionPort is a global variable defined at the top of Signals.cpp:
     17              static mach_port_t exceptionPort;
     18            It is set in exactly one place:
     19              kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exceptionPort);
     20            in a std::call_once, in startMachExceptionHandlerThread().
     21            Note that startMachExceptionHandlerThread() is called from the main thread just before the point where we are stuck.. and there is no synchronization to make sure it completed and its effect is visible to the worker thread before it uses exceptionPort.
     22
     23            So I think the crash is due to this race between allocating exceptionPort and using it, resulting in an invalid exceptionPort being sometimes passed to the kernel.
     24            So this patch is a simple speculative fix, by running startMachExceptionHandlerThread() in initializeThreading(), before JSLock()::lock() can be run.
     25
     26            * runtime/InitializeThreading.cpp:
     27            (JSC::initializeThreading):
     28
     29    2020-05-11  Mark Lam  <mark.lam@apple.com>
     30
     31            Introduce WTF::Config and put Signal.cpp's init-once globals in it.
     32            https://bugs.webkit.org/show_bug.cgi?id=211729
     33            <rdar://problem/62938878>
     34
     35            Reviewed by Keith Miller and Saam Barati.
     36
     37            1. Initialize VMTraps' signals early now that we'll be freezing signals at the end
     38               of the first VM initialization.
     39
     40            2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading()
     41               to the bottom of the function.  This way, we'll also catch bugs which may cause
     42               us to jump into the middle of the function.
     43
     44               Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed
     45               after all initialization is done.  This guarantees that it will only be executed
     46               at the end.
     47
     48            3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze()
     49               for obvious reasons: freezing one should freeze the other.
     50
     51            * runtime/InitializeThreading.cpp:
     52            (JSC::initializeThreading):
     53            * runtime/JSCConfig.cpp:
     54            (JSC::Config::permanentlyFreeze):
     55            * runtime/VMTraps.cpp:
     56            (JSC::VMTraps::initializeSignals):
     57            * runtime/VMTraps.h:
     58
    1592020-04-18  Alex Christensen  <achristensen@webkit.org>
    260
  • branches/safari-609-branch/Source/JavaScriptCore/runtime/InitializeThreading.cpp

    r250725 r261591  
    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"
     
    5455#include <wtf/dtoa.h>
    5556#include <wtf/dtoa/cached-powers.h>
     57#include <wtf/threads/Signals.h>
    5658
    5759namespace JSC {
     
    6466
    6567    std::call_once(initializeThreadingOnceFlag, []{
    66         RELEASE_ASSERT(!g_jscConfig.initializeThreadingHasBeenCalled);
    67         g_jscConfig.initializeThreadingHasBeenCalled = true;
    68 
    6968        WTF::initializeThreading();
    7069        Options::initialize();
     
    10099        if (VM::isInMiniMode())
    101100            WTF::fastEnableMiniMode();
     101
     102#if HAVE(MACH_EXCEPTIONS)
     103        // JSLock::lock() can call registerThreadForMachExceptionHandling() which crashes if this has not been called first.
     104        WTF::startMachExceptionHandlerThread();
     105#endif
     106        VMTraps::initializeSignals();
     107
     108        WTF::compilerFence();
     109        RELEASE_ASSERT(!g_jscConfig.initializeThreadingHasBeenCalled);
     110        g_jscConfig.initializeThreadingHasBeenCalled = true;
    102111    });
    103112}
  • branches/safari-609-branch/Source/JavaScriptCore/runtime/JSCConfig.cpp

    r249808 r261591  
    2929#include <wtf/ResourceUsage.h>
    3030#include <wtf/StdLibExtras.h>
     31#include <wtf/WTFConfig.h>
    3132
    3233#if OS(DARWIN)
     
    5455void Config::permanentlyFreeze()
    5556{
     57    WTF::Config::permanentlyFreeze();
     58
    5659#if PLATFORM(COCOA)
    5760    RELEASE_ASSERT(roundUpToMultipleOf(vmPageSize(), ConfigSizeToProtect) == ConfigSizeToProtect);
  • branches/safari-609-branch/Source/JavaScriptCore/runtime/VMTraps.cpp

    r253613 r261591  
    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;
     
    296299
    297300#endif // ENABLE(SIGNAL_BASED_VM_TRAPS)
     301
     302void VMTraps::initializeSignals()
     303{
     304#if ENABLE(SIGNAL_BASED_VM_TRAPS)
     305    if (!Options::usePollingTraps())
     306        SignalSender::initializeSignals();
     307#endif
     308}
    298309
    299310void VMTraps::willDestroyVM()
  • branches/safari-609-branch/Source/JavaScriptCore/runtime/VMTraps.h

    r253613 r261591  
    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
  • branches/safari-609-branch/Source/WTF/ChangeLog

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

    r259002 r261591  
    182182                E4A0AD391A96245500536DF6 /* WorkQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A0AD371A96245500536DF6 /* WorkQueue.cpp */; };
    183183                E4A0AD3D1A96253C00536DF6 /* WorkQueueCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A0AD3C1A96253C00536DF6 /* WorkQueueCocoa.cpp */; };
     184                FE032AD22463E43B0012D7C7 /* WTFConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE032AD02463E43B0012D7C7 /* WTFConfig.cpp */; };
    184185                FE05FAFF1FE5007500093230 /* WTFAssertions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE05FAFE1FE5007500093230 /* WTFAssertions.cpp */; };
    185186                FE1E2C3B2240C06600F6B729 /* PtrTag.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE1E2C392240C05400F6B729 /* PtrTag.cpp */; };
     
    721722                EF7D6CD59D8642A8A0DA86AD /* StackTrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackTrace.h; sourceTree = "<group>"; };
    722723                F72BBDB107FA424886178B9E /* SymbolImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolImpl.cpp; sourceTree = "<group>"; };
     724                FE032AD02463E43B0012D7C7 /* WTFConfig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WTFConfig.cpp; sourceTree = "<group>"; };
     725                FE032AD12463E43B0012D7C7 /* WTFConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WTFConfig.h; sourceTree = "<group>"; };
    723726                FE05FAE61FDB214300093230 /* DumbPtrTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumbPtrTraits.h; sourceTree = "<group>"; };
    724727                FE05FAFE1FE5007500093230 /* WTFAssertions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WTFAssertions.cpp; sourceTree = "<group>"; };
     
    12711274                                E4A0AD381A96245500536DF6 /* WorkQueue.h */,
    12721275                                FE05FAFE1FE5007500093230 /* WTFAssertions.cpp */,
     1276                                FE032AD02463E43B0012D7C7 /* WTFConfig.cpp */,
     1277                                FE032AD12463E43B0012D7C7 /* WTFConfig.h */,
    12731278                                A36E16F7216FF828008DD87E /* WTFSemaphore.h */,
    12741279                        );
     
    17231728                                7AFEC6B11EB22B5900DADE36 /* UUID.cpp in Sources */,
    17241729                                E3149A39228BB43500BFA6C7 /* Vector.cpp in Sources */,
     1730                                FE032AD22463E43B0012D7C7 /* WTFConfig.cpp in Sources */,
    17251731                                0F66B2921DC97BAB004A1D3F /* WallTime.cpp in Sources */,
    17261732                                1FA47C8A152502DA00568D1B /* WebCoreThread.cpp in Sources */,
  • branches/safari-609-branch/Source/WTF/wtf/CMakeLists.txt

    r254865 r261591  
    271271    VectorHash.h
    272272    VectorTraits.h
     273    WTFConfig.h
    273274    WTFSemaphore.h
    274275    WallTime.h
     
    429430    Vector.cpp
    430431    WTFAssertions.cpp
     432    WTFConfig.cpp
    431433    WallTime.cpp
    432434    WordLock.cpp
  • branches/safari-609-branch/Source/WTF/wtf/Threading.cpp

    r261520 r261591  
    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)
     
    338340    static std::once_flag onceKey;
    339341    std::call_once(onceKey, [] {
     342        Config::AssertNotFrozenScope assertScope;
    340343        initializeRandomNumberGenerator();
    341344#if !HAVE(FAST_TLS) && !OS(WINDOWS)
     
    344347        initializeDates();
    345348        Thread::initializePlatformThreading();
     349#if USE(PTHREADS) && HAVE(MACHINE_CONTEXT)
     350        SignalHandlers::initialize();
     351#endif
    346352    });
    347353}
  • branches/safari-609-branch/Source/WTF/wtf/WTFConfig.h

    r261538 r261591  
    3535namespace WTF {
    3636
    37 constexpr size_t ConfigSizeToProtect = CeilingOnPageSize;
     37#if CPU(ARM64) || PLATFORM(WATCHOS)
     38constexpr size_t PageSize = 16 * KB;
     39#else
     40constexpr size_t PageSize = 4 * KB;
     41#endif
     42
     43constexpr size_t ConfigSizeToProtect = PageSize;
    3844
    3945struct Config {
  • branches/safari-609-branch/Source/WTF/wtf/threads/Signals.cpp

    r241583 r261591  
    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
    72 static void startMachExceptionHandlerThread()
     98void startMachExceptionHandlerThread()
    7399{
    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
  • branches/safari-609-branch/Source/WTF/wtf/threads/Signals.h

    r239427 r261591  
    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
     
    94124class Thread;
    95125void registerThreadForMachExceptionHandling(Thread&);
     126void startMachExceptionHandlerThread();
    96127
    97128void handleSignalsWithMach();
Note: See TracChangeset for help on using the changeset viewer.