Diff
Modified: trunk/Source/_javascript_Core/API/tests/ExecutionTimeLimitTest.cpp (219237 => 219238)
--- trunk/Source/_javascript_Core/API/tests/ExecutionTimeLimitTest.cpp 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/_javascript_Core/API/tests/ExecutionTimeLimitTest.cpp 2017-07-07 04:56:23 UTC (rev 219238)
@@ -36,6 +36,7 @@
#include <wtf/Condition.h>
#include <wtf/CurrentTime.h>
#include <wtf/Lock.h>
+#include <wtf/Threading.h>
#include <wtf/text/StringBuilder.h>
#if HAVE(MACH_EXCEPTIONS)
Modified: trunk/Source/_javascript_Core/ChangeLog (219237 => 219238)
--- trunk/Source/_javascript_Core/ChangeLog 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/_javascript_Core/ChangeLog 2017-07-07 04:56:23 UTC (rev 219238)
@@ -1,3 +1,57 @@
+2017-07-05 Yusuke Suzuki <utatane....@gmail.com>
+
+ [WTF] Implement WTF::ThreadGroup
+ https://bugs.webkit.org/show_bug.cgi?id=174081
+
+ Reviewed by Mark Lam.
+
+ Large part of MachineThreads are now removed and replaced with WTF::ThreadGroup.
+ And SamplingProfiler and others interact with WTF::Thread directly.
+
+ * API/tests/ExecutionTimeLimitTest.cpp:
+ * heap/MachineStackMarker.cpp:
+ (JSC::MachineThreads::MachineThreads):
+ (JSC::captureStack):
+ (JSC::MachineThreads::tryCopyOtherThreadStack):
+ (JSC::MachineThreads::tryCopyOtherThreadStacks):
+ (JSC::MachineThreads::gatherConservativeRoots):
+ (JSC::ActiveMachineThreadsManager::Locker::Locker): Deleted.
+ (JSC::ActiveMachineThreadsManager::add): Deleted.
+ (JSC::ActiveMachineThreadsManager::remove): Deleted.
+ (JSC::ActiveMachineThreadsManager::contains): Deleted.
+ (JSC::ActiveMachineThreadsManager::ActiveMachineThreadsManager): Deleted.
+ (JSC::activeMachineThreadsManager): Deleted.
+ (JSC::MachineThreads::~MachineThreads): Deleted.
+ (JSC::MachineThreads::addCurrentThread): Deleted.
+ (): Deleted.
+ (JSC::MachineThreads::removeThread): Deleted.
+ (JSC::MachineThreads::removeThreadIfFound): Deleted.
+ (JSC::MachineThreads::MachineThread::MachineThread): Deleted.
+ (JSC::MachineThreads::MachineThread::getRegisters): Deleted.
+ (JSC::MachineThreads::MachineThread::Registers::stackPointer): Deleted.
+ (JSC::MachineThreads::MachineThread::Registers::framePointer): Deleted.
+ (JSC::MachineThreads::MachineThread::Registers::instructionPointer): Deleted.
+ (JSC::MachineThreads::MachineThread::Registers::llintPC): Deleted.
+ (JSC::MachineThreads::MachineThread::captureStack): Deleted.
+ * heap/MachineStackMarker.h:
+ (JSC::MachineThreads::addCurrentThread):
+ (JSC::MachineThreads::getLock):
+ (JSC::MachineThreads::threads):
+ (JSC::MachineThreads::MachineThread::suspend): Deleted.
+ (JSC::MachineThreads::MachineThread::resume): Deleted.
+ (JSC::MachineThreads::MachineThread::threadID): Deleted.
+ (JSC::MachineThreads::MachineThread::stackBase): Deleted.
+ (JSC::MachineThreads::MachineThread::stackEnd): Deleted.
+ (JSC::MachineThreads::threadsListHead): Deleted.
+ * runtime/SamplingProfiler.cpp:
+ (JSC::FrameWalker::isValidFramePointer):
+ (JSC::SamplingProfiler::SamplingProfiler):
+ (JSC::SamplingProfiler::takeSample):
+ (JSC::SamplingProfiler::noticeCurrentThreadAsJSCExecutionThread):
+ * runtime/SamplingProfiler.h:
+ * wasm/WasmMachineThreads.cpp:
+ (JSC::Wasm::resetInstructionCacheOnAllThreads):
+
2017-07-06 Saam Barati <sbar...@apple.com>
We are missing places where we invalidate the for-in context
Modified: trunk/Source/_javascript_Core/heap/MachineStackMarker.cpp (219237 => 219238)
--- trunk/Source/_javascript_Core/heap/MachineStackMarker.cpp 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/_javascript_Core/heap/MachineStackMarker.cpp 2017-07-07 04:56:23 UTC (rev 219238)
@@ -23,17 +23,10 @@
#include "MachineStackMarker.h"
#include "ConservativeRoots.h"
-#include "GPRInfo.h"
-#include "Heap.h"
-#include "JSArray.h"
-#include "JSCInlines.h"
-#include "LLIntPCRanges.h"
-#include "MacroAssembler.h"
-#include "VM.h"
+#include "MachineContext.h"
#include <setjmp.h>
#include <stdlib.h>
-#include <wtf/MainThread.h>
-#include <wtf/NeverDestroyed.h>
+#include <wtf/BitVector.h>
#include <wtf/StdLibExtras.h>
using namespace WTF;
@@ -40,190 +33,11 @@
namespace JSC {
-class ActiveMachineThreadsManager;
-static ActiveMachineThreadsManager& activeMachineThreadsManager();
-
-class ActiveMachineThreadsManager {
- WTF_MAKE_NONCOPYABLE(ActiveMachineThreadsManager);
-public:
-
- class Locker {
- public:
- Locker(ActiveMachineThreadsManager& manager)
- : m_locker(manager.m_lock)
- {
- }
-
- private:
- LockHolder m_locker;
- };
-
- void add(MachineThreads* machineThreads)
- {
- LockHolder managerLock(m_lock);
- m_set.add(machineThreads);
- }
-
- void THREAD_SPECIFIC_CALL remove(MachineThreads* machineThreads)
- {
- LockHolder managerLock(m_lock);
- auto recordedMachineThreads = m_set.take(machineThreads);
- RELEASE_ASSERT(recordedMachineThreads == machineThreads);
- }
-
- bool contains(MachineThreads* machineThreads)
- {
- return m_set.contains(machineThreads);
- }
-
-private:
- typedef HashSet<MachineThreads*> MachineThreadsSet;
-
- ActiveMachineThreadsManager() { }
-
- Lock m_lock;
- MachineThreadsSet m_set;
-
- friend ActiveMachineThreadsManager& activeMachineThreadsManager();
-};
-
-static ActiveMachineThreadsManager& activeMachineThreadsManager()
-{
- static std::once_flag initializeManagerOnceFlag;
- static ActiveMachineThreadsManager* manager = nullptr;
-
- std::call_once(initializeManagerOnceFlag, [] {
- manager = new ActiveMachineThreadsManager();
- });
- return *manager;
-}
-
-#if CPU(X86_64) && OS(DARWIN)
-#define FILL_CALLEE_SAVES_FOR_CRASH_INFO(number) \
- asm volatile( \
- "movq $0xc0defefe000000" number ", %%rbx;" \
- "movq $0xc0defefe000000" number ", %%r12;" \
- "movq $0xc0defefe000000" number ", %%r13;" \
- "movq $0xc0defefe000000" number ", %%r14;" \
- "movq $0xc0defefe000000" number ", %%r15;" \
- : \
- : \
- : "%rbx", "%r12", "%r13", "%r14", "%r15" \
- );
-
-#define FILL_CALLER_SAVES_FOR_CRASH_INFO(number) \
- asm volatile( \
- "movq $0xc0defefe000000" number ", %%rax;" \
- "movq $0xc0defefe000000" number ", %%rdi;" \
- "movq $0xc0defefe000000" number ", %%rsi;" \
- "movq $0xc0defefe000000" number ", %%rdx;" \
- "movq $0xc0defefe000000" number ", %%rcx;" \
- "movq $0xc0defefe000000" number ", %%r8;" \
- "movq $0xc0defefe000000" number ", %%r9;" \
- "movq $0xc0defefe000000" number ", %%r10;" \
- "movq $0xc0defefe000000" number ", %%r11;" \
- : \
- : \
- : "%rax", "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9", "%r10", "%r11" \
- );
-#else
-#define FILL_CALLEE_SAVES_FOR_CRASH_INFO(number)
-#define FILL_CALLER_SAVES_FOR_CRASH_INFO(number)
-#endif
-
MachineThreads::MachineThreads()
- : m_registeredThreads()
- , m_threadSpecificForMachineThreads(0)
+ : m_threadGroup(ThreadGroup::create())
{
- FILL_CALLEE_SAVES_FOR_CRASH_INFO("01");
- threadSpecificKeyCreate(&m_threadSpecificForMachineThreads, removeThread);
- FILL_CALLEE_SAVES_FOR_CRASH_INFO("02");
- activeMachineThreadsManager().add(this);
- FILL_CALLER_SAVES_FOR_CRASH_INFO("03");
}
-MachineThreads::~MachineThreads()
-{
- activeMachineThreadsManager().remove(this);
- threadSpecificKeyDelete(m_threadSpecificForMachineThreads);
-
- LockHolder registeredThreadsLock(m_registeredThreadsMutex);
- for (MachineThread* current = m_registeredThreads.head(); current;) {
- MachineThread* next = current->next();
- delete current;
- current = next;
- }
-}
-
-void MachineThreads::addCurrentThread()
-{
- if (threadSpecificGet(m_threadSpecificForMachineThreads)) {
-#ifndef NDEBUG
- LockHolder lock(m_registeredThreadsMutex);
- ASSERT(threadSpecificGet(m_threadSpecificForMachineThreads) == this);
-#endif
- return;
- }
-
- MachineThread* thread = new MachineThread();
- threadSpecificSet(m_threadSpecificForMachineThreads, this);
-
- LockHolder lock(m_registeredThreadsMutex);
-
- m_registeredThreads.append(thread);
-}
-
-auto MachineThreads::machineThreadForCurrentThread() -> MachineThread*
-{
- LockHolder lock(m_registeredThreadsMutex);
- ThreadIdentifier id = currentThread();
- for (MachineThread* thread = m_registeredThreads.head(); thread; thread = thread->next()) {
- if (thread->threadID() == id)
- return thread;
- }
-
- RELEASE_ASSERT_NOT_REACHED();
- return nullptr;
-}
-
-void THREAD_SPECIFIC_CALL MachineThreads::removeThread(void* p)
-{
- auto& manager = activeMachineThreadsManager();
- ActiveMachineThreadsManager::Locker lock(manager);
- auto machineThreads = static_cast<MachineThreads*>(p);
- if (manager.contains(machineThreads)) {
- // There's a chance that the MachineThreads registry that this thread
- // was registered with was already destructed, and another one happened
- // to be instantiated at the same address. Hence, this thread may or
- // may not be found in this MachineThreads registry. We only need to
- // do a removal if this thread is found in it.
-
-#if OS(WINDOWS)
- // On Windows the thread specific destructor is also called when the
- // main thread is exiting. This may lead to the main thread waiting
- // forever for the machine thread lock when exiting, if the sampling
- // profiler thread was terminated by the system while holding the
- // machine thread lock.
- if (WTF::isMainThread())
- return;
-#endif
-
- machineThreads->removeThreadIfFound(currentThread());
- }
-}
-
-void MachineThreads::removeThreadIfFound(ThreadIdentifier id)
-{
- LockHolder lock(m_registeredThreadsMutex);
- for (MachineThread* current = m_registeredThreads.head(); current; current = current->next()) {
- if (current->threadID() == id) {
- m_registeredThreads.remove(current);
- delete current;
- break;
- }
- }
-}
-
SUPPRESS_ASAN
void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, CurrentThreadState& currentThreadState)
{
@@ -236,52 +50,6 @@
conservativeRoots.add(currentThreadState.stackTop, currentThreadState.stackOrigin, jitStubRoutines, codeBlocks);
}
-MachineThreads::MachineThread::MachineThread()
- : m_thread(WTF::Thread::current())
-{
-}
-
-size_t MachineThreads::MachineThread::getRegisters(MachineThread::Registers& registers)
-{
- WTF::PlatformRegisters& regs = registers.regs;
- return m_thread->getRegisters(regs);
-}
-
-void* MachineThreads::MachineThread::Registers::stackPointer() const
-{
- return MachineContext::stackPointer(regs);
-}
-
-#if ENABLE(SAMPLING_PROFILER)
-void* MachineThreads::MachineThread::Registers::framePointer() const
-{
-#if OS(WINDOWS) || HAVE(MACHINE_CONTEXT)
- return MachineContext::framePointer(regs);
-#else
-#error Need a way to get the frame pointer for another thread on this platform
-#endif
-}
-
-void* MachineThreads::MachineThread::Registers::instructionPointer() const
-{
-#if OS(WINDOWS) || HAVE(MACHINE_CONTEXT)
- return MachineContext::instructionPointer(regs);
-#else
-#error Need a way to get the instruction pointer for another thread on this platform
-#endif
-}
-
-void* MachineThreads::MachineThread::Registers::llintPC() const
-{
- // LLInt uses regT4 as PC.
-#if OS(WINDOWS) || HAVE(MACHINE_CONTEXT)
- return MachineContext::llintInstructionPointer(regs);
-#else
-#error Need a way to get the LLIntPC for another thread on this platform
-#endif
-}
-#endif // ENABLE(SAMPLING_PROFILER)
-
static inline int osRedZoneAdjustment()
{
int redZoneAdjustment = 0;
@@ -297,9 +65,9 @@
return redZoneAdjustment;
}
-std::pair<void*, size_t> MachineThreads::MachineThread::captureStack(void* stackTop)
+static std::pair<void*, size_t> captureStack(Thread& thread, void* stackTop)
{
- char* begin = reinterpret_cast_ptr<char*>(stackBase());
+ char* begin = reinterpret_cast_ptr<char*>(thread.stack().origin());
char* end = bitwise_cast<char*>(WTF::roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(stackTop)));
ASSERT(begin >= end);
@@ -306,8 +74,8 @@
char* endWithRedZone = end + osRedZoneAdjustment();
ASSERT(WTF::roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(endWithRedZone)) == reinterpret_cast<uintptr_t>(endWithRedZone));
- if (endWithRedZone < stackEnd())
- endWithRedZone = reinterpret_cast_ptr<char*>(stackEnd());
+ if (endWithRedZone < thread.stack().end())
+ endWithRedZone = reinterpret_cast_ptr<char*>(thread.stack().end());
std::swap(begin, endWithRedZone);
return std::make_pair(begin, endWithRedZone - begin);
@@ -340,20 +108,20 @@
// significant performance loss as tryCopyOtherThreadStack is only called as part of an O(heapsize)
// operation. As the heap is generally much larger than the stack the performance hit is minimal.
// See: https://bugs.webkit.org/show_bug.cgi?id=146297
-void MachineThreads::tryCopyOtherThreadStack(MachineThread* thread, void* buffer, size_t capacity, size_t* size)
+void MachineThreads::tryCopyOtherThreadStack(Thread& thread, void* buffer, size_t capacity, size_t* size)
{
- MachineThread::Registers registers;
- size_t registersSize = thread->getRegisters(registers);
+ PlatformRegisters registers;
+ size_t registersSize = thread.getRegisters(registers);
// This is a workaround for <rdar://problem/27607384>. libdispatch recycles work
// queue threads without running pthread exit destructors. This can cause us to scan a
// thread during work queue initialization, when the stack pointer is null.
- if (UNLIKELY(!registers.stackPointer())) {
+ if (UNLIKELY(!MachineContext::stackPointer(registers))) {
*size = 0;
return;
}
- std::pair<void*, size_t> stack = thread->captureStack(registers.stackPointer());
+ std::pair<void*, size_t> stack = captureStack(thread, MachineContext::stackPointer(registers));
bool canCopy = *size + registersSize + stack.second <= capacity;
@@ -366,7 +134,7 @@
*size += stack.second;
}
-bool MachineThreads::tryCopyOtherThreadStacks(const AbstractLocker&, void* buffer, size_t capacity, size_t* size)
+bool MachineThreads::tryCopyOtherThreadStacks(const AbstractLocker& locker, void* buffer, size_t capacity, size_t* size)
{
// Prevent two VMs from suspending each other's threads at the same time,
// which can cause deadlock: <rdar://problem/20300842>.
@@ -375,60 +143,49 @@
*size = 0;
- ThreadIdentifier id = currentThread();
- int numberOfThreads = 0; // Using 0 to denote that we haven't counted the number of threads yet.
- int index = 1;
- DoublyLinkedList<MachineThread> threadsToBeDeleted;
+ Thread& currentThread = Thread::current();
+ const auto& threads = m_threadGroup->threads(locker);
+ BitVector isSuspended(threads.size());
- for (MachineThread* thread = m_registeredThreads.head(); thread; index++) {
- if (thread->threadID() != id) {
- auto result = thread->suspend();
+ {
+ unsigned index = 0;
+ for (auto* thread : threads) {
+ if (*thread != currentThread) {
+ auto result = thread->suspend();
+ if (result)
+ isSuspended.set(index);
+ else {
#if OS(DARWIN)
- if (!result) {
- if (!numberOfThreads)
- numberOfThreads = m_registeredThreads.size();
-
- ASSERT(result.error() != KERN_SUCCESS);
-
- WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
- "_javascript_ garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] id %u.",
- result.error(), index, numberOfThreads, thread, thread->threadID());
-
- // Put the invalid thread on the threadsToBeDeleted list.
- // We can't just delete it here because we have suspended other
- // threads, and they may still be holding the C heap lock which
- // we need for deleting the invalid thread. Hence, we need to
- // defer the deletion till after we have resumed all threads.
- MachineThread* nextThread = thread->next();
- m_registeredThreads.remove(thread);
- threadsToBeDeleted.append(thread);
- thread = nextThread;
- continue;
+ // These threads will be removed from the ThreadGroup. Thus, we do not do anything here except for reporting.
+ ASSERT(result.error() != KERN_SUCCESS);
+ WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
+ "_javascript_ garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] id %u.",
+ result.error(), index, threads.size(), thread, thread->id());
+#endif
+ }
}
-#else
- UNUSED_PARAM(numberOfThreads);
- ASSERT_UNUSED(result, result);
-#endif
+ ++index;
}
- thread = thread->next();
}
- for (MachineThread* thread = m_registeredThreads.head(); thread; thread = thread->next()) {
- if (thread->threadID() != id)
- tryCopyOtherThreadStack(thread, buffer, capacity, size);
+ {
+ unsigned index = 0;
+ for (auto* thread : threads) {
+ if (isSuspended.get(index))
+ tryCopyOtherThreadStack(*thread, buffer, capacity, size);
+ ++index;
+ }
}
- for (MachineThread* thread = m_registeredThreads.head(); thread; thread = thread->next()) {
- if (thread->threadID() != id)
- thread->resume();
+ {
+ unsigned index = 0;
+ for (auto* thread : threads) {
+ if (isSuspended.get(index))
+ thread->resume();
+ ++index;
+ }
}
- for (MachineThread* thread = threadsToBeDeleted.head(); thread; ) {
- MachineThread* nextThread = thread->next();
- delete thread;
- thread = nextThread;
- }
-
return *size <= capacity;
}
@@ -449,8 +206,8 @@
size_t size;
size_t capacity = 0;
void* buffer = nullptr;
- LockHolder lock(m_registeredThreadsMutex);
- while (!tryCopyOtherThreadStacks(lock, buffer, capacity, &size))
+ auto locker = holdLock(m_threadGroup->getLock());
+ while (!tryCopyOtherThreadStacks(locker, buffer, capacity, &size))
growBuffer(size, &buffer, &capacity);
if (!buffer)
Modified: trunk/Source/_javascript_Core/heap/MachineStackMarker.h (219237 => 219238)
--- trunk/Source/_javascript_Core/heap/MachineStackMarker.h 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/_javascript_Core/heap/MachineStackMarker.h 2017-07-07 04:56:23 UTC (rev 219238)
@@ -21,12 +21,10 @@
#pragma once
-#include "MachineContext.h"
#include "RegisterState.h"
-#include <wtf/DoublyLinkedList.h>
#include <wtf/Lock.h>
#include <wtf/ScopedLambda.h>
-#include <wtf/ThreadSpecific.h>
+#include <wtf/ThreadGroup.h>
namespace JSC {
@@ -45,58 +43,22 @@
WTF_MAKE_NONCOPYABLE(MachineThreads);
public:
MachineThreads();
- ~MachineThreads();
void gatherConservativeRoots(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, CurrentThreadState*);
- JS_EXPORT_PRIVATE void addCurrentThread(); // Only needs to be called by clients that can use the same heap from multiple threads.
+ // Only needs to be called by clients that can use the same heap from multiple threads.
+ void addCurrentThread() { m_threadGroup->addCurrentThread(); }
- class MachineThread : public DoublyLinkedListNode<MachineThread> {
- WTF_MAKE_FAST_ALLOCATED;
- public:
- MachineThread();
+ std::mutex& getLock() { return m_threadGroup->getLock(); }
+ const ListHashSet<Thread*>& threads(const AbstractLocker& locker) const { return m_threadGroup->threads(locker); }
- struct Registers {
- void* stackPointer() const;
-#if ENABLE(SAMPLING_PROFILER)
- void* framePointer() const;
- void* instructionPointer() const;
- void* llintPC() const;
-#endif // ENABLE(SAMPLING_PROFILER)
- PlatformRegisters regs;
- };
-
- Expected<void, Thread::PlatformSuspendError> suspend() { return m_thread->suspend(); }
- void resume() { m_thread->resume(); }
- size_t getRegisters(Registers& regs);
- std::pair<void*, size_t> captureStack(void* stackTop);
-
- WTF::ThreadIdentifier threadID() const { return m_thread->id(); }
- void* stackBase() const { return m_thread->stack().origin(); }
- void* stackEnd() const { return m_thread->stack().end(); }
-
- Ref<WTF::Thread> m_thread;
- MachineThread* m_next { nullptr };
- MachineThread* m_prev { nullptr };
- };
-
- Lock& getLock() { return m_registeredThreadsMutex; }
- const DoublyLinkedList<MachineThread>& threadsListHead(const AbstractLocker&) const { ASSERT(m_registeredThreadsMutex.isLocked()); return m_registeredThreads; }
- MachineThread* machineThreadForCurrentThread();
-
private:
void gatherFromCurrentThread(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, CurrentThreadState&);
- void tryCopyOtherThreadStack(MachineThread*, void*, size_t capacity, size_t*);
+ void tryCopyOtherThreadStack(Thread&, void*, size_t capacity, size_t*);
bool tryCopyOtherThreadStacks(const AbstractLocker&, void*, size_t capacity, size_t*);
- static void THREAD_SPECIFIC_CALL removeThread(void*);
-
- void removeThreadIfFound(ThreadIdentifier);
-
- Lock m_registeredThreadsMutex;
- DoublyLinkedList<MachineThread> m_registeredThreads;
- WTF::ThreadSpecificKey m_threadSpecificForMachineThreads;
+ Ref<ThreadGroup> m_threadGroup;
};
#define DECLARE_AND_COMPUTE_CURRENT_THREAD_STATE(stateName) \
Modified: trunk/Source/_javascript_Core/runtime/SamplingProfiler.cpp (219237 => 219238)
--- trunk/Source/_javascript_Core/runtime/SamplingProfiler.cpp 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/_javascript_Core/runtime/SamplingProfiler.cpp 2017-07-07 04:56:23 UTC (rev 219238)
@@ -39,6 +39,7 @@
#include "JSCInlines.h"
#include "JSFunction.h"
#include "LLIntPCRanges.h"
+#include "MachineContext.h"
#include "MarkedBlock.h"
#include "MarkedBlockSet.h"
#include "MarkedSpaceInlines.h"
@@ -165,10 +166,9 @@
bool isValidFramePointer(void* exec)
{
uint8_t* fpCast = bitwise_cast<uint8_t*>(exec);
- const auto& threadList = m_vm.heap.machineThreads().threadsListHead(m_machineThreadsLocker);
- for (MachineThreads::MachineThread* thread = threadList.head(); thread; thread = thread->next()) {
- uint8_t* stackBase = static_cast<uint8_t*>(thread->stackBase());
- uint8_t* stackLimit = static_cast<uint8_t*>(thread->stackEnd());
+ for (auto* thread : m_vm.heap.machineThreads().threads(m_machineThreadsLocker)) {
+ uint8_t* stackBase = static_cast<uint8_t*>(thread->stack().origin());
+ uint8_t* stackLimit = static_cast<uint8_t*>(thread->stack().end());
RELEASE_ASSERT(stackBase);
RELEASE_ASSERT(stackLimit);
if (fpCast <= stackBase && fpCast >= stackLimit)
@@ -278,7 +278,6 @@
, m_weakRandom()
, m_stopwatch(WTFMove(stopwatch))
, m_timingInterval(std::chrono::microseconds(Options::sampleInterval()))
- , m_jscExecutionThread(nullptr)
, m_isPaused(false)
, m_isShutDown(false)
{
@@ -338,7 +337,7 @@
if (m_vm.entryScope) {
double nowTime = m_stopwatch->elapsedTime();
- LockHolder machineThreadsLocker(m_vm.heap.machineThreads().getLock());
+ auto machineThreadsLocker = holdLock(m_vm.heap.machineThreads().getLock());
LockHolder codeBlockSetLocker(m_vm.heap.codeBlockSet().getLock());
LockHolder executableAllocatorLocker(ExecutableAllocator::singleton().getLock());
@@ -352,12 +351,12 @@
bool topFrameIsLLInt = false;
void* llintPC;
{
- MachineThreads::MachineThread::Registers registers;
+ PlatformRegisters registers;
m_jscExecutionThread->getRegisters(registers);
- machineFrame = registers.framePointer();
+ machineFrame = MachineContext::framePointer(registers);
callFrame = static_cast<ExecState*>(machineFrame);
- machinePC = registers.instructionPointer();
- llintPC = registers.llintPC();
+ machinePC = MachineContext::instructionPointer(registers);
+ llintPC = MachineContext::llintInstructionPointer(registers);
}
// FIXME: Lets have a way of detecting when we're parsing code.
// https://bugs.webkit.org/show_bug.cgi?id=152761
@@ -678,7 +677,7 @@
void SamplingProfiler::noticeCurrentThreadAsJSCExecutionThread(const AbstractLocker&)
{
ASSERT(m_lock.isLocked());
- m_jscExecutionThread = m_vm.heap.machineThreads().machineThreadForCurrentThread();
+ m_jscExecutionThread = &Thread::current();
}
void SamplingProfiler::noticeCurrentThreadAsJSCExecutionThread()
Modified: trunk/Source/_javascript_Core/runtime/SamplingProfiler.h (219237 => 219238)
--- trunk/Source/_javascript_Core/runtime/SamplingProfiler.h 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/_javascript_Core/runtime/SamplingProfiler.h 2017-07-07 04:56:23 UTC (rev 219238)
@@ -196,7 +196,7 @@
double m_lastTime;
Lock m_lock;
RefPtr<Thread> m_thread;
- MachineThreads::MachineThread* m_jscExecutionThread;
+ RefPtr<Thread> m_jscExecutionThread;
bool m_isPaused;
bool m_isShutDown;
bool m_needsReportAtExit { false };
Modified: trunk/Source/_javascript_Core/wasm/WasmMachineThreads.cpp (219237 => 219238)
--- trunk/Source/_javascript_Core/wasm/WasmMachineThreads.cpp 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/_javascript_Core/wasm/WasmMachineThreads.cpp 2017-07-07 04:56:23 UTC (rev 219238)
@@ -55,10 +55,8 @@
void resetInstructionCacheOnAllThreads()
{
auto locker = holdLock(wasmThreads().getLock());
-
- const DoublyLinkedList<MachineThreads::MachineThread>& threads = wasmThreads().threadsListHead(locker);
- for (const auto* thread = threads.head(); thread; thread = thread->next()) {
- sendMessage(thread->m_thread.get(), [] (const PlatformRegisters&) {
+ for (auto* thread : wasmThreads().threads(locker)) {
+ sendMessage(*thread, [] (const PlatformRegisters&) {
// It's likely that the signal handler will already reset the instruction cache but we might as well be sure.
WTF::crossModifyingCodeFence();
});
Modified: trunk/Source/WTF/ChangeLog (219237 => 219238)
--- trunk/Source/WTF/ChangeLog 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/WTF/ChangeLog 2017-07-07 04:56:23 UTC (rev 219238)
@@ -1,3 +1,69 @@
+2017-07-05 Yusuke Suzuki <utatane....@gmail.com>
+
+ [WTF] Implement WTF::ThreadGroup
+ https://bugs.webkit.org/show_bug.cgi?id=174081
+
+ Reviewed by Mark Lam.
+
+ This patch implements WTF::ThreadGroup. It implements core of JSC::MachineThreads with more reliable way.
+ JSC::MachineThreads was complicated because of managing dead threads. Each JSC::MachineThreads has its
+ own TLS with a registered destructor. And everytime a thread dies, the registered TLS destructor is called.
+ And this destructor will remove the current dying thread from JSC::MachineThreads.
+
+ However the above implementation is tricky. And each JSC::MachineThreads requires own TLS space, which is
+ not considered in WTF's Windows ThreadSpecific implementation. Current design works well since we only
+ have small number of MachineThreads right now.
+
+ Instead, we use more reliable way. After introducing WTF::Thread, WTF::Thread has WTF::Thread::didExit,
+ which is called when associated TLS (with WTF::Thread) is destroyed. We leverage this mechanism to remove
+ WTF::Thread from MachineThreads.
+
+ This patch introduces WTF::ThreadGroup. It is tightly integrated with WTF::Thread: WTF::Thread knows
+ ThreadGroups which includes this thread. And WTF::ThreadGroup of course knows WTF::Threads added to it.
+ WTF::Thread::didExit carefully remove itself from WTF::ThreadGroups.
+
+ The most important part of this patch is locking. WTF::Thread can die. And WTF::ThreadGroup can die.
+ If we take a design using two fine grain locks in WTF::Thread and WTF::ThreadGroup, we easily encounter
+ dead lock. Consider the following case.
+
+ 1. When adding WTF::Thread (TH) to WTF::ThreadGroup (THG), we first hold a lock of THG, and hold a lock of TH (locking order is THG -> TH).
+ 2. When TH dies, TH need to hold a lock of TH to iterate THGs. And we hold a lock of THG to unregister TH from it (locking order is TH -> THG).
+ 3. When suspending and resuming THs in THG, we first hold a lock of THG. And then, we hold a lock of TH to suspend and resume it (locking order is THG -> TH).
+ 4. When destroying THG, we need to hold a lock of TH to unregister THG from TH. We can hold a lock of THG before that (locking order is THG -> TH).
+
+ Then, it easily causes dead lock. We cannot swap the locking order of (2) since iterating THG requires a lock of TH.
+ To solve this problem, we introduce one global lock ThreadGroup::destructionMutex (GL).
+
+ 1. When adding WTF::Thread (TH) to WTF::ThreadGroup (THG), we first hold GL, and hold a lock of THG. Do not hold a
+ lock of TH. TH's thread groups information is guarded by GL instead of a lock of TH (locking order is GL -> THG).
+ 2. When TH dies, TH need to hold GL to iterate THGs. And we hold a lock of THG to unregister TH from it (locking order is GL -> THG).
+ 3. When suspending and resuming THs in THG, we first hold a lock of THG. And then, we hold a lock of TH to suspend and resume it (locking order is THG -> TH).
+ 4. When destroying THG, we need to hold GL to unregister THG from TH. We can hold a lock of THG after that (locking order is GL -> THG).
+
+ We still have a lock of THG. By separating GL and THG's lock, we can hold a lock of THG while completely unrelated TH is destructed which takes a lock of GL and unrelated THG.
+
+ * WTF.xcodeproj/project.pbxproj:
+ * wtf/AutomaticThread.cpp:
+ * wtf/CMakeLists.txt:
+ * wtf/CrossThreadCopier.h:
+ * wtf/ParkingLot.h:
+ * wtf/ThreadGroup.cpp: Copied from Source/_javascript_Core/wasm/WasmMachineThreads.cpp.
+ (WTF::ThreadGroup::destructionMutex):
+ (WTF::ThreadGroup::~ThreadGroup):
+ (WTF::ThreadGroup::add):
+ (WTF::ThreadGroup::addCurrentThread):
+ (WTF::ThreadGroup::removeCurrentThread):
+ * wtf/ThreadGroup.h: Copied from Source/_javascript_Core/wasm/WasmMachineThreads.cpp.
+ (WTF::ThreadGroup::create):
+ (WTF::ThreadGroup::threads):
+ (WTF::ThreadGroup::getLock):
+ * wtf/Threading.cpp:
+ (WTF::Thread::didExit):
+ (WTF::Thread::addToThreadGroup):
+ (WTF::Thread::removeFromThreadGroup):
+ * wtf/Threading.h:
+ (WTF::Thread::canAddToThreadGroup):
+
2017-07-06 Yusuke Suzuki <utatane....@gmail.com>
[WTF] Clean up StringStatics.cpp by using LazyNeverDestroyed<> for Atoms
Modified: trunk/Source/WTF/WTF.xcodeproj/project.pbxproj (219237 => 219238)
--- trunk/Source/WTF/WTF.xcodeproj/project.pbxproj 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/WTF/WTF.xcodeproj/project.pbxproj 2017-07-07 04:56:23 UTC (rev 219238)
@@ -131,6 +131,7 @@
DCEE22011CEA7551000C2396 /* BlockObjCExceptions.mm in Sources */ = {isa = PBXBuildFile; fileRef = DCEE21FD1CEA7551000C2396 /* BlockObjCExceptions.mm */; };
DCEE22031CEA7551000C2396 /* PlatformUserPreferredLanguagesMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = DCEE21FF1CEA7551000C2396 /* PlatformUserPreferredLanguagesMac.mm */; };
E15556F518A0CC18006F48FB /* CryptographicUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E15556F318A0CC18006F48FB /* CryptographicUtilities.cpp */; };
+ E311FB171F0A568B003C08DE /* ThreadGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E311FB151F0A568B003C08DE /* ThreadGroup.cpp */; };
E3200AB81E9A536D003B59D2 /* ThreadHolder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3200AB51E9A536D003B59D2 /* ThreadHolder.cpp */; };
E38C41251EB4E04C0042957D /* CPUTimeCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = E38C41241EB4E04C0042957D /* CPUTimeCocoa.mm */; };
E38C41281EB4E0680042957D /* CPUTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38C41261EB4E0680042957D /* CPUTime.cpp */; };
@@ -539,6 +540,8 @@
DE5A09FB1BA36992003D4424 /* CommonCryptoSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonCryptoSPI.h; sourceTree = "<group>"; };
E15556F318A0CC18006F48FB /* CryptographicUtilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptographicUtilities.cpp; sourceTree = "<group>"; };
E15556F418A0CC18006F48FB /* CryptographicUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptographicUtilities.h; sourceTree = "<group>"; };
+ E311FB151F0A568B003C08DE /* ThreadGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadGroup.cpp; sourceTree = "<group>"; };
+ E311FB161F0A568B003C08DE /* ThreadGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadGroup.h; sourceTree = "<group>"; };
E3200AB41E9A536D003B59D2 /* PlatformRegisters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformRegisters.h; sourceTree = "<group>"; };
E3200AB51E9A536D003B59D2 /* ThreadHolder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadHolder.cpp; sourceTree = "<group>"; };
E3200AB61E9A536D003B59D2 /* ThreadHolder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadHolder.h; sourceTree = "<group>"; };
@@ -956,6 +959,8 @@
E3E158251EADA53C004A079D /* SystemFree.h */,
0FB317C31C488001007E395A /* SystemTracing.h */,
A8A4732F151A825B004123FF /* ThreadFunctionInvocation.h */,
+ E311FB151F0A568B003C08DE /* ThreadGroup.cpp */,
+ E311FB161F0A568B003C08DE /* ThreadGroup.h */,
E3200AB51E9A536D003B59D2 /* ThreadHolder.cpp */,
E3200AB61E9A536D003B59D2 /* ThreadHolder.h */,
A8A47330151A825B004123FF /* ThreadHolderPthreads.cpp */,
@@ -1388,6 +1393,7 @@
A8A47448151A825B004123FF /* ThreadHolderPthreads.cpp in Sources */,
A8A4744A151A825B004123FF /* Threading.cpp in Sources */,
A8A4744E151A825B004123FF /* ThreadingPthreads.cpp in Sources */,
+ E311FB171F0A568B003C08DE /* ThreadGroup.cpp in Sources */,
5311BD5C1EA822F900525281 /* ThreadMessage.cpp in Sources */,
0F66B2901DC97BAB004A1D3F /* TimeWithDynamicClockType.cpp in Sources */,
1C181C8F1D307AB800F5FA16 /* UTextProvider.cpp in Sources */,
Modified: trunk/Source/WTF/wtf/AutomaticThread.cpp (219237 => 219238)
--- trunk/Source/WTF/wtf/AutomaticThread.cpp 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/WTF/wtf/AutomaticThread.cpp 2017-07-07 04:56:23 UTC (rev 219238)
@@ -27,6 +27,7 @@
#include "AutomaticThread.h"
#include "DataLog.h"
+#include "Threading.h"
namespace WTF {
Modified: trunk/Source/WTF/wtf/CMakeLists.txt (219237 => 219238)
--- trunk/Source/WTF/wtf/CMakeLists.txt 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/WTF/wtf/CMakeLists.txt 2017-07-07 04:56:23 UTC (rev 219238)
@@ -132,6 +132,7 @@
StringPrintStream.h
SystemFree.h
SystemTracing.h
+ ThreadGroup.h
ThreadHolder.cpp
ThreadMessage.h
ThreadSafeRefCounted.h
@@ -246,6 +247,7 @@
StackStats.cpp
StackTrace.cpp
StringPrintStream.cpp
+ ThreadGroup.cpp
ThreadMessage.cpp
Threading.cpp
TimeWithDynamicClockType.cpp
Modified: trunk/Source/WTF/wtf/CrossThreadCopier.h (219237 => 219238)
--- trunk/Source/WTF/wtf/CrossThreadCopier.h 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/WTF/wtf/CrossThreadCopier.h 2017-07-07 04:56:23 UTC (rev 219238)
@@ -35,6 +35,7 @@
#include <wtf/Forward.h>
#include <wtf/HashSet.h>
#include <wtf/RefPtr.h>
+#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/text/WTFString.h>
namespace WTF {
Modified: trunk/Source/WTF/wtf/ParkingLot.h (219237 => 219238)
--- trunk/Source/WTF/wtf/ParkingLot.h 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/WTF/wtf/ParkingLot.h 2017-07-07 04:56:23 UTC (rev 219238)
@@ -28,11 +28,12 @@
#include <wtf/Atomics.h>
#include <wtf/ScopedLambda.h>
-#include <wtf/Threading.h>
#include <wtf/TimeWithDynamicClockType.h>
namespace WTF {
+class Thread;
+
class ParkingLot {
ParkingLot() = delete;
ParkingLot(const ParkingLot&) = delete;
Copied: trunk/Source/WTF/wtf/ThreadGroup.cpp (from rev 219237, trunk/Source/_javascript_Core/wasm/WasmMachineThreads.cpp) (0 => 219238)
--- trunk/Source/WTF/wtf/ThreadGroup.cpp (rev 0)
+++ trunk/Source/WTF/wtf/ThreadGroup.cpp 2017-07-07 04:56:23 UTC (rev 219238)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 Yusuke Suzuki <utatane....@gmail.com>.
+ *
+ * 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 "config.h"
+#include "ThreadGroup.h"
+
+#include <wtf/NeverDestroyed.h>
+
+namespace WTF {
+
+std::mutex& ThreadGroup::destructionMutex()
+{
+ static NeverDestroyed<std::mutex> mutex;
+ return mutex.get();
+}
+
+ThreadGroup::~ThreadGroup()
+{
+ auto destructionMutexLocker = holdLock(destructionMutex());
+ auto locker = holdLock(m_lock);
+ for (auto* thread : m_threads)
+ thread->removeFromThreadGroup(destructionMutexLocker, *this);
+}
+
+bool ThreadGroup::add(Thread& thread)
+{
+ auto destructionMutexLocker = holdLock(destructionMutex());
+ auto locker = holdLock(m_lock);
+ if (!thread.canAddToThreadGroup(destructionMutexLocker))
+ return false;
+ if (m_threads.add(&thread).isNewEntry)
+ thread.addToThreadGroup(destructionMutexLocker, *this);
+ return true;
+}
+
+void ThreadGroup::addCurrentThread()
+{
+ bool isAdded = add(Thread::current());
+ ASSERT_UNUSED(isAdded, isAdded);
+}
+
+void ThreadGroup::removeCurrentThread(const AbstractLocker&, Thread& thread)
+{
+ auto locker = holdLock(m_lock);
+ m_threads.remove(&thread);
+}
+
+} // namespace WTF
Copied: trunk/Source/WTF/wtf/ThreadGroup.h (from rev 219237, trunk/Source/_javascript_Core/wasm/WasmMachineThreads.cpp) (0 => 219238)
--- trunk/Source/WTF/wtf/ThreadGroup.h (rev 0)
+++ trunk/Source/WTF/wtf/ThreadGroup.h 2017-07-07 04:56:23 UTC (rev 219238)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 Yusuke Suzuki <utatane....@gmail.com>.
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <wtf/ListHashSet.h>
+#include <wtf/Lock.h>
+#include <wtf/Threading.h>
+
+namespace WTF {
+
+class ThreadGroup : public ThreadSafeRefCounted<ThreadGroup> {
+public:
+ friend class Thread;
+
+ static Ref<ThreadGroup> create()
+ {
+ return adoptRef(*new ThreadGroup());
+ }
+
+ WTF_EXPORT_PRIVATE bool add(Thread&);
+ WTF_EXPORT_PRIVATE void addCurrentThread();
+
+ const ListHashSet<Thread*>& threads(const AbstractLocker&) const { return m_threads; }
+
+ std::mutex& getLock() { return m_lock; }
+
+ WTF_EXPORT_PRIVATE ~ThreadGroup();
+
+private:
+ ThreadGroup() = default;
+
+ static std::mutex& destructionMutex();
+ void removeCurrentThread(const AbstractLocker& destructionMutexLocker, Thread&);
+
+ // We use std::mutex since it can be used when deallocating TLS.
+ std::mutex m_lock;
+ ListHashSet<Thread*> m_threads;
+};
+
+}
+
+using WTF::ThreadGroup;
Modified: trunk/Source/WTF/wtf/Threading.cpp (219237 => 219238)
--- trunk/Source/WTF/wtf/Threading.cpp 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/WTF/wtf/Threading.cpp 2017-07-07 04:56:23 UTC (rev 219238)
@@ -26,8 +26,6 @@
#include "config.h"
#include "Threading.h"
-#include "dtoa.h"
-#include "dtoa/cached-powers.h"
#include <algorithm>
#include <cmath>
#include <cstring>
@@ -34,6 +32,7 @@
#include <wtf/DateMath.h>
#include <wtf/PrintStream.h>
#include <wtf/RandomNumberSeed.h>
+#include <wtf/ThreadGroup.h>
#include <wtf/ThreadHolder.h>
#include <wtf/ThreadMessage.h>
#include <wtf/ThreadingPrimitives.h>
@@ -130,12 +129,48 @@
m_stack = StackBounds::currentThreadStackBounds();
}
+static bool shouldRemoveThreadFromThreadGroup()
+{
+#if OS(WINDOWS)
+ // On Windows the thread specific destructor is also called when the
+ // main thread is exiting. This may lead to the main thread waiting
+ // forever for the thread group lock when exiting, if the sampling
+ // profiler thread was terminated by the system while holding the
+ // thread group lock.
+ if (WTF::isMainThread())
+ return false;
+#endif
+ return true;
+}
+
+bool Thread::canAddToThreadGroup(const AbstractLocker&)
+{
+ std::lock_guard<std::mutex> locker(m_mutex);
+ return !m_didExit;
+}
+
void Thread::didExit()
{
+ auto destructionMutexLocker = holdLock(ThreadGroup::destructionMutex());
+ if (shouldRemoveThreadFromThreadGroup()) {
+ for (auto* threadGroup : m_threadGroups)
+ threadGroup->removeCurrentThread(destructionMutexLocker, *this);
+ }
std::lock_guard<std::mutex> locker(m_mutex);
m_didExit = true;
}
+void Thread::addToThreadGroup(const AbstractLocker& destructionMutexLocker, ThreadGroup& threadGroup)
+{
+ ASSERT(canAddToThreadGroup(destructionMutexLocker));
+ m_threadGroups.add(&threadGroup);
+}
+
+void Thread::removeFromThreadGroup(const AbstractLocker&, ThreadGroup& threadGroup)
+{
+ m_threadGroups.remove(&threadGroup);
+}
+
void Thread::setCurrentThreadIsUserInteractive(int relativePriority)
{
#if HAVE(QOS_CLASSES)
Modified: trunk/Source/WTF/wtf/Threading.h (219237 => 219238)
--- trunk/Source/WTF/wtf/Threading.h 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/WTF/wtf/Threading.h 2017-07-07 04:56:23 UTC (rev 219238)
@@ -36,6 +36,7 @@
#include <wtf/Atomics.h>
#include <wtf/Expected.h>
#include <wtf/Function.h>
+#include <wtf/HashSet.h>
#include <wtf/PlatformRegisters.h>
#include <wtf/RefPtr.h>
#include <wtf/StackBounds.h>
@@ -48,16 +49,19 @@
namespace WTF {
+class AbstractLocker;
class ThreadMessageData;
using ThreadIdentifier = uint32_t;
typedef void (*ThreadFunction)(void* argument);
+class ThreadGroup;
class ThreadHolder;
class PrintStream;
class Thread : public ThreadSafeRefCounted<Thread> {
public:
+ friend class ThreadGroup;
friend class ThreadHolder;
WTF_EXPORT_PRIVATE ~Thread();
@@ -175,11 +179,17 @@
void didJoin() { m_joinableState = Joined; }
bool hasExited() { return m_didExit; }
+ // These functions are only called from ThreadGroup.
+ bool canAddToThreadGroup(const AbstractLocker& destructionMutexLocker);
+ void addToThreadGroup(const AbstractLocker& destructionMutexLocker, ThreadGroup&);
+ void removeFromThreadGroup(const AbstractLocker& destructionMutexLocker, ThreadGroup&);
+
// WordLock & Lock rely on ThreadSpecific. But Thread object can be destroyed even after ThreadSpecific things are destroyed.
std::mutex m_mutex;
ThreadIdentifier m_id { 0 };
JoinableState m_joinableState { Joinable };
StackBounds m_stack { StackBounds::emptyBounds() };
+ HashSet<ThreadGroup*> m_threadGroups;
bool m_didExit { false };
#if USE(PTHREADS)
pthread_t m_handle;
Modified: trunk/Source/WebCore/ChangeLog (219237 => 219238)
--- trunk/Source/WebCore/ChangeLog 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/WebCore/ChangeLog 2017-07-07 04:56:23 UTC (rev 219238)
@@ -1,3 +1,12 @@
+2017-07-05 Yusuke Suzuki <utatane....@gmail.com>
+
+ [WTF] Implement WTF::ThreadGroup
+ https://bugs.webkit.org/show_bug.cgi?id=174081
+
+ Reviewed by Mark Lam.
+
+ * page/ResourceUsageThread.h:
+
2017-07-06 Yusuke Suzuki <utatane....@gmail.com>
[WTF] Clean up StringStatics.cpp by using LazyNeverDestroyed<> for Atoms
Modified: trunk/Source/WebCore/page/ResourceUsageThread.h (219237 => 219238)
--- trunk/Source/WebCore/page/ResourceUsageThread.h 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/WebCore/page/ResourceUsageThread.h 2017-07-07 04:56:23 UTC (rev 219238)
@@ -35,6 +35,7 @@
#include <wtf/Lock.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/Noncopyable.h>
+#include <wtf/Threading.h>
namespace JSC {
class VM;
Modified: trunk/Source/WebKit2/ChangeLog (219237 => 219238)
--- trunk/Source/WebKit2/ChangeLog 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/WebKit2/ChangeLog 2017-07-07 04:56:23 UTC (rev 219238)
@@ -1,3 +1,13 @@
+2017-07-05 Yusuke Suzuki <utatane....@gmail.com>
+
+ [WTF] Implement WTF::ThreadGroup
+ https://bugs.webkit.org/show_bug.cgi?id=174081
+
+ Reviewed by Mark Lam.
+
+ * Shared/AsyncRequest.h:
+ * UIProcess/Storage/ResourceLoadStatisticsStore.h:
+
2017-07-06 Chris Dumez <cdu...@apple.com>
Drop unused ResourceLoadStatistics members
Modified: trunk/Source/WebKit2/Shared/AsyncRequest.h (219237 => 219238)
--- trunk/Source/WebKit2/Shared/AsyncRequest.h 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/WebKit2/Shared/AsyncRequest.h 2017-07-07 04:56:23 UTC (rev 219238)
@@ -27,6 +27,7 @@
#ifndef AsyncRequest_h
#define AsyncRequest_h
+#include <wtf/Function.h>
#include <wtf/HashMap.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
Modified: trunk/Source/WebKit2/UIProcess/Storage/ResourceLoadStatisticsStore.h (219237 => 219238)
--- trunk/Source/WebKit2/UIProcess/Storage/ResourceLoadStatisticsStore.h 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Source/WebKit2/UIProcess/Storage/ResourceLoadStatisticsStore.h 2017-07-07 04:56:23 UTC (rev 219238)
@@ -29,6 +29,7 @@
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/MonotonicTime.h>
+#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/WallTime.h>
#include <wtf/text/WTFString.h>
Modified: trunk/Tools/ChangeLog (219237 => 219238)
--- trunk/Tools/ChangeLog 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Tools/ChangeLog 2017-07-07 04:56:23 UTC (rev 219238)
@@ -1,3 +1,17 @@
+2017-07-05 Yusuke Suzuki <utatane....@gmail.com>
+
+ [WTF] Implement WTF::ThreadGroup
+ https://bugs.webkit.org/show_bug.cgi?id=174081
+
+ Reviewed by Mark Lam.
+
+ Add WTF::ThreadGroup tests.
+
+ * TestWebKitAPI/CMakeLists.txt:
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WTF/ThreadGroup.cpp: Added.
+ (TestWebKitAPI::TEST):
+
2017-07-06 Yusuke Suzuki <utatane....@gmail.com>
[WTF] Clean up StringStatics.cpp by using LazyNeverDestroyed<> for Atoms
Modified: trunk/Tools/TestWebKitAPI/CMakeLists.txt (219237 => 219238)
--- trunk/Tools/TestWebKitAPI/CMakeLists.txt 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Tools/TestWebKitAPI/CMakeLists.txt 2017-07-07 04:56:23 UTC (rev 219238)
@@ -81,6 +81,7 @@
${TESTWEBKITAPI_DIR}/Tests/WTF/StringOperators.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/StringView.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/TextBreakIterator.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/ThreadGroup.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/Time.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/UniqueRef.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/Variant.cpp
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (219237 => 219238)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2017-07-07 04:42:04 UTC (rev 219237)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2017-07-07 04:56:23 UTC (rev 219238)
@@ -631,6 +631,7 @@
D34E08761E4E42E1005FF14A /* WKWebViewGetContents.mm in Sources */ = {isa = PBXBuildFile; fileRef = D3BE5E341E4CE85E00FD563A /* WKWebViewGetContents.mm */; };
E1220DCA155B28AA0013E2FC /* MemoryCacheDisableWithinResourceLoadDelegate.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = E1220DC9155B287D0013E2FC /* MemoryCacheDisableWithinResourceLoadDelegate.html */; };
E194E1BD177E53C7009C4D4E /* StopLoadingFromDidReceiveResponse.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = E194E1BC177E534A009C4D4E /* StopLoadingFromDidReceiveResponse.html */; };
+ E3DEA8111F0A589000CBC2E8 /* ThreadGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3DEA8101F0A588000CBC2E8 /* ThreadGroup.cpp */; };
ECA680CE1E68CC0900731D20 /* StringUtilities.mm in Sources */ = {isa = PBXBuildFile; fileRef = ECA680CD1E68CC0900731D20 /* StringUtilities.mm */; };
F415086D1DA040C50044BE9B /* play-audio-on-click.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F415086C1DA040C10044BE9B /* play-audio-on-click.html */; };
F41AB99F1EF4696B0083FA08 /* autofocus-contenteditable.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F41AB9981EF4692C0083FA08 /* autofocus-contenteditable.html */; };
@@ -1609,6 +1610,7 @@
E194E1BA177E5145009C4D4E /* StopLoadingFromDidReceiveResponse.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StopLoadingFromDidReceiveResponse.mm; sourceTree = "<group>"; };
E194E1BC177E534A009C4D4E /* StopLoadingFromDidReceiveResponse.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = StopLoadingFromDidReceiveResponse.html; sourceTree = "<group>"; };
E19DB9781B32137C00DB38D4 /* NavigatorLanguage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NavigatorLanguage.mm; sourceTree = "<group>"; };
+ E3DEA8101F0A588000CBC2E8 /* ThreadGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadGroup.cpp; sourceTree = "<group>"; };
E40019301ACE9B5C001B0A2A /* BloomFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BloomFilter.cpp; sourceTree = "<group>"; };
E490296714E2E3A4002BEDD1 /* TypingStyleCrash.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TypingStyleCrash.mm; sourceTree = "<group>"; };
E4A757D3178AEA5B00B5D7A4 /* Deque.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Deque.cpp; sourceTree = "<group>"; };
@@ -2391,6 +2393,7 @@
7C74D42D188228F300E5ED57 /* StringView.cpp */,
5597F8341D9596C80066BC21 /* SynchronizedFixedQueue.cpp */,
9329AA281DE3F81E003ABD07 /* TextBreakIterator.cpp */,
+ E3DEA8101F0A588000CBC2E8 /* ThreadGroup.cpp */,
5311BD5D1EA9490D00525281 /* ThreadMessages.cpp */,
0F2C20B71DCD544800542D9E /* Time.cpp */,
5C5E633D1D0B67940085A025 /* UniqueRef.cpp */,
@@ -2890,6 +2893,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ E3DEA8111F0A589000CBC2E8 /* ThreadGroup.cpp in Sources */,
7C83DE991D0A590C00FEBCF3 /* AtomicString.cpp in Sources */,
1ADAD1501D77A9F600212586 /* BlockPtr.mm in Sources */,
7C83DE9C1D0A590C00FEBCF3 /* BloomFilter.cpp in Sources */,
Added: trunk/Tools/TestWebKitAPI/Tests/WTF/ThreadGroup.cpp (0 => 219238)
--- trunk/Tools/TestWebKitAPI/Tests/WTF/ThreadGroup.cpp (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/ThreadGroup.cpp 2017-07-07 04:56:23 UTC (rev 219238)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2017 Yusuke Suzuki <utatane....@gmail.com>.
+ *
+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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 "config.h"
+
+#include <wtf/Condition.h>
+#include <wtf/ThreadGroup.h>
+#include <wtf/Vector.h>
+
+namespace TestWebKitAPI {
+
+enum class Mode { Add, AddCurrentThread };
+static void testThreadGroup(Mode mode)
+{
+ Ref<ThreadGroup> threadGroup = ThreadGroup::create();
+ unsigned numberOfThreads = 16;
+ unsigned waitingThreads = 0;
+ bool restarting = false;
+ Lock lock;
+ Condition condition;
+ Condition restartCondition;
+ Vector<RefPtr<Thread>> threads;
+
+ {
+ auto locker = holdLock(lock);
+ for (unsigned i = 0; i < numberOfThreads; ++i) {
+ RefPtr<Thread> thread = Thread::create("ThreadGroupWorker", [&] {
+ auto locker = holdLock(lock);
+ if (mode == Mode::AddCurrentThread)
+ threadGroup->addCurrentThread();
+ ++waitingThreads;
+ condition.notifyOne();
+ restartCondition.wait(lock, [&] {
+ return restarting;
+ });
+ });
+ if (mode == Mode::Add)
+ EXPECT_EQ(threadGroup->add(*thread), true);
+ threads.append(thread);
+ }
+
+ condition.wait(lock, [&] {
+ return waitingThreads == numberOfThreads;
+ });
+ }
+
+ {
+ auto threadGroupLocker = holdLock(threadGroup->getLock());
+ EXPECT_EQ(threads.size(), numberOfThreads);
+ EXPECT_EQ(threadGroup->threads(threadGroupLocker).size(), numberOfThreads);
+ {
+ auto locker = holdLock(lock);
+ restarting = true;
+ restartCondition.notifyAll();
+ }
+
+ // While holding ThreadGroup lock, threads do not exit.
+ WTF::sleep(0.1);
+ EXPECT_EQ(threadGroup->threads(threadGroupLocker).size(), numberOfThreads);
+ }
+ {
+ for (auto& thread : threads)
+ thread->waitForCompletion();
+
+ auto threadGroupLocker = holdLock(threadGroup->getLock());
+ EXPECT_EQ(threadGroup->threads(threadGroupLocker).size(), 0u);
+ }
+}
+
+TEST(WTF, ThreadGroupAdd)
+{
+ testThreadGroup(Mode::Add);
+}
+
+TEST(WTF, ThreadGroupAddCurrentThread)
+{
+ testThreadGroup(Mode::AddCurrentThread);
+}
+
+TEST(WTF, ThreadGroupDoNotAddDeadThread)
+{
+ Ref<ThreadGroup> threadGroup = ThreadGroup::create();
+ RefPtr<Thread> thread = Thread::create("ThreadGroupWorker", [&] { });
+ thread->waitForCompletion();
+ EXPECT_EQ(threadGroup->add(*thread), false);
+
+ auto threadGroupLocker = holdLock(threadGroup->getLock());
+ EXPECT_EQ(threadGroup->threads(threadGroupLocker).size(), 0u);
+}
+
+TEST(WTF, ThreadGroupAddDuplicateThreads)
+{
+ bool restarting = false;
+ Lock lock;
+ Condition restartCondition;
+ Ref<ThreadGroup> threadGroup = ThreadGroup::create();
+ RefPtr<Thread> thread = Thread::create("ThreadGroupWorker", [&] {
+ auto locker = holdLock(lock);
+ restartCondition.wait(lock, [&] {
+ return restarting;
+ });
+ });
+ EXPECT_EQ(threadGroup->add(*thread), true);
+ EXPECT_EQ(threadGroup->add(*thread), true);
+
+ {
+ auto threadGroupLocker = holdLock(threadGroup->getLock());
+ EXPECT_EQ(threadGroup->threads(threadGroupLocker).size(), 1u);
+ }
+
+ {
+ auto locker = holdLock(lock);
+ restarting = true;
+ restartCondition.notifyAll();
+ }
+ thread->waitForCompletion();
+ {
+ auto threadGroupLocker = holdLock(threadGroup->getLock());
+ EXPECT_EQ(threadGroup->threads(threadGroupLocker).size(), 0u);
+ }
+}
+
+} // namespace TestWebKitAPI