Undo rollout in r217638 with bug fix
authorkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 Jun 2017 18:28:48 +0000 (18:28 +0000)
committerkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 Jun 2017 18:28:48 +0000 (18:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=172824

Unreviewed, reland patch with unused set_state code removed.

Source/JavaScriptCore:

* API/tests/ExecutionTimeLimitTest.cpp:
(dispatchTermitateCallback):
(testExecutionTimeLimit):
* runtime/JSLock.cpp:
(JSC::JSLock::didAcquireLock):
* runtime/Options.cpp:
(JSC::overrideDefaults):
(JSC::Options::initialize):
* runtime/Options.h:
* runtime/VMTraps.cpp:
(JSC::SignalContext::SignalContext):
(JSC::SignalContext::adjustPCToPointToTrappingInstruction):
(JSC::installSignalHandler):
(JSC::VMTraps::SignalSender::send):
* tools/SigillCrashAnalyzer.cpp:
(JSC::SignalContext::SignalContext):
(JSC::SignalContext::dump):
(JSC::installCrashHandler):
* wasm/WasmBBQPlan.cpp:
(JSC::Wasm::BBQPlan::compileFunctions):
* wasm/WasmFaultSignalHandler.cpp:
(JSC::Wasm::trapHandler):
(JSC::Wasm::enableFastMemory):
* wasm/WasmMachineThreads.cpp:
(JSC::Wasm::resetInstructionCacheOnAllThreads):

Source/WTF:

* Configurations/WTF.xcconfig:
* WTF.xcodeproj/project.pbxproj:
* wtf/Platform.h:
* wtf/PlatformRegisters.h:
(WTF::registersFromUContext):
* wtf/StackBounds.h:
(WTF::StackBounds::StackBounds):
* wtf/ThreadHolder.cpp:
(WTF::ThreadHolder::~ThreadHolder):
* wtf/ThreadMessage.cpp:
(WTF::sendMessageUsingSignal):
(WTF::sendMessageUsingMach):
(WTF::deliverMessagesUsingMach):
(WTF::sendMessageScoped):
* wtf/ThreadMessage.h:
(WTF::sendMessage):
* wtf/Threading.h:
(WTF::Thread::machThread):
* wtf/mac/MachExceptions.defs: Copied from Source/WTF/wtf/ThreadMessage.h.
* wtf/threads/Signals.cpp:
(WTF::startMachExceptionHandlerThread):
(WTF::fromMachException):
(WTF::toMachMask):
(WTF::handleSignalsWithMach):
(WTF::setExceptionPorts):
(WTF::activeThreads):
(WTF::registerThreadForMachExceptionHandling):
(WTF::unregisterThreadForMachExceptionHandling):
(WTF::installSignalHandler):
(WTF::jscSignalHandler):
* wtf/threads/Signals.h:

Tools:

* TestWebKitAPI/Tests/WTF/ThreadMessages.cpp:
(runThreadMessageTest):
(TEST):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@217669 268f45cc-cd09-0410-ab3c-d52691b4dbfc

25 files changed:
Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSLock.cpp
Source/JavaScriptCore/runtime/Options.cpp
Source/JavaScriptCore/runtime/Options.h
Source/JavaScriptCore/runtime/VMTraps.cpp
Source/JavaScriptCore/tools/SigillCrashAnalyzer.cpp
Source/JavaScriptCore/wasm/WasmBBQPlan.cpp
Source/JavaScriptCore/wasm/WasmFaultSignalHandler.cpp
Source/JavaScriptCore/wasm/WasmMachineThreads.cpp
Source/WTF/ChangeLog
Source/WTF/Configurations/WTF.xcconfig
Source/WTF/WTF.xcodeproj/project.pbxproj
Source/WTF/wtf/Platform.h
Source/WTF/wtf/PlatformRegisters.h
Source/WTF/wtf/StackBounds.h
Source/WTF/wtf/ThreadHolder.cpp
Source/WTF/wtf/ThreadMessage.cpp
Source/WTF/wtf/ThreadMessage.h
Source/WTF/wtf/Threading.h
Source/WTF/wtf/mac/MachExceptions.defs [new file with mode: 0644]
Source/WTF/wtf/threads/Signals.cpp
Source/WTF/wtf/threads/Signals.h
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WTF/ThreadMessages.cpp

index 85c272c..a3c39a7 100644 (file)
 #include "JSContextRefPrivate.h"
 #include "JavaScript.h"
 #include "Options.h"
+
 #include <chrono>
+#include <wtf/Atomics.h>
+#include <wtf/Condition.h>
 #include <wtf/CurrentTime.h>
+#include <wtf/Lock.h>
 #include <wtf/text/StringBuilder.h>
 
+#if HAVE(MACH_EXCEPTIONS)
+#include <dispatch/dispatch.h>
+#endif
+
 using namespace std::chrono;
 using JSC::Options;
 
@@ -77,6 +85,15 @@ static bool extendTerminateCallback(JSContextRef ctx, void*)
     return true;
 }
 
+#if HAVE(MACH_EXCEPTIONS)
+bool dispatchTerminateCallbackCalled = false;
+static bool dispatchTermitateCallback(JSContextRef, void*)
+{
+    dispatchTerminateCallbackCalled = true;
+    return true;
+}
+#endif
+
 struct TierOptions {
     const char* tier;
     unsigned timeLimitAdjustmentMillis;
@@ -365,6 +382,65 @@ int testExecutionTimeLimit()
             }
         }
 
+#if HAVE(MACH_EXCEPTIONS)
+        /* Test script timeout from dispatch queue: */
+        timeLimit = (100 + tierAdjustmentMillis) / 1000.0;
+        JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, dispatchTermitateCallback, 0);
+        {
+            unsigned timeAfterWatchdogShouldHaveFired = 300 + tierAdjustmentMillis;
+
+            StringBuilder scriptBuilder;
+            scriptBuilder.appendLiteral("function foo() { var startTime = currentCPUTime(); while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > ");
+            scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0);
+            scriptBuilder.appendLiteral(") break; } } foo();");
+
+            JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data());
+            exception = nullptr;
+            dispatchTerminateCallbackCalled = false;
+
+            // We have to do this since blocks can only capture things as const.
+            JSGlobalContextRef& contextRef = context;
+            JSStringRef& scriptRef = script;
+            JSValueRef& exceptionRef = exception;
+
+            Lock syncLock;
+            Lock& syncLockRef = syncLock;
+            Condition synchronize;
+            Condition& synchronizeRef = synchronize;
+            bool didSynchronize = false;
+            bool& didSynchronizeRef = didSynchronize;
+
+            std::chrono::microseconds startTime;
+            std::chrono::microseconds endTime;
+
+            std::chrono::microseconds& startTimeRef = startTime;
+            std::chrono::microseconds& endTimeRef = endTime;
+
+            dispatch_group_t group = dispatch_group_create();
+            dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
+                startTimeRef = currentCPUTime();
+                JSEvaluateScript(contextRef, scriptRef, nullptr, nullptr, 1, &exceptionRef);
+                endTimeRef = currentCPUTime();
+                auto locker = WTF::holdLock(syncLockRef);
+                didSynchronizeRef = true;
+                synchronizeRef.notifyAll();
+            });
+
+            auto locker = holdLock(syncLock);
+            synchronize.wait(syncLock, [&] { return didSynchronize; });
+
+            if (((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired)) && dispatchTerminateCallbackCalled)
+                printf("PASS: %s script on dispatch queue timed out as expected.\n", tierOptions.tier);
+            else {
+                if ((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired))
+                    printf("FAIL: %s script on dispatch queue did not time out as expected.\n", tierOptions.tier);
+                if (!shouldTerminateCallbackWasCalled)
+                    printf("FAIL: %s script on dispatch queue timeout callback was not called.\n", tierOptions.tier);
+                failed = true;
+            }
+        }
+#endif
+
         JSGlobalContextRelease(context);
 
         Options::setOptions(savedOptionsBuilder.toString().ascii().data());
index b1056b4..6b42b48 100644 (file)
@@ -1,3 +1,36 @@
+2017-06-01  Keith Miller  <keith_miller@apple.com>
+
+        Undo rollout in r217638 with bug fix
+        https://bugs.webkit.org/show_bug.cgi?id=172824
+
+        Unreviewed, reland patch with unused set_state code removed.
+
+        * API/tests/ExecutionTimeLimitTest.cpp:
+        (dispatchTermitateCallback):
+        (testExecutionTimeLimit):
+        * runtime/JSLock.cpp:
+        (JSC::JSLock::didAcquireLock):
+        * runtime/Options.cpp:
+        (JSC::overrideDefaults):
+        (JSC::Options::initialize):
+        * runtime/Options.h:
+        * runtime/VMTraps.cpp:
+        (JSC::SignalContext::SignalContext):
+        (JSC::SignalContext::adjustPCToPointToTrappingInstruction):
+        (JSC::installSignalHandler):
+        (JSC::VMTraps::SignalSender::send):
+        * tools/SigillCrashAnalyzer.cpp:
+        (JSC::SignalContext::SignalContext):
+        (JSC::SignalContext::dump):
+        (JSC::installCrashHandler):
+        * wasm/WasmBBQPlan.cpp:
+        (JSC::Wasm::BBQPlan::compileFunctions):
+        * wasm/WasmFaultSignalHandler.cpp:
+        (JSC::Wasm::trapHandler):
+        (JSC::Wasm::enableFastMemory):
+        * wasm/WasmMachineThreads.cpp:
+        (JSC::Wasm::resetInstructionCacheOnAllThreads):
+
 2017-06-01  Guillaume Emont  <guijemont@igalia.com>
 
         [JSC][MIPS] SamplingProfiler::timerLoop() sleeps for 4000+ seconds
index c175ae0..31e2db4 100644 (file)
@@ -30,6 +30,8 @@
 #include "SamplingProfiler.h"
 #include "WasmMachineThreads.h"
 #include <thread>
+#include <wtf/Threading.h>
+#include <wtf/threads/Signals.h>
 
 namespace JSC {
 
@@ -148,6 +150,10 @@ void JSLock::didAcquireLock()
     Wasm::startTrackingCurrentThread();
 #endif
 
+#if HAVE(MACH_EXCEPTIONS)
+    registerThreadForMachExceptionHandling(&Thread::current());
+#endif
+
     m_vm->traps().notifyGrabAllLocks();
 
 #if ENABLE(SAMPLING_PROFILER)
index 3757786..9f12df9 100644 (file)
@@ -43,6 +43,7 @@
 #include <wtf/StdLibExtras.h>
 #include <wtf/StringExtras.h>
 #include <wtf/text/StringBuilder.h>
+#include <wtf/threads/Signals.h>
 
 #if PLATFORM(COCOA)
 #include <crt_externs.h>
@@ -358,6 +359,10 @@ static void overrideDefaults()
 #if !ENABLE(WEBASSEMBLY_FAST_MEMORY)
     Options::useWebAssemblyFastMemory() = false;
 #endif
+
+#if !HAVE(MACH_EXCEPTIONS)
+    Options::useMachForExceptions() = false;
+#endif
 }
 
 static void recomputeDependentOptions()
@@ -550,6 +555,11 @@ void Options::initialize()
 
             dumpOptionsIfNeeded();
             ensureOptionsAreCoherent();
+
+#if HAVE(MACH_EXCEPTIONS)
+            if (Options::useMachForExceptions())
+                handleSignalsWithMach();
+#endif
         });
 }
 
index 4ad16ea..a0935d2 100644 (file)
@@ -423,6 +423,8 @@ typedef const char* optionString;
     v(unsigned, watchdog, 0, Normal, "watchdog timeout (0 = Disabled, N = a timeout period of N milliseconds)") \
     v(bool, usePollingTraps, false, Normal, "use polling (instead of signalling) VM traps") \
     \
+    v(bool, useMachForExceptions, true, Normal, "Use mach exceptions rather than signals to handle faults and pass thread messages. (This does nothing on platforms without mach)") \
+    \
     v(bool, useICStats, false, Normal, nullptr) \
     \
     v(unsigned, prototypeHitCountForLLIntCaching, 2, Normal, "Number of prototype property hits before caching a prototype in the LLInt. A count of 0 means never cache.") \
@@ -446,6 +448,7 @@ typedef const char* optionString;
     v(unsigned, webAssemblyBBQOptimizationLevel, 1, Normal, "B3 Optimization level for BBQ Web Assembly module compilations.") \
     v(unsigned, webAssemblyOMGOptimizationLevel, Options::defaultB3OptLevel(), Normal, "B3 Optimization level for OMG Web Assembly module compilations.") \
     \
+    v(bool, useBBQTierUpChecks, true, Normal, "Enables tier up checks for our BBQ code.") \
     v(unsigned, webAssemblyOMGTierUpCount, 5000, Normal, "The countdown before we tier up a function to OMG.") \
     v(unsigned, webAssemblyLoopDecrement, 15, Normal, "The amount the tier up countdown is decremented on each loop backedge.") \
     v(unsigned, webAssemblyFunctionEntryDecrement, 1, Normal, "The amount the tier up countdown is decremented on each function entry.") \
index 1baace6..8c57c45 100644 (file)
@@ -53,11 +53,11 @@ ALWAYS_INLINE VM& VMTraps::vm() const
 #if ENABLE(SIGNAL_BASED_VM_TRAPS)
 
 struct SignalContext {
-    SignalContext(mcontext_t& mcontext)
-        : mcontext(mcontext)
-        , trapPC(MachineContext::instructionPointer(mcontext))
-        , stackPointer(MachineContext::stackPointer(mcontext))
-        , framePointer(MachineContext::framePointer(mcontext))
+    SignalContext(PlatformRegisters& registers)
+        : registers(registers)
+        , trapPC(MachineContext::instructionPointer(registers))
+        , stackPointer(MachineContext::stackPointer(registers))
+        , framePointer(MachineContext::framePointer(registers))
     {
 #if CPU(X86_64) || CPU(X86)
         // On X86_64, SIGTRAP reports the address after the trapping PC. So, dec by 1.
@@ -68,11 +68,11 @@ struct SignalContext {
     void adjustPCToPointToTrappingInstruction()
     {
 #if CPU(X86_64) || CPU(X86)
-        MachineContext::instructionPointer(mcontext) = trapPC;
+        MachineContext::instructionPointer(registers) = trapPC;
 #endif
     }
 
-    mcontext_t& mcontext;
+    PlatformRegisters& registers;
     void* trapPC;
     void* stackPointer;
     void* framePointer;
@@ -130,8 +130,8 @@ static Expected<VMAndStackBounds, VMTraps::Error> findActiveVMAndStackBounds(Sig
 
 static void installSignalHandler()
 {
-    installSignalHandler(Signal::Trap, [] (int, siginfo_t*, void* uap) -> SignalAction {
-        SignalContext context(static_cast<ucontext_t*>(uap)->uc_mcontext);
+    installSignalHandler(Signal::Trap, [] (Signal, SigInfo&, PlatformRegisters& registers) -> SignalAction {
+        SignalContext context(registers);
 
         if (!isJITPC(context.trapPC))
             return SignalAction::NotHandled;
@@ -404,8 +404,8 @@ void VMTraps::SignalSender::send()
             VM& vm = *m_vm;
             auto optionalOwnerThread = vm.ownerThread();
             if (optionalOwnerThread) {
-                sendMessage(*optionalOwnerThread.value().get(), [] (siginfo_t*, ucontext_t* ucontext) -> void {
-                    SignalContext context(ucontext->uc_mcontext);
+                sendMessage(*optionalOwnerThread.value().get(), [] (PlatformRegisters& registers) -> void {
+                    SignalContext context(registers);
                     auto activeVMAndStackBounds = findActiveVMAndStackBounds(context);
                     if (activeVMAndStackBounds) {
                         VM* vm = activeVMAndStackBounds.value().vm;
index 4adaeff..71a6e42 100644 (file)
@@ -78,11 +78,11 @@ private:
 #endif // USE(OS_LOG)
 
 struct SignalContext {
-    SignalContext(mcontext_t& mcontext)
-        : mcontext(mcontext)
-        , machinePC(MachineContext::instructionPointer(mcontext))
-        , stackPointer(MachineContext::stackPointer(mcontext))
-        , framePointer(MachineContext::framePointer(mcontext))
+    SignalContext(PlatformRegisters& registers)
+        : registers(registers)
+        , machinePC(MachineContext::instructionPointer(registers))
+        , stackPointer(MachineContext::stackPointer(registers))
+        , framePointer(MachineContext::framePointer(registers))
     { }
 
     void dump()
@@ -112,7 +112,7 @@ struct SignalContext {
         v(gs)
 
 #define DUMP_REGISTER(__reg) \
-        log("Register " #__reg ": %p", reinterpret_cast<void*>(mcontext->__ss.__##__reg));
+        log("Register " #__reg ": %p", reinterpret_cast<void*>(registers.__##__reg));
         FOR_EACH_REGISTER(DUMP_REGISTER)
 #undef FOR_EACH_REGISTER
 
@@ -120,20 +120,20 @@ struct SignalContext {
         int i;
         for (i = 0; i < 28; i += 4) {
             log("x%d: %016llx x%d: %016llx x%d: %016llx x%d: %016llx",
-                i, mcontext->__ss.__x[i],
-                i+1, mcontext->__ss.__x[i+1],
-                i+2, mcontext->__ss.__x[i+2],
-                i+3, mcontext->__ss.__x[i+3]);
+                i, registers.__x[i],
+                i+1, registers.__x[i+1],
+                i+2, registers.__x[i+2],
+                i+3, registers.__x[i+3]);
         }
         ASSERT(i < 29);
         log("x%d: %016llx fp: %016llx lr: %016llx",
-            i, mcontext->__ss.__x[i], mcontext->__ss.__fp, mcontext->__ss.__lr);
+            i, registers.__x[i], registers.__fp, registers.__lr);
         log("sp: %016llx pc: %016llx cpsr: %08x",
-            mcontext->__ss.__sp, mcontext->__ss.__pc, mcontext->__ss.__cpsr);
+            registers.__sp, registers.__pc, registers.__cpsr);
 #endif
     }
 
-    mcontext_t& mcontext;
+    PlatformRegisters& registers;
     void* machinePC;
     void* stackPointer;
     void* framePointer;
@@ -142,8 +142,8 @@ struct SignalContext {
 static void installCrashHandler()
 {
 #if CPU(X86_64) || CPU(ARM64)
-    installSignalHandler(Signal::Ill, [] (int, siginfo_t*, void* uap) {
-        SignalContext context(static_cast<ucontext_t*>(uap)->uc_mcontext);
+    installSignalHandler(Signal::Ill, [] (Signal, SigInfo&, PlatformRegisters& registers) {
+        SignalContext context(registers);
 
         if (!isJITPC(context.machinePC))
             return SignalAction::NotHandled;
index 1dd0cd1..b1b598d 100644 (file)
@@ -242,7 +242,7 @@ void BBQPlan::compileFunctions(CompilationEffort effort)
         ASSERT(validateFunction(functionStart, functionLength, signature, m_moduleInformation.get()));
 
         m_unlinkedWasmToWasmCalls[functionIndex] = Vector<UnlinkedWasmToWasmCall>();
-        TierUpCount* tierUp = &m_tierUpCounts[functionIndex];
+        TierUpCount* tierUp = Options::useBBQTierUpChecks() ? &m_tierUpCounts[functionIndex] : nullptr;
         auto parseAndCompileResult = parseAndCompile(m_compilationContexts[functionIndex], functionStart, functionLength, signature, m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, CompilationMode::BBQMode, functionIndex, tierUp);
 
         if (UNLIKELY(!parseAndCompileResult)) {
index 2e0c99a..264c34d 100644 (file)
@@ -52,9 +52,8 @@ static LazyNeverDestroyed<HashSet<std::tuple<void*, void*>>> codeLocations; // (
 
 static bool fastHandlerInstalled { false };
 
-static SignalAction trapHandler(int, siginfo_t* sigInfo, void* ucontext)
+static SignalAction trapHandler(Signal, SigInfo& sigInfo, PlatformRegisters& context)
 {
-    mcontext_t& context = static_cast<ucontext_t*>(ucontext)->uc_mcontext;
     void* faultingInstruction = MachineContext::instructionPointer(context);
     dataLogLnIf(verbose, "starting handler for fault at: ", RawPointer(faultingInstruction));
 
@@ -64,7 +63,7 @@ static SignalAction trapHandler(int, siginfo_t* sigInfo, void* ucontext)
     if (isJITPC(faultingInstruction)) {
         bool faultedInActiveFastMemory = false;
         {
-            void* faultingAddress = sigInfo->si_addr;
+            void* faultingAddress = sigInfo.faultingAddress;
             dataLogLnIf(verbose, "checking faulting address: ", RawPointer(faultingAddress), " is in an active fast memory");
             faultedInActiveFastMemory = Wasm::Memory::addressIsInActiveFastMemory(faultingAddress);
         }
@@ -124,11 +123,11 @@ void enableFastMemory()
             return;
 
 #if ENABLE(WEBASSEMBLY_FAST_MEMORY)
-        installSignalHandler(Signal::Bus, [] (int signal, siginfo_t* sigInfo, void* ucontext) {
+        installSignalHandler(Signal::Bus, [] (Signal signal, SigInfo& sigInfo, PlatformRegisters& ucontext) {
             return trapHandler(signal, sigInfo, ucontext);
         });
 
-        installSignalHandler(Signal::SegV, [] (int signal, siginfo_t* sigInfo, void* ucontext) {
+        installSignalHandler(Signal::SegV, [] (Signal signal, SigInfo& sigInfo, PlatformRegisters& ucontext) {
             return trapHandler(signal, sigInfo, ucontext);
         });
 
index 5aac87a..0a367fd 100644 (file)
@@ -31,6 +31,7 @@
 #include "MachineStackMarker.h"
 #include <wtf/NeverDestroyed.h>
 #include <wtf/ThreadMessage.h>
+#include <wtf/threads/Signals.h>
 
 namespace JSC { namespace Wasm {
 
@@ -57,7 +58,7 @@ void resetInstructionCacheOnAllThreads()
 
     const DoublyLinkedList<MachineThreads::MachineThread>& threads = wasmThreads().threadsListHead(locker);
     for (const auto* thread = threads.head(); thread; thread = thread->next()) {
-        sendMessage(thread->m_thread.get(), [] (siginfo_t*, ucontext_t*) {
+        sendMessage(thread->m_thread.get(), [] (const PlatformRegisters&) {
             // It's likely that the signal handler will already reset the instruction cache but we might as well be sure.
             WTF::crossModifyingCodeFence();
         });
index e96f879..560753e 100644 (file)
@@ -1,3 +1,42 @@
+2017-06-01  Keith Miller  <keith_miller@apple.com>
+
+        Undo rollout in r217638 with bug fix
+        https://bugs.webkit.org/show_bug.cgi?id=172824
+
+        Unreviewed, reland patch with unused set_state code removed.
+
+        * Configurations/WTF.xcconfig:
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/Platform.h:
+        * wtf/PlatformRegisters.h:
+        (WTF::registersFromUContext):
+        * wtf/StackBounds.h:
+        (WTF::StackBounds::StackBounds):
+        * wtf/ThreadHolder.cpp:
+        (WTF::ThreadHolder::~ThreadHolder):
+        * wtf/ThreadMessage.cpp:
+        (WTF::sendMessageUsingSignal):
+        (WTF::sendMessageUsingMach):
+        (WTF::deliverMessagesUsingMach):
+        (WTF::sendMessageScoped):
+        * wtf/ThreadMessage.h:
+        (WTF::sendMessage):
+        * wtf/Threading.h:
+        (WTF::Thread::machThread):
+        * wtf/mac/MachExceptions.defs: Copied from Source/WTF/wtf/ThreadMessage.h.
+        * wtf/threads/Signals.cpp:
+        (WTF::startMachExceptionHandlerThread):
+        (WTF::fromMachException):
+        (WTF::toMachMask):
+        (WTF::handleSignalsWithMach):
+        (WTF::setExceptionPorts):
+        (WTF::activeThreads):
+        (WTF::registerThreadForMachExceptionHandling):
+        (WTF::unregisterThreadForMachExceptionHandling):
+        (WTF::installSignalHandler):
+        (WTF::jscSignalHandler):
+        * wtf/threads/Signals.h:
+
 2017-05-31  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r217611 and r217631.
index 421efd9..af199ce 100644 (file)
@@ -27,3 +27,6 @@ PRODUCT_NAME = WTF;
 
 GCC_SYMBOLS_PRIVATE_EXTERN = YES;
 STRIP_INSTALLED_PRODUCT = NO;
+
+EXCLUDED_SOURCE_FILE_NAMES_ = MachExceptions.defs
+EXCLUDED_SOURCE_FILE_NAMES[sdk=iphoneos*] = $(EXCLUDED_SOURCE_FILE_NAMES_$(USE_INTERNAL_SDK))
index 57b3e0f..d62a793 100644 (file)
@@ -64,6 +64,7 @@
                52183012C99E476A84EEBEA8 /* SymbolImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F72BBDB107FA424886178B9E /* SymbolImpl.cpp */; };
                5311BD531EA71CAD00525281 /* Signals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5311BD511EA71CAD00525281 /* Signals.cpp */; };
                5311BD5C1EA822F900525281 /* ThreadMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5311BD5B1EA822F900525281 /* ThreadMessage.cpp */; };
+               53534F2A1EC0E10E00141B2F /* MachExceptions.defs in Sources */ = {isa = PBXBuildFile; fileRef = 53534F291EC0E10E00141B2F /* MachExceptions.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; };
                70A993FE1AD7151300FA615B /* SymbolRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70A993FC1AD7151300FA615B /* SymbolRegistry.cpp */; };
                70ECA60D1B02426800449739 /* AtomicStringImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70ECA60A1B02426800449739 /* AtomicStringImpl.cpp */; };
                7AFEC6B11EB22B5900DADE36 /* UUID.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7AFEC6B01EB22B5900DADE36 /* UUID.cpp */; };
                5311BD571EA7E1A100525281 /* Signals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Signals.h; sourceTree = "<group>"; };
                5311BD591EA81A9600525281 /* ThreadMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadMessage.h; sourceTree = "<group>"; };
                5311BD5B1EA822F900525281 /* ThreadMessage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadMessage.cpp; sourceTree = "<group>"; };
+               53534F291EC0E10E00141B2F /* MachExceptions.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = MachExceptions.defs; sourceTree = "<group>"; };
                539EB0621D55284200C82EF7 /* LEBDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LEBDecoder.h; sourceTree = "<group>"; };
                53EC253C1E95AD30000831B9 /* PriorityQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PriorityQueue.h; sourceTree = "<group>"; };
                553071C91C40427200384898 /* TinyLRUCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TinyLRUCache.h; sourceTree = "<group>"; };
                        children = (
                                1A428B8B1C8F89DD0051E9EB /* AppKitCompatibilityDeclarations.h */,
                                1ACADD821884480100D8B71D /* DeprecatedSymbolsUsedBySafari.mm */,
+                               53534F291EC0E10E00141B2F /* MachExceptions.defs */,
                                A8A472C5151A825A004123FF /* MainThreadMac.mm */,
                        );
                        path = mac;
                                143F611F1565F0F900DB514A /* RAMSize.cpp in Sources */,
                                A3B725EC987446AD93F1A440 /* RandomDevice.cpp in Sources */,
                                A8A47414151A825B004123FF /* RandomNumber.cpp in Sources */,
+                               53534F2A1EC0E10E00141B2F /* MachExceptions.defs in Sources */,
                                A8A4741A151A825B004123FF /* RefCountedLeakCounter.cpp in Sources */,
                                2CDED0F318115C85004DBA70 /* RunLoop.cpp in Sources */,
                                2CDED0EF18115C38004DBA70 /* RunLoopCF.cpp in Sources */,
index 45bd8a8..0c956f4 100644 (file)
 #define HAVE_READLINE 1
 #define HAVE_SYS_TIMEB_H 1
 
+#if __has_include(<mach/mach_exc.defs>) && !(PLATFORM(WATCHOS) || PLATFORM(APPLETV))
+#define HAVE_MACH_EXCEPTIONS 1
+#endif
+
 #if !PLATFORM(GTK)
 #define USE_ACCELERATE 1
 #endif
index d5b5abc..84bd893 100644 (file)
 #pragma once
 
 #include <wtf/Platform.h>
+#include <wtf/StdLibExtras.h>
 
 #if OS(DARWIN)
 #include <mach/thread_act.h>
+#include <signal.h>
 #elif OS(WINDOWS)
 #include <windows.h>
 #else
@@ -55,6 +57,11 @@ typedef arm_thread_state64_t PlatformRegisters;
 #error Unknown Architecture
 #endif
 
+inline PlatformRegisters& registersFromUContext(ucontext_t* ucontext)
+{
+    return ucontext->uc_mcontext->__ss;
+}
+
 #elif OS(WINDOWS)
 
 using PlatformRegisters = CONTEXT;
@@ -65,6 +72,11 @@ struct PlatformRegisters {
     mcontext_t machineContext;
 };
 
+inline PlatformRegisters& registersFromUContext(ucontext_t* ucontext)
+{
+    return *bitwise_cast<PlatformRegisters*>(&ucontext->uc_mcontext);
+}
+
 #else
 
 struct PlatformRegisters {
index 554604f..cd62c14 100644 (file)
@@ -54,7 +54,6 @@ public:
         : m_origin(origin)
         , m_bound(end)
     {
-        checkConsistency();
     }
 
     void* origin() const
index e2a31be..977d1df 100644 (file)
 
 #include "Threading.h"
 
+#include <wtf/threads/Signals.h>
+
 namespace WTF {
 
 ThreadSpecificKey ThreadHolder::m_key = InvalidThreadSpecificKey;
 
 ThreadHolder::~ThreadHolder()
 {
+#if HAVE(MACH_EXCEPTIONS)
+    unregisterThreadForMachExceptionHandling(&m_thread.get());
+#endif
     m_thread->didExit();
 }
 
index f14bc45..64e775e 100644 (file)
@@ -36,6 +36,9 @@
 #include <wtf/Locker.h>
 #include <wtf/threads/Signals.h>
 
+#if HAVE(MACH_EXCEPTIONS)
+#include <mach/thread_act.h>
+#endif
 
 namespace WTF {
 
@@ -83,12 +86,12 @@ void initializeThreadMessages()
 }
 
 SUPPRESS_ASAN
-MessageStatus sendMessageScoped(Thread& thread, const ThreadMessage& message)
+static MessageStatus sendMessageUsingSignal(Thread& thread, const ThreadMessage& message)
 {
     constexpr Signal signal = Signal::Usr;
     static std::once_flag once;
     std::call_once(once, [] {
-        installSignalHandler(signal, [] (int, siginfo_t* info, void* uap) {
+        installSignalHandler(signal, [] (Signal, SigInfo&, PlatformRegisters& registers) {
             Thread* thread = Thread::currentMayBeNull();
 
             if (!thread) {
@@ -98,7 +101,7 @@ MessageStatus sendMessageScoped(Thread& thread, const ThreadMessage& message)
 
             // Node should be deleted in the sender thread. Deleting Nodes in signal handler causes dead lock.
             thread->threadMessages().consumeAllWithNode([&] (ThreadMessageData* data, Node* node) {
-                data->message(info, static_cast<ucontext_t*>(uap));
+                data->message(registers);
                 // By setting ran variable, (1) the sender acknowledges the completion and
                 // (2) gets the Node to be deleted.
                 data->ran.store(node);
@@ -156,6 +159,43 @@ MessageStatus sendMessageScoped(Thread& thread, const ThreadMessage& message)
     RELEASE_ASSERT_NOT_REACHED();
 }
 
+#if HAVE(MACH_EXCEPTIONS)
+static MessageStatus sendMessageUsingMach(Thread& thread, const ThreadMessage& message)
+{
+    static StaticLock messageLock;
+    auto lockholder = holdLock(messageLock);
+
+    auto result = thread.suspend();
+    if (!result)
+        return MessageStatus::ThreadExited;
+
+    PlatformRegisters registers;
+    thread.getRegisters(registers);
+
+    message(registers);
+
+    thread.resume();
+    return MessageStatus::MessageRan;
+}
+
+static bool useMach = false;
+void deliverMessagesUsingMach()
+{
+    useMach = true;
+}
+
+#endif // HAVE(MACH_EXCEPTIONS)
+
+MessageStatus sendMessageScoped(Thread& thread, const ThreadMessage& message)
+{
+#if HAVE(MACH_EXCEPTIONS)
+    if (useMach)
+        return sendMessageUsingMach(thread, message);
+#endif
+    return sendMessageUsingSignal(thread, message);
+}
+
+
 } // namespace WTF
 
 #endif // USE(PTHREADS)
index 268add4..0f74551 100644 (file)
@@ -36,7 +36,7 @@ namespace WTF {
 void initializeThreadMessages();
 
 class ThreadMessageData;
-using ThreadMessage = ScopedLambda<void(siginfo_t*, ucontext_t*)>;
+using ThreadMessage = ScopedLambda<void(PlatformRegisters&)>;
 
 enum class MessageStatus {
     MessageRan,
@@ -51,10 +51,14 @@ WTF_EXPORT_PRIVATE MessageStatus sendMessageScoped(Thread&, const ThreadMessage&
 template<typename Functor>
 MessageStatus sendMessage(Thread& targetThread, const Functor& func)
 {
-    auto lambda = scopedLambdaRef<void(siginfo_t*, ucontext_t*)>(func);
+    auto lambda = scopedLambdaRef<void(PlatformRegisters&)>(func);
     return sendMessageScoped(targetThread, lambda);
 }
 
+#if HAVE(MACH_EXCEPTIONS)
+void deliverMessagesUsingMach();
+#endif
+
 } // namespace WTF
 
 using WTF::sendMessage;
index d2e536d..3514e8c 100644 (file)
@@ -138,6 +138,10 @@ public:
 
 #if USE(PTHREADS)
     LocklessBag<ThreadMessageData*>& threadMessages() { return m_threadMessages; }
+
+#if OS(DARWIN)
+    mach_port_t machThread() { return m_platformThread; }
+#endif
 #endif
 
 protected:
diff --git a/Source/WTF/wtf/mac/MachExceptions.defs b/Source/WTF/wtf/mac/MachExceptions.defs
new file mode 100644 (file)
index 0000000..4205742
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 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 <mach/mach_exc.defs>
index 855b28b..7f24706 100644 (file)
 
 #if USE(PTHREADS)
 
+#if HAVE(MACH_EXCEPTIONS)
+extern "C" {
+#include "MachExceptionsServer.h"
+};
+#endif
+
 #include <cstdio>
 #include <mutex>
 #include <signal.h>
+
+#if HAVE(MACH_EXCEPTIONS)
+#include <dispatch/dispatch.h>
+#include <mach/mach.h>
+#include <mach/thread_act.h>
+#endif
+
 #include <wtf/Atomics.h>
 #include <wtf/DataLog.h>
+#include <wtf/HashSet.h>
 #include <wtf/LocklessBag.h>
 #include <wtf/NeverDestroyed.h>
+#include <wtf/ThreadMessage.h>
+#include <wtf/Threading.h>
+
 
 namespace WTF {
 
+    
 static LazyNeverDestroyed<LocklessBag<SignalHandler>> handlers[static_cast<size_t>(Signal::NumberOfSignals)] = { };
-static struct sigaction oldActions[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)];
+
+#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
+// 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;
+
+static void startMachExceptionHandlerThread()
+{
+    static std::once_flag once;
+    std::call_once(once, [] {
+        if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exceptionPort) != KERN_SUCCESS)
+            CRASH();
+
+        if (mach_port_insert_right(mach_task_self(), exceptionPort, exceptionPort, MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS)
+            CRASH();
+
+        // It's not clear that this needs to be the high priority queue but it should be rare and it might be
+        // handling exceptions from high priority threads. Anyway, our handlers should be very fast anyway so it's
+        // probably not the end of the world if we handle a low priority exception on a high priority queue.
+        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
+        dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, exceptionPort, 0, queue);
+        RELEASE_ASSERT_WITH_MESSAGE(source, "We need to ensure our source was created.");
+
+        // We should never cancel our handler since it's a permanent thing so we don't add a cancel handler.
+        dispatch_source_set_event_handler(source, ^{
+            // the leaks tool will get mad at us if we don't pretend to watch the source.
+            UNUSED_PARAM(source);
+            union Message {
+                mach_msg_header_t header;
+                char data[maxMessageSize];
+            };
+            Message messageHeaderIn;
+            Message messageHeaderOut;
+
+            kern_return_t messageResult = mach_msg(&messageHeaderIn.header, MACH_RCV_MSG, 0, maxMessageSize, exceptionPort, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+            if (messageResult == KERN_SUCCESS) {
+                if (!mach_exc_server(&messageHeaderIn.header, &messageHeaderOut.header))
+                    CRASH();
+
+                messageResult = mach_msg(&messageHeaderOut.header, MACH_SEND_MSG, messageHeaderOut.header.msgh_size, 0, messageHeaderOut.header.msgh_local_port, 0, MACH_PORT_NULL);
+                RELEASE_ASSERT(messageResult == KERN_SUCCESS);
+            } else {
+                dataLogLn("Failed to receive mach message due to ", mach_error_string(messageResult));
+                RELEASE_ASSERT_NOT_REACHED();
+            }
+        });
+
+        dispatch_resume(source);
+    });
+}
+
+static Signal fromMachException(exception_type_t type)
+{
+    switch (type) {
+    case EXC_BAD_ACCESS: return Signal::SegV;
+    case EXC_BAD_INSTRUCTION: return Signal::Ill;
+    case EXC_BREAKPOINT: return Signal::Trap;
+    default: break;
+    }
+    return Signal::Unknown;
+}
+
+static exception_mask_t toMachMask(Signal signal)
+{
+    switch (signal) {
+    case Signal::SegV: return EXC_MASK_BAD_ACCESS;
+    case Signal::Ill: return EXC_MASK_BAD_INSTRUCTION;
+    case Signal::Trap: return EXC_MASK_BREAKPOINT;
+    default: break;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+extern "C" {
 
-static void jscSignalHandler(int sig, siginfo_t* info, void* mcontext)
+// We need to implement stubs for catch_mach_exception_raise and catch_mach_exception_raise_state_identity.
+// The MiG generated file will fail to link otherwise, even though we don't use the functions. Only the
+// catch_mach_exception_raise_state function should be called because we pass EXCEPTION_STATE to
+// thread_set_exception_ports.
+kern_return_t catch_mach_exception_raise(mach_port_t, mach_port_t, mach_port_t, exception_type_t, mach_exception_data_t, mach_msg_type_number_t)
+{
+    dataLogLn("We should not have called catch_exception_raise(), please file a bug at bugs.webkit.org");
+    return KERN_FAILURE;
+}
+
+kern_return_t catch_mach_exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t, exception_type_t, mach_exception_data_t, mach_msg_type_number_t, int*, thread_state_t, mach_msg_type_number_t, thread_state_t,  mach_msg_type_number_t*)
+{
+    dataLogLn("We should not have called catch_mach_exception_raise_state_identity, please file a bug at bugs.webkit.org");
+    return KERN_FAILURE;
+}
+
+kern_return_t catch_mach_exception_raise_state(
+    mach_port_t port,
+    exception_type_t exceptionType,
+    const mach_exception_data_t exceptionData,
+    mach_msg_type_number_t dataCount,
+    int* stateFlavor,
+    const thread_state_t inState,
+    mach_msg_type_number_t inStateCount,
+    thread_state_t outState,
+    mach_msg_type_number_t* outStateCount)
+{
+    RELEASE_ASSERT(port == exceptionPort);
+    Signal signal = fromMachException(exceptionType);
+    RELEASE_ASSERT(signal != Signal::Unknown);
+
+    memcpy(outState, inState, inStateCount * sizeof(inState[0]));
+    *outStateCount = inStateCount;
+
+#if CPU(X86_64)
+    RELEASE_ASSERT(*stateFlavor == x86_THREAD_STATE);
+    PlatformRegisters& registers = reinterpret_cast<x86_thread_state_t*>(outState)->uts.ts64;
+#elif CPU(X86)
+    RELEASE_ASSERT(*stateFlavor == x86_THREAD_STATE);
+    PlatformRegisters& registers = reinterpret_cast<x86_thread_state_t*>(outState)->uts.ts32;
+#elif CPU(ARM64)
+    RELEASE_ASSERT(*stateFlavor == ARM_THREAD_STATE);
+    PlatformRegisters& registers = reinterpret_cast<arm_unified_thread_state*>(outState)->ts_64;
+#elif CPU(ARM)
+    RELEASE_ASSERT(*stateFlavor == ARM_THREAD_STATE);
+    PlatformRegisters& registers = reinterpret_cast<arm_unified_thread_state*>(outState)->ts_32;
+#endif
+
+    SigInfo info;
+    if (signal == Signal::SegV) {
+        ASSERT_UNUSED(dataCount, dataCount == 2);
+        info.faultingAddress = reinterpret_cast<void*>(exceptionData[1]);
+    }
+
+    bool didHandle = false;
+    handlers[static_cast<size_t>(signal)]->iterate([&] (const SignalHandler& handler) {
+        SignalAction handlerResult = handler(signal, info, registers);
+        didHandle |= handlerResult == SignalAction::Handled;
+    });
+
+    if (didHandle)
+        return KERN_SUCCESS;
+    return KERN_FAILURE;
+}
+
+};
+
+static bool useMach { false };
+void handleSignalsWithMach()
+{
+    deliverMessagesUsingMach();
+    useMach = true;
+}
+
+
+static StaticLock threadLock;
+exception_mask_t activeExceptions { 0 };
+
+inline void setExceptionPorts(const AbstractLocker&, Thread* thread)
+{
+    kern_return_t result = thread_set_exception_ports(thread->machThread(), activeExceptions, 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();
+    }
+}
+
+inline HashSet<Thread*>& activeThreads(const AbstractLocker&)
+{
+    static NeverDestroyed<HashSet<Thread*>> activeThreads;
+    return activeThreads;
+}
+
+void registerThreadForMachExceptionHandling(Thread* thread)
+{
+    auto locker = holdLock(threadLock);
+    auto result = activeThreads(locker).add(thread);
+
+    if (result.isNewEntry)
+        setExceptionPorts(locker, thread);
+}
+
+void unregisterThreadForMachExceptionHandling(Thread* thread)
+{
+    auto locker = holdLock(threadLock);
+    activeThreads(locker).remove(thread);
+}
+
+#else
+static constexpr bool useMach = false;
+#endif // HAVE(MACH_EXCEPTIONS)
+
+static void jscSignalHandler(int, siginfo_t*, void*);
+
+void installSignalHandler(Signal signal, SignalHandler&& handler)
+{
+    ASSERT(signal < Signal::Unknown);
+#if HAVE(MACH_EXCEPTIONS)
+    // Since mach only has EXC_BAD_ACCESS, which covers both SegV and Bus, we arbitarily choose to make
+    // mach EXC_BAD_ACCESSes map to SegV.
+    // FIXME: We should just use a single Signal::BadAccess value instead of SegV/Bus.
+    // See: https://bugs.webkit.org/show_bug.cgi?id=172063
+    if (signal == Signal::Bus && useMach)
+        return;
+    ASSERT(!useMach || signal != Signal::Usr);
+
+    if (useMach)
+        startMachExceptionHandlerThread();
+#endif
+
+    std::call_once(initializeOnceFlags[static_cast<size_t>(signal)], [&] {
+        handlers[static_cast<size_t>(signal)].construct();
+
+        if (!useMach) {
+            struct sigaction action;
+            action.sa_sigaction = jscSignalHandler;
+            auto result = sigfillset(&action.sa_mask);
+            RELEASE_ASSERT(!result);
+            action.sa_flags = SA_SIGINFO;
+            result = sigaction(toSystemSignal(signal), &action, &oldActions[static_cast<size_t>(signal)]);
+            RELEASE_ASSERT(!result);
+        }
+
+    });
+
+    handlers[static_cast<size_t>(signal)]->add(WTFMove(handler));
+
+#if HAVE(MACH_EXCEPTIONS)
+    auto locker = holdLock(threadLock);
+    if (useMach) {
+        activeExceptions |= toMachMask(signal);
+
+        for (Thread* thread : activeThreads(locker))
+            setExceptionPorts(locker, thread);
+    }
+#endif
+}
+
+void jscSignalHandler(int sig, siginfo_t* info, void* ucontext)
 {
     Signal signal = fromSystemSignal(sig);
 
@@ -62,10 +316,16 @@ static void jscSignalHandler(int sig, siginfo_t* info, void* mcontext)
         return;
     }
 
+    SigInfo sigInfo;
+    if (signal == Signal::SegV || signal == Signal::Bus)
+        sigInfo.faultingAddress = info->si_addr;
+
+    PlatformRegisters& registers = registersFromUContext(reinterpret_cast<ucontext_t*>(ucontext));
+
     bool didHandle = false;
     bool restoreDefaultHandler = false;
     handlers[static_cast<size_t>(signal)]->iterate([&] (const SignalHandler& handler) {
-        switch (handler(sig, info, mcontext)) {
+        switch (handler(signal, sigInfo, registers)) {
         case SignalAction::Handled:
             didHandle = true;
             break;
@@ -85,13 +345,13 @@ static void jscSignalHandler(int sig, siginfo_t* info, void* mcontext)
     struct sigaction& oldAction = oldActions[static_cast<size_t>(signal)];
     if (signal == Signal::Usr) {
         if (oldAction.sa_sigaction)
-            oldAction.sa_sigaction(sig, info, mcontext);
+            oldAction.sa_sigaction(sig, info, ucontext);
         return;
     }
 
     if (!didHandle) {
         if (oldAction.sa_sigaction) {
-            oldAction.sa_sigaction(sig, info, mcontext);
+            oldAction.sa_sigaction(sig, info, ucontext);
             return;
         }
 
@@ -100,24 +360,6 @@ static void jscSignalHandler(int sig, siginfo_t* info, void* mcontext)
     }
 }
 
-void installSignalHandler(Signal signal, SignalHandler&& handler)
-{
-    ASSERT(signal < Signal::Unknown);
-    std::call_once(initializeOnceFlags[static_cast<size_t>(signal)], [&] {
-        handlers[static_cast<size_t>(signal)].construct();
-
-        struct sigaction action;
-        action.sa_sigaction = jscSignalHandler;
-        auto result = sigfillset(&action.sa_mask);
-        RELEASE_ASSERT(!result);
-        action.sa_flags = SA_SIGINFO;
-        result = sigaction(toSystemSignal(signal), &action, &oldActions[static_cast<size_t>(signal)]);
-        RELEASE_ASSERT(!result);
-    });
-
-    handlers[static_cast<size_t>(signal)]->add(WTFMove(handler));
-}
-
 } // namespace WTF
 
 #endif // USE(PTHREADS)
index f29d4dd..f4bb530 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <signal.h>
 #include <wtf/Function.h>
+#include <wtf/PlatformRegisters.h>
 
 namespace WTF {
 
@@ -79,7 +80,11 @@ enum class SignalAction {
     ForceDefault
 };
 
-using SignalHandler = Function<SignalAction(int, siginfo_t*, void*)>;
+struct SigInfo {
+    void* faultingAddress { 0 };
+};
+
+using SignalHandler = Function<SignalAction(Signal, SigInfo&, PlatformRegisters&)>;
 
 // Call this method whenever you want to install a signal handler. It's ok to call this function lazily.
 // Note: Your signal handler will be called every time the handler for the desired signal is called.
@@ -87,9 +92,25 @@ using SignalHandler = Function<SignalAction(int, siginfo_t*, void*)>;
 // This function is currently a one way street i.e. once installed, a signal handler cannot be uninstalled.
 WTF_EXPORT_PRIVATE void installSignalHandler(Signal, SignalHandler&&);
 
+
+#if HAVE(MACH_EXCEPTIONS)
+class Thread;
+void registerThreadForMachExceptionHandling(Thread*);
+void unregisterThreadForMachExceptionHandling(Thread*);
+
+void handleSignalsWithMach();
+#endif // HAVE(MACH_EXCEPTIONS)
+
 } // namespace WTF
 
+#if HAVE(MACH_EXCEPTIONS)
+using WTF::registerThreadForMachExceptionHandling;
+using WTF::unregisterThreadForMachExceptionHandling;
+using WTF::handleSignalsWithMach;
+#endif // HAVE(MACH_EXCEPTIONS)
+
 using WTF::Signal;
+using WTF::SigInfo;
 using WTF::toSystemSignal;
 using WTF::fromSystemSignal;
 using WTF::SignalAction;
index 150ae93..9ccd932 100644 (file)
@@ -1,3 +1,14 @@
+2017-06-01  Keith Miller  <keith_miller@apple.com>
+
+        Undo rollout in r217638 with bug fix
+        https://bugs.webkit.org/show_bug.cgi?id=172824
+
+        Unreviewed, reland patch with unused set_state code removed.
+
+        * TestWebKitAPI/Tests/WTF/ThreadMessages.cpp:
+        (runThreadMessageTest):
+        (TEST):
+
 2017-06-01  Jonathan Bedard  <jbedard@apple.com>
 
         webkitpy: Do not send 0 or -1 as a pid to kill_process
index d63e9bf..e6a5789 100644 (file)
@@ -50,7 +50,7 @@ static void runThreadMessageTest(unsigned numSenders, unsigned numMessages)
     for (unsigned senderID = 0; senderID < numSenders; ++senderID) {
         senderThreads[senderID] = Thread::create("ThreadMessage sender", [senderID, numMessages, receiverThread, &messagesRun, &handlersRun] () {
             for (unsigned i = 0; i < numMessages; ++i) {
-                auto result = sendMessage(*receiverThread.get(), [senderID, &handlersRun] (siginfo_t*, ucontext_t*) {
+                auto result = sendMessage(*receiverThread.get(), [senderID, &handlersRun] (PlatformRegisters&) {
                     handlersRun[senderID]++;
                 });
                 EXPECT_TRUE(result == WTF::MessageStatus::MessageRan);
@@ -95,7 +95,7 @@ public:
 TEST(ThreadMessage, SignalsWorkOnExit)
 {
     static bool handlerRan = false;
-    installSignalHandler(Signal::Usr, [] (int, siginfo_t*, void*) -> SignalAction {
+    installSignalHandler(Signal::Usr, [] (Signal, SigInfo&, PlatformRegisters&) -> SignalAction {
         dataLogLn("here");
         handlerRan = true;
         return SignalAction::Handled;