void 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. machineThreads->removeThreadIfFound(getCurrentPlatformThread()); } }
void MachineThreads::addCurrentThread() { ASSERT(!m_heap->globalData()->exclusiveThread || m_heap->globalData()->exclusiveThread == currentThread()); if (!m_threadSpecific || threadSpecificGet(m_threadSpecific)) return; threadSpecificSet(m_threadSpecific, this); Thread* thread = new Thread(getCurrentPlatformThread(), wtfThreadData().stack().origin()); MutexLocker lock(m_registeredThreadsMutex); thread->next = m_registeredThreads; m_registeredThreads = thread; }
void MachineThreads::gatherConservativeRoots(ConservativeRoots& conservativeRoots, void* stackCurrent) { gatherFromCurrentThread(conservativeRoots, stackCurrent); if (m_threadSpecific) { PlatformThread currentPlatformThread = getCurrentPlatformThread(); MutexLocker lock(m_registeredThreadsMutex); #ifndef NDEBUG // Forbid malloc during the gather phase. The gather phase suspends // threads, so a malloc during gather would risk a deadlock with a // thread that had been suspended while holding the malloc lock. fastMallocForbid(); #endif for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { if (!equalThread(thread->platformThread, currentPlatformThread)) suspendThread(thread->platformThread); } // It is safe to access the registeredThreads list, because we earlier asserted that locks are being held, // and since this is a shared heap, they are real locks. for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { if (!equalThread(thread->platformThread, currentPlatformThread)) gatherFromOtherThread(conservativeRoots, thread); } for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { if (!equalThread(thread->platformThread, currentPlatformThread)) resumeThread(thread->platformThread); } #ifndef NDEBUG fastMallocAllow(); #endif } }
void MachineThreads::removeCurrentThread() { PlatformThread currentPlatformThread = getCurrentPlatformThread(); MutexLocker lock(m_registeredThreadsMutex); if (equalThread(currentPlatformThread, m_registeredThreads->platformThread)) { Thread* t = m_registeredThreads; m_registeredThreads = m_registeredThreads->next; delete t; } else { Thread* last = m_registeredThreads; Thread* t; for (t = m_registeredThreads->next; t; t = t->next) { if (equalThread(t->platformThread, currentPlatformThread)) { last->next = t->next; break; } last = t; } ASSERT(t); // If t is NULL, we never found ourselves in the list. delete t; } }
bool MachineThreads::tryCopyOtherThreadStacks(MutexLocker&, 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>. static StaticSpinLock mutex; std::lock_guard<StaticSpinLock> lock(mutex); *size = 0; PlatformThread currentPlatformThread = getCurrentPlatformThread(); int numberOfThreads = 0; // Using 0 to denote that we haven't counted the number of threads yet. int index = 1; Thread* threadsToBeDeleted = nullptr; Thread* previousThread = nullptr; for (Thread* thread = m_registeredThreads; thread; index++) { if (*thread != currentPlatformThread) { bool success = thread->suspend(); #if OS(DARWIN) if (!success) { if (!numberOfThreads) { for (Thread* countedThread = m_registeredThreads; countedThread; countedThread = countedThread->next) numberOfThreads++; } // Re-do the suspension to get the actual failure result for logging. kern_return_t error = thread_suspend(thread->platformThread); ASSERT(error != KERN_SUCCESS); WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, "JavaScript garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] platformThread %p.", error, index, numberOfThreads, thread, reinterpret_cast<void*>(thread->platformThread)); // 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. Thread* nextThread = thread->next; thread->next = threadsToBeDeleted; threadsToBeDeleted = thread; if (previousThread) previousThread->next = nextThread; else m_registeredThreads = nextThread; thread = nextThread; continue; } #else UNUSED_PARAM(numberOfThreads); UNUSED_PARAM(previousThread); ASSERT_UNUSED(success, success); #endif } previousThread = thread; thread = thread->next; } for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { if (*thread != currentPlatformThread) tryCopyOtherThreadStack(thread, buffer, capacity, size); } for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { if (*thread != currentPlatformThread) thread->resume(); } for (Thread* thread = threadsToBeDeleted; thread; ) { Thread* nextThread = thread->next; delete thread; thread = nextThread; } return *size <= capacity; }
static Thread* createForCurrentThread() { return new Thread(getCurrentPlatformThread(), wtfThreadData().stack().origin()); }