Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 65 additions & 34 deletions Source/JavaScriptCore/runtime/VMTraps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "WaiterListManager.h"
#include "Watchdog.h"
#include <wtf/ProcessID.h>
#include <wtf/WorkQueue.h>
#include <wtf/ThreadMessage.h>
#include <wtf/threads/Signals.h>

Expand Down Expand Up @@ -194,16 +195,26 @@ void VMTraps::invalidateCodeBlocksOnStack(Locker<Lock>&, CallFrame* topCallFrame
}
}

class VMTraps::SignalSender final : public AutomaticThread {
class VMTraps::SignalSender final : public ThreadSafeRefCounted<VMTraps::SignalSender> {
public:
using Base = AutomaticThread;
SignalSender(const AbstractLocker& locker, VM& vm)
: Base(locker, vm.traps().m_lock, vm.traps().m_condition.copyRef())
, m_vm(vm)
SignalSender(const AbstractLocker&, VM& vm)
: m_vm(vm)
, m_lock(vm.traps().m_lock)
, m_condition(vm.traps().m_condition)
{
activateSignalHandlersFor(Signal::AccessFault);
}

static WorkQueue& queue()
{
static LazyNeverDestroyed<Ref<WorkQueue>> workQueue;
static std::once_flag onceKey;
std::call_once(onceKey, [&] {
workQueue.construct(WorkQueue::create("JSC VMTraps Signal Sender"_s));
});
return workQueue.get();
}

static void initializeSignals()
{
static std::once_flag once;
Expand Down Expand Up @@ -257,31 +268,47 @@ class VMTraps::SignalSender final : public AutomaticThread {
});
}

ASCIILiteral name() const final
VMTraps& traps() { return m_vm.traps(); }


void notify(AbstractLocker&)
{
return "JSC VMTraps Signal Sender Thread"_s;
if (m_scheduled)
return;
m_scheduled = true;
queue().dispatch([protectedThis = Ref { *this }] {
protectedThis->work();
});
}

VMTraps& traps() { return m_vm.traps(); }
bool isStopped(AbstractLocker&)
{
return !m_scheduled;
}

private:
PollResult poll(const AbstractLocker&) final
void work()
{
if (traps().m_isShuttingDown)
return PollResult::Stop;
VM& vm = m_vm;

if (!traps().needHandling(VMTraps::AsyncEvents))
return PollResult::Wait;
auto workDone = [&](AbstractLocker&) {
m_scheduled = false;
m_condition->notifyAll(); // let work queue service next SignalSender if needed.
};

// We know that no trap could have been processed and re-added because we are holding the lock.
if (vmIsInactive(m_vm))
return PollResult::Wait;
return PollResult::Work;
}
{
Locker locker { *m_lock };
ASSERT(m_scheduled);
if (traps().m_isShuttingDown)
return workDone(locker);

WorkResult work() final
{
VM& vm = m_vm;
if (!traps().needHandling(VMTraps::AsyncEvents))
return workDone(locker);

// We know that no trap could have been processed and re-added because we are holding the lock.
if (vmIsInactive(m_vm))
return workDone(locker);
}

auto optionalOwnerThread = vm.ownerThread();
if (optionalOwnerThread) {
Expand All @@ -301,21 +328,26 @@ class VMTraps::SignalSender final : public AutomaticThread {
});
}

{
if (vm.traps().hasTrapBit(NeedTermination))
vm.syncWaiter()->condition().notifyOne();
}
if (vm.traps().hasTrapBit(NeedTermination))
vm.syncWaiter()->condition().notifyOne();

{
Locker locker { *traps().m_lock };
Locker locker { *m_lock };
ASSERT(m_scheduled);
if (traps().m_isShuttingDown)
return WorkResult::Stop;
traps().m_condition->waitFor(*traps().m_lock, 1_ms);
return workDone(locker);
ASSERT(m_scheduled);
}
return WorkResult::Continue;

queue().dispatchAfter(1_ms, [protectedThis = Ref { *this }] {
protectedThis->work();
});
}

VM& m_vm;
Box<Lock> m_lock;
Box<Condition> m_condition;
bool m_scheduled { false };
};

#endif // ENABLE(SIGNAL_BASED_VM_TRAPS)
Expand All @@ -337,10 +369,9 @@ void VMTraps::willDestroyVM()
if (m_signalSender) {
{
Locker locker { *m_lock };
if (!m_signalSender->tryStop(locker))
m_condition->notifyAll(locker);
while (!m_signalSender->isStopped(locker))
m_condition->wait(*m_lock);
}
m_signalSender->join();
m_signalSender = nullptr;
}
#endif
Expand All @@ -365,7 +396,7 @@ void VMTraps::fireTrap(VMTraps::Event event)
Locker locker { *m_lock };
if (!m_signalSender)
m_signalSender = adoptRef(new SignalSender(locker, vm()));
m_condition->notifyAll(locker);
m_signalSender->notify(locker);
}
#endif

Expand Down Expand Up @@ -471,7 +502,7 @@ void VMTraps::undoDeferTerminationSlow(DeferAction deferAction)

VMTraps::VMTraps()
: m_lock(Box<Lock>::create())
, m_condition(AutomaticThreadCondition::create())
, m_condition(Box<Condition>::create())
{
}

Expand Down
2 changes: 1 addition & 1 deletion Source/JavaScriptCore/runtime/VMTraps.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ class VMTraps {
static constexpr BitField NeedExceptionHandlingMask = ~(1 << NeedExceptionHandling);

Box<Lock> m_lock;
Ref<AutomaticThreadCondition> m_condition;
Box<Condition> m_condition;
Atomic<BitField> m_trapBits { 0 };
bool m_needToInvalidatedCodeBlocks { false };
bool m_isShuttingDown { false };
Expand Down