Ignore:
Timestamp:
Apr 21, 2017, 11:35:42 AM (8 years ago)
Author:
[email protected]
Message:

Add signaling API
https://bugs.webkit.org/show_bug.cgi?id=170976

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Update various uses of sigaction to use the new signaling API.
Also switch VMTraps to use the thread message system instead of
rolling it's own.

  • jit/ExecutableAllocator.h:

(JSC::isJITPC):

  • runtime/VMTraps.cpp:

(JSC::installSignalHandler):
(JSC::VMTraps::VMTraps):
(JSC::VMTraps::SignalSender::send):
(JSC::handleSigusr1): Deleted.
(JSC::handleSigtrap): Deleted.
(JSC::installSignalHandlers): Deleted.

  • runtime/VMTraps.h:
  • tools/SigillCrashAnalyzer.cpp:

(JSC::installCrashHandler):
(JSC::handleCrash): Deleted.

  • wasm/WasmFaultSignalHandler.cpp:

(JSC::Wasm::trapHandler):
(JSC::Wasm::enableFastMemory):

Source/WTF:

This patch adds a bunch of new functionality to WTF. First, it add
a new data structure of a lockless bag. The LocklessBag class can
be used as either a multi-writer multi-reader lockless bag or a
multi-writer single consumer lockless bag.

Next, this patch adds an abstraction around sigaction in WTF.
Basically, you can add a handler, which can be an arbitrary
lambda. Although it should still be safe for the signal you are
handling. the signal handler manager will then do all the
appropriate handling of chaining:

In the SIGUSR case we always forward the signal to any other
non-default handler installed before us. We need to do this,
otherwise, since it's not possible to tell if a SIGUSR was
intended exlusively for our handlers. Signal handlers don't record
how many times they were sent only that there is at least one
unhandled signal.

In the faulting cases we require that every handle be able to
recognise a fault they installed, vs crashes. If none of our
handlers claim to have handled the fault we will forward the
fault. If a handler was installed before the first fault handler
we simply call that handler and rely on them to take the
appropriate action. If no handler was installed before our first
handler we restore the default handler and allow the fault to
happen again.

Finally, this patch adds a signal based messaging system. This
system allows the user to run an arbitrary lambda from the SIGUSR2
signal handler of any target WTF::Thread. This is already in use
for the VMTraps API which allows us to kill rogue VMs by sending
the VM's running WTF::Thread a SIGUSR and requesting it jetison
all optimized code and throw an uncatchable exception from all
function entries/loop backedges. In the future, we will also use
this API for Wasm to reset the instruction caches in currently
executing Wasm threads.

  • WTF.xcodeproj/project.pbxproj:
  • wtf/Atomics.h:

(WTF::Atomic::Atomic):

  • wtf/LocklessBag.h: Added.

(WTF::LocklessBag::LocklessBag):
(WTF::LocklessBag::add):
(WTF::LocklessBag::iterate):
(WTF::LocklessBag::consumeAll):

  • wtf/ThreadMessage.cpp: Added.

(WTF::ThreadMessageData::ThreadMessageData):
(WTF::initializeThreadMessages):
(WTF::sendMessageScoped):

  • wtf/ThreadMessage.h: Added.

(WTF::sendMessage):

  • wtf/Threading.cpp:

(WTF::initializeThreading):

  • wtf/Threading.h:

(WTF::Thread::threadMessages):

  • wtf/ThreadingPthreads.cpp:

(WTF::Thread::currentMayBeNull):
(WTF::Thread::current):
(WTF::Thread::signal):

  • wtf/threads/Signals.cpp: Added.

(WTF::jscSignalHandler):
(WTF::installSignalHandler):

  • wtf/threads/Signals.h: Added.

(WTF::toSystemSignal):
(WTF::fromSystemSignal):

Tools:

Add tests for ThreadMessages.

  • TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
  • TestWebKitAPI/Tests/WTF/ThreadMessages.cpp: Added.

(runThreadMessageTest):
(TEST):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/VMTraps.cpp

    r215522 r215620  
    4141#include "Watchdog.h"
    4242#include <wtf/ProcessID.h>
    43 
    44 #if OS(DARWIN)
    45 #include <signal.h>
    46 #endif
     43#include <wtf/ThreadMessage.h>
     44#include <wtf/threads/Signals.h>
    4745
    4846namespace JSC {
     
    5452
    5553#if ENABLE(SIGNAL_BASED_VM_TRAPS)
    56 
    57 struct sigaction originalSigusr1Action;
    58 struct sigaction originalSigtrapAction;
    5954
    6055struct SignalContext {
     
    133128}
    134129
    135 static void handleSigusr1(int signalNumber, siginfo_t* info, void* uap)
    136 {
    137     SignalContext context(static_cast<ucontext_t*>(uap)->uc_mcontext);
    138     auto activeVMAndStackBounds = findActiveVMAndStackBounds(context);
    139     if (activeVMAndStackBounds) {
     130static void installSignalHandler()
     131{
     132    installSignalHandler(Signal::Trap, [] (int, siginfo_t*, void* uap) -> SignalAction {
     133        SignalContext context(static_cast<ucontext_t*>(uap)->uc_mcontext);
     134
     135        if (!isJITPC(context.trapPC))
     136            return SignalAction::NotHandled;
     137
     138        // FIXME: This currently eats all traps including jit asserts we should make sure this
     139        // always works. https://bugs.webkit.org/show_bug.cgi?id=171039
     140        auto activeVMAndStackBounds = findActiveVMAndStackBounds(context);
     141        if (!activeVMAndStackBounds)
     142            return SignalAction::Handled; // Let the SignalSender try again later.
     143
    140144        VM* vm = activeVMAndStackBounds.value().vm;
    141145        if (vm) {
    142             StackBounds stackBounds = activeVMAndStackBounds.value().stackBounds;
    143146            VMTraps& traps = vm->traps();
    144             if (traps.needTrapHandling())
    145                 traps.tryInstallTrapBreakpoints(context, stackBounds);
    146         }
    147     }
    148 
    149     auto originalAction = originalSigusr1Action.sa_sigaction;
    150     if (originalAction)
    151         originalAction(signalNumber, info, uap);
    152 }
    153 
    154 static void handleSigtrap(int signalNumber, siginfo_t* info, void* uap)
    155 {
    156     SignalContext context(static_cast<ucontext_t*>(uap)->uc_mcontext);
    157     auto activeVMAndStackBounds = findActiveVMAndStackBounds(context);
    158     if (!activeVMAndStackBounds)
    159         return; // Let the SignalSender try again later.
    160 
    161     VM* vm = activeVMAndStackBounds.value().vm;
    162     if (vm) {
    163         VMTraps& traps = vm->traps();
    164         if (!traps.needTrapHandling())
    165             return; // The polling code beat us to handling the trap already.
    166 
    167         auto expectedSuccess = traps.tryJettisonCodeBlocksOnStack(context);
    168         if (!expectedSuccess)
    169             return; // Let the SignalSender try again later.
    170         if (expectedSuccess.value())
    171             return; // We've success jettison the codeBlocks.
    172     }
    173 
    174     // If we get here, then this SIGTRAP is not due to a VMTrap. Let's do the default action.
    175     auto originalAction = originalSigtrapAction.sa_sigaction;
    176     if (originalAction) {
    177         // It is always safe to just invoke the original handler using the sa_sigaction form
    178         // without checking for the SA_SIGINFO flag. If the original handler is of the
    179         // sa_handler form, it will just ignore the 2nd and 3rd arguments since sa_handler is a
    180         // subset of sa_sigaction. This is what the man pages says the OS does anyway.
    181         originalAction(signalNumber, info, uap);
    182     }
    183    
    184     // Pre-emptively restore the default handler but we may roll it back below.
    185     struct sigaction currentAction;
    186     struct sigaction defaultAction;
    187     defaultAction.sa_handler = SIG_DFL;
    188     sigfillset(&defaultAction.sa_mask);
    189     defaultAction.sa_flags = 0;
    190     sigaction(SIGTRAP, &defaultAction, &currentAction);
    191    
    192     if (currentAction.sa_sigaction != handleSigtrap) {
    193         // This means that there's a client handler installed after us. This also means
    194         // that the client handler thinks it was able to recover from the SIGTRAP, and
    195         // did not uninstall itself. We can't argue with this because the signal isn't
    196         // known to be from a VMTraps signal. Hence, restore the client handler
    197         // and keep going.
    198         sigaction(SIGTRAP, &currentAction, nullptr);
    199     }
    200 }
    201 
    202 static void installSignalHandlers()
    203 {
    204     typedef void (* SigactionHandler)(int, siginfo_t *, void *);
    205     struct sigaction action;
    206 
    207     action.sa_sigaction = reinterpret_cast<SigactionHandler>(handleSigusr1);
    208     sigfillset(&action.sa_mask);
    209     action.sa_flags = SA_SIGINFO;
    210     sigaction(SIGUSR1, &action, &originalSigusr1Action);
    211 
    212     action.sa_sigaction = reinterpret_cast<SigactionHandler>(handleSigtrap);
    213     sigfillset(&action.sa_mask);
    214     action.sa_flags = SA_SIGINFO;
    215     sigaction(SIGTRAP, &action, &originalSigtrapAction);
     147            if (!traps.needTrapHandling())
     148                return SignalAction::Handled; // The polling code beat us to handling the trap already.
     149
     150            auto expectedSuccess = traps.tryJettisonCodeBlocksOnStack(context);
     151            if (!expectedSuccess)
     152                return SignalAction::Handled; // Let the SignalSender try again later.
     153            if (expectedSuccess.value())
     154                return SignalAction::Handled; // We've success jettison the codeBlocks.
     155        }
     156
     157        return SignalAction::Handled;
     158    });
    216159}
    217160
     
    401344        static std::once_flag once;
    402345        std::call_once(once, [] {
    403             installSignalHandlers();
     346            installSignalHandler();
    404347        });
    405348    }
     
    461404            auto optionalOwnerThread = vm.ownerThread();
    462405            if (optionalOwnerThread) {
    463                 optionalOwnerThread.value()->signal(SIGUSR1);
     406                sendMessage(*optionalOwnerThread.value().get(), [] (siginfo_t*, ucontext_t* ucontext) -> void {
     407                    SignalContext context(ucontext->uc_mcontext);
     408                    auto activeVMAndStackBounds = findActiveVMAndStackBounds(context);
     409                    if (activeVMAndStackBounds) {
     410                        VM* vm = activeVMAndStackBounds.value().vm;
     411                        if (vm) {
     412                            StackBounds stackBounds = activeVMAndStackBounds.value().stackBounds;
     413                            VMTraps& traps = vm->traps();
     414                            if (traps.needTrapHandling())
     415                                traps.tryInstallTrapBreakpoints(context, stackBounds);
     416                        }
     417                    }
     418                });
    464419                break;
    465420            }
Note: See TracChangeset for help on using the changeset viewer.