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.
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: http://svn.webkit.org/repository/webkit/trunk@217669 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp b/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp
index 85c272c..a3c39a7 100644
--- a/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp
+++ b/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp
@@ -30,10 +30,18 @@
#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 @@
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 @@
}
}
+#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());
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index b1056b4..6b42b48 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -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
diff --git a/Source/JavaScriptCore/runtime/JSLock.cpp b/Source/JavaScriptCore/runtime/JSLock.cpp
index c175ae0..31e2db4 100644
--- a/Source/JavaScriptCore/runtime/JSLock.cpp
+++ b/Source/JavaScriptCore/runtime/JSLock.cpp
@@ -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 @@
Wasm::startTrackingCurrentThread();
#endif
+#if HAVE(MACH_EXCEPTIONS)
+ registerThreadForMachExceptionHandling(&Thread::current());
+#endif
+
m_vm->traps().notifyGrabAllLocks();
#if ENABLE(SAMPLING_PROFILER)
diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp
index 3757786..9f12df9 100644
--- a/Source/JavaScriptCore/runtime/Options.cpp
+++ b/Source/JavaScriptCore/runtime/Options.cpp
@@ -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 @@
#if !ENABLE(WEBASSEMBLY_FAST_MEMORY)
Options::useWebAssemblyFastMemory() = false;
#endif
+
+#if !HAVE(MACH_EXCEPTIONS)
+ Options::useMachForExceptions() = false;
+#endif
}
static void recomputeDependentOptions()
@@ -550,6 +555,11 @@
dumpOptionsIfNeeded();
ensureOptionsAreCoherent();
+
+#if HAVE(MACH_EXCEPTIONS)
+ if (Options::useMachForExceptions())
+ handleSignalsWithMach();
+#endif
});
}
diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h
index 4ad16ea..a0935d2 100644
--- a/Source/JavaScriptCore/runtime/Options.h
+++ b/Source/JavaScriptCore/runtime/Options.h
@@ -423,6 +423,8 @@
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 @@
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.") \
diff --git a/Source/JavaScriptCore/runtime/VMTraps.cpp b/Source/JavaScriptCore/runtime/VMTraps.cpp
index 1baace6..8c57c45 100644
--- a/Source/JavaScriptCore/runtime/VMTraps.cpp
+++ b/Source/JavaScriptCore/runtime/VMTraps.cpp
@@ -53,11 +53,11 @@
#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 @@
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 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 @@
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;
diff --git a/Source/JavaScriptCore/tools/SigillCrashAnalyzer.cpp b/Source/JavaScriptCore/tools/SigillCrashAnalyzer.cpp
index 4adaeff..71a6e42 100644
--- a/Source/JavaScriptCore/tools/SigillCrashAnalyzer.cpp
+++ b/Source/JavaScriptCore/tools/SigillCrashAnalyzer.cpp
@@ -78,11 +78,11 @@
#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 @@
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 @@
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 @@
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;
diff --git a/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp b/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp
index 1dd0cd1..b1b598d 100644
--- a/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp
+++ b/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp
@@ -242,7 +242,7 @@
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)) {
diff --git a/Source/JavaScriptCore/wasm/WasmFaultSignalHandler.cpp b/Source/JavaScriptCore/wasm/WasmFaultSignalHandler.cpp
index 2e0c99a..264c34d 100644
--- a/Source/JavaScriptCore/wasm/WasmFaultSignalHandler.cpp
+++ b/Source/JavaScriptCore/wasm/WasmFaultSignalHandler.cpp
@@ -52,9 +52,8 @@
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 @@
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 @@
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);
});
diff --git a/Source/JavaScriptCore/wasm/WasmMachineThreads.cpp b/Source/JavaScriptCore/wasm/WasmMachineThreads.cpp
index 5aac87a..0a367fd 100644
--- a/Source/JavaScriptCore/wasm/WasmMachineThreads.cpp
+++ b/Source/JavaScriptCore/wasm/WasmMachineThreads.cpp
@@ -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 @@
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();
});
diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog
index e96f879..560753e 100644
--- a/Source/WTF/ChangeLog
+++ b/Source/WTF/ChangeLog
@@ -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.
diff --git a/Source/WTF/Configurations/WTF.xcconfig b/Source/WTF/Configurations/WTF.xcconfig
index 421efd9..af199ce 100644
--- a/Source/WTF/Configurations/WTF.xcconfig
+++ b/Source/WTF/Configurations/WTF.xcconfig
@@ -27,3 +27,6 @@
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))
diff --git a/Source/WTF/WTF.xcodeproj/project.pbxproj b/Source/WTF/WTF.xcodeproj/project.pbxproj
index 57b3e0f..d62a793 100644
--- a/Source/WTF/WTF.xcodeproj/project.pbxproj
+++ b/Source/WTF/WTF.xcodeproj/project.pbxproj
@@ -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 */; };
@@ -299,6 +300,7 @@
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>"; };
@@ -1022,6 +1024,7 @@
children = (
1A428B8B1C8F89DD0051E9EB /* AppKitCompatibilityDeclarations.h */,
1ACADD821884480100D8B71D /* DeprecatedSymbolsUsedBySafari.mm */,
+ 53534F291EC0E10E00141B2F /* MachExceptions.defs */,
A8A472C5151A825A004123FF /* MainThreadMac.mm */,
);
path = mac;
@@ -1346,6 +1349,7 @@
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 */,
diff --git a/Source/WTF/wtf/Platform.h b/Source/WTF/wtf/Platform.h
index 45bd8a8..0c956f4 100644
--- a/Source/WTF/wtf/Platform.h
+++ b/Source/WTF/wtf/Platform.h
@@ -669,6 +669,10 @@
#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
diff --git a/Source/WTF/wtf/PlatformRegisters.h b/Source/WTF/wtf/PlatformRegisters.h
index d5b5abc..84bd893 100644
--- a/Source/WTF/wtf/PlatformRegisters.h
+++ b/Source/WTF/wtf/PlatformRegisters.h
@@ -26,9 +26,11 @@
#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 @@
#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 @@
mcontext_t machineContext;
};
+inline PlatformRegisters& registersFromUContext(ucontext_t* ucontext)
+{
+ return *bitwise_cast<PlatformRegisters*>(&ucontext->uc_mcontext);
+}
+
#else
struct PlatformRegisters {
diff --git a/Source/WTF/wtf/StackBounds.h b/Source/WTF/wtf/StackBounds.h
index 554604f..cd62c14 100644
--- a/Source/WTF/wtf/StackBounds.h
+++ b/Source/WTF/wtf/StackBounds.h
@@ -54,7 +54,6 @@
: m_origin(origin)
, m_bound(end)
{
- checkConsistency();
}
void* origin() const
diff --git a/Source/WTF/wtf/ThreadHolder.cpp b/Source/WTF/wtf/ThreadHolder.cpp
index e2a31be..977d1df 100644
--- a/Source/WTF/wtf/ThreadHolder.cpp
+++ b/Source/WTF/wtf/ThreadHolder.cpp
@@ -34,12 +34,17 @@
#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();
}
diff --git a/Source/WTF/wtf/ThreadMessage.cpp b/Source/WTF/wtf/ThreadMessage.cpp
index f14bc45..64e775e 100644
--- a/Source/WTF/wtf/ThreadMessage.cpp
+++ b/Source/WTF/wtf/ThreadMessage.cpp
@@ -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 @@
}
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 @@
// 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 @@
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)
diff --git a/Source/WTF/wtf/ThreadMessage.h b/Source/WTF/wtf/ThreadMessage.h
index 268add4..0f74551 100644
--- a/Source/WTF/wtf/ThreadMessage.h
+++ b/Source/WTF/wtf/ThreadMessage.h
@@ -36,7 +36,7 @@
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 @@
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;
diff --git a/Source/WTF/wtf/Threading.h b/Source/WTF/wtf/Threading.h
index d2e536d..3514e8c 100644
--- a/Source/WTF/wtf/Threading.h
+++ b/Source/WTF/wtf/Threading.h
@@ -138,6 +138,10 @@
#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
index 0000000..4205742
--- /dev/null
+++ b/Source/WTF/wtf/mac/MachExceptions.defs
@@ -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>
diff --git a/Source/WTF/wtf/threads/Signals.cpp b/Source/WTF/wtf/threads/Signals.cpp
index 855b28b..7f24706 100644
--- a/Source/WTF/wtf/threads/Signals.cpp
+++ b/Source/WTF/wtf/threads/Signals.cpp
@@ -28,21 +28,275 @@
#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)];
-static void jscSignalHandler(int sig, siginfo_t* info, void* mcontext)
+#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" {
+
+// 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 @@
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 @@
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 @@
}
}
-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)
diff --git a/Source/WTF/wtf/threads/Signals.h b/Source/WTF/wtf/threads/Signals.h
index f29d4dd..f4bb530 100644
--- a/Source/WTF/wtf/threads/Signals.h
+++ b/Source/WTF/wtf/threads/Signals.h
@@ -29,6 +29,7 @@
#include <signal.h>
#include <wtf/Function.h>
+#include <wtf/PlatformRegisters.h>
namespace WTF {
@@ -79,7 +80,11 @@
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 @@
// 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;
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index 150ae93..9ccd932b1 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -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
diff --git a/Tools/TestWebKitAPI/Tests/WTF/ThreadMessages.cpp b/Tools/TestWebKitAPI/Tests/WTF/ThreadMessages.cpp
index d63e9bf..e6a5789 100644
--- a/Tools/TestWebKitAPI/Tests/WTF/ThreadMessages.cpp
+++ b/Tools/TestWebKitAPI/Tests/WTF/ThreadMessages.cpp
@@ -50,7 +50,7 @@
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 @@
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;