void ThreadState::cleanup() { checkThread(); // Finish sweeping. completeSweep(); { // Grab the threadAttachMutex to ensure only one thread can shutdown at // a time and that no other thread can do a global GC. It also allows // safe iteration of the attachedThreads set which happens as part of // thread local GC asserts. We enter a safepoint while waiting for the // lock to avoid a dead-lock where another thread has already requested // GC. SafePointAwareMutexLocker locker(threadAttachMutex(), NoHeapPointersOnStack); // From here on ignore all conservatively discovered // pointers into the heap owned by this thread. m_isTerminating = true; // Set the terminate flag on all heap pages of this thread. This is used to // ensure we don't trace pages on other threads that are not part of the // thread local GC. prepareHeapForTermination(); // Do thread local GC's as long as the count of thread local Persistents // changes and is above zero. PersistentAnchor* anchor = static_cast<PersistentAnchor*>(m_persistents.get()); int oldCount = -1; int currentCount = anchor->numberOfPersistents(); ASSERT(currentCount >= 0); while (currentCount != oldCount) { Heap::collectGarbageForTerminatingThread(this); oldCount = currentCount; currentCount = anchor->numberOfPersistents(); } // We should not have any persistents left when getting to this point, // if we have it is probably a bug so adding a debug ASSERT to catch this. ASSERT(!currentCount); // All of pre-finalizers should be consumed. ASSERT(m_preFinalizers.isEmpty()); RELEASE_ASSERT(gcState() == NoGCScheduled); // Add pages to the orphaned page pool to ensure any global GCs from this point // on will not trace objects on this thread's heaps. cleanupPages(); ASSERT(attachedThreads().contains(this)); attachedThreads().remove(this); } for (auto& task : m_cleanupTasks) task->postCleanup(); m_cleanupTasks.clear(); }
void ThreadState::attach() { RELEASE_ASSERT(!Heap::s_shutdownCalled); MutexLocker locker(threadAttachMutex()); ThreadState* state = new ThreadState(); attachedThreads().add(state); }
void ThreadState::detach() { ThreadState* state = current(); MutexLocker locker(threadAttachMutex()); attachedThreads().remove(state); delete state; }
void ThreadState::shutdownHeapIfNecessary() { // We don't need to enter a safe point before acquiring threadAttachMutex // because this thread is already detached. MutexLocker locker(threadAttachMutex()); // We start shutting down the heap if there is no running thread // and Heap::shutdown() is already called. if (!attachedThreads().size() && Heap::s_shutdownCalled) Heap::doShutdown(); }
void ThreadState::visitPersistentRoots(Visitor* visitor) { TRACE_EVENT0("blink_gc", "ThreadState::visitPersistentRoots"); { // All threads are at safepoints so this is not strictly necessary. // However we acquire the mutex to make mutation and traversal of this // list symmetrical. MutexLocker locker(globalRootsMutex()); globalRoots()->trace(visitor); } for (ThreadState* state : attachedThreads()) state->visitPersistents(visitor); }
void ThreadState::detachMainThread() { // Enter a safe point before trying to acquire threadAttachMutex // to avoid dead lock if another thread is preparing for GC, has acquired // threadAttachMutex and waiting for other threads to pause or reach a // safepoint. ThreadState* state = mainThreadState(); // 1. Finish sweeping. state->completeSweep(); { SafePointAwareMutexLocker locker(threadAttachMutex(), NoHeapPointersOnStack); // 2. Add the main thread's heap pages to the orphaned pool. state->cleanupPages(); // 3. Detach the main thread. ASSERT(attachedThreads().contains(state)); attachedThreads().remove(state); state->~ThreadState(); } shutdownHeapIfNecessary(); }
void ThreadState::visitStackRoots(Visitor* visitor) { TRACE_EVENT0("blink_gc", "ThreadState::visitStackRoots"); for (ThreadState* state : attachedThreads()) state->visitStack(visitor); }
void ThreadState::attach(intptr_t* startOfStack) { MutexLocker locker(threadAttachMutex()); ThreadState* state = new ThreadState(startOfStack); attachedThreads().add(state); }
void ThreadState::init(intptr_t* startOfStack) { s_threadSpecific = new WTF::ThreadSpecific<ThreadState*>(); new(s_mainThreadStateStorage) ThreadState(startOfStack); attachedThreads().add(mainThreadState()); }