Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1579)

Unified Diff: Source/platform/heap/ThreadState.cpp

Issue 371623002: [oilpan]: Make thread shutdown more robust. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: review feedback Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/platform/heap/ThreadState.cpp
diff --git a/Source/platform/heap/ThreadState.cpp b/Source/platform/heap/ThreadState.cpp
index b15a2362232652299e2b378a40b89fa7bff432c5..352344bf308792847501064de36b79ee72449cce 100644
--- a/Source/platform/heap/ThreadState.cpp
+++ b/Source/platform/heap/ThreadState.cpp
@@ -102,6 +102,19 @@ static Mutex& threadAttachMutex()
return mutex;
}
+// The threadShutdownMutex is used to synchronize thread shutdown
+// since the thread local GC, as of now, cannot run in parallel
+// with other thread local GCs since it is using the global marking
+// stack. It can also not run in parallel with a global GC, but
+// that is honored by not entering a safepoint while doing the
+// thread local GC, meaning a request for a global GC would time
+// out.
haraken 2014/07/07 16:13:47 I'm not sure if this assumption is correct. Heap::
wibling-chromium 2014/07/08 13:39:47 It should not be the case that we enter a safepoin
+static Mutex& threadShutdownMutex()
+{
+ AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
+ return mutex;
+}
+
static double lockingTimeout()
{
// Wait time for parking all threads is at most 100 MS.
@@ -260,6 +273,16 @@ private:
ThreadCondition m_resume;
};
+
+BaseHeapPage::BaseHeapPage(PageMemory* storage, const GCInfo* gcInfo, ThreadState* state)
+ : m_storage(storage)
+ , m_gcInfo(gcInfo)
+ , m_threadState(state)
+ , m_padding(0)
+{
+ ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this)));
+}
+
ThreadState::ThreadState()
: m_thread(currentThread())
, m_persistents(adoptPtr(new PersistentAnchor()))
@@ -287,9 +310,9 @@ ThreadState::ThreadState()
m_statsAfterLastGC.clear();
// First allocate the general heap, second iterate through to
// allocate the type specific heaps
- m_heaps[GeneralHeap] = new ThreadHeap<FinalizedHeapObjectHeader>(this);
+ m_heaps[GeneralHeap] = new ThreadHeap<FinalizedHeapObjectHeader>(this, GeneralHeap);
for (int i = GeneralHeap + 1; i < NumberOfHeaps; i++)
- m_heaps[i] = new ThreadHeap<HeapObjectHeader>(this);
+ m_heaps[i] = new ThreadHeap<HeapObjectHeader>(this, i);
CallbackStack::init(&m_weakCallbackStack);
}
@@ -375,14 +398,29 @@ void ThreadState::cleanup()
for (size_t i = 0; i < m_cleanupTasks.size(); i++)
m_cleanupTasks[i]->preCleanup();
- // After this GC we expect heap to be empty because
- // preCleanup tasks should have cleared all persistent
- // handles that were externally owned.
- Heap::collectAllGarbage();
+ {
+ // We enter a safepoint while waiting for the thread shutdown mutex.
+ SafePointAwareMutexLocker locker(threadShutdownMutex());
+
+ // Set a flag on all this thread's heap pages to ensure we don't trace
haraken 2014/07/07 16:13:47 Set flags on all heap pages of this thread to ensu
wibling-chromium 2014/07/08 13:39:47 Done.
+ // outside this thread's heap pages.
+ setupHeapsForShutdown();
+
+ // 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 = 0;
+ int curCount = anchor->numberOfPersistents();
haraken 2014/07/07 16:13:46 curCount => currentCount
wibling-chromium 2014/07/08 13:39:47 Done.
+ while (curCount > 0 && curCount != oldCount) {
haraken 2014/07/07 16:13:47 I'm not sure if 'curCount == oldCount' is enough t
wibling-chromium 2014/07/08 13:39:48 I have added an ASSERT to PersistentBase to check
+ Heap::collectGarbageForThread(this, false);
+ oldCount = curCount;
+ curCount = anchor->numberOfPersistents();
+ }
- // Verify that all heaps are empty now.
- for (int i = 0; i < NumberOfHeaps; i++)
- m_heaps[i]->assertEmpty();
+ // Do a final sweep to finalize any objects pointed to by persistents
+ // collected in the last round of GC above.
+ Heap::collectGarbageForThread(this, true);
Mads Ager (chromium) 2014/07/08 08:24:56 Add enum instead of bool?
wibling-chromium 2014/07/08 13:39:47 Done.
+ }
for (size_t i = 0; i < m_cleanupTasks.size(); i++)
m_cleanupTasks[i]->postCleanup();
@@ -407,6 +445,10 @@ void ThreadState::detach()
state->leaveSafePoint();
ASSERT(attachedThreads().contains(state));
attachedThreads().remove(state);
+ // Deleting the thread state also destroys the thread's heaps at which
+ // point all the thread's pages are added to the orphanedPagePool.
+ // Subsequently they are moved to the memoryPool once they are no
+ // longer traced by a global GC.
delete state;
}
shutdownHeapIfNecessary();
@@ -427,6 +469,14 @@ void ThreadState::visitRoots(Visitor* visitor)
(*it)->trace(visitor);
}
+void ThreadState::visitLocalRoots(Visitor* visitor)
+{
+ // We assume there are no CrossThreadPersistents to this threads heap. If
+ // there is, it will be handled in the same way as any other cross-thread
+ // pointer pointing to an orphaned page.
+ m_persistents->trace(visitor);
+}
+
NO_SANITIZE_ADDRESS
void ThreadState::visitAsanFakeStackForPointer(Visitor* visitor, Address ptr)
{
@@ -549,7 +599,7 @@ void ThreadState::pushWeakObjectPointerCallback(void* object, WeakPointerCallbac
bool ThreadState::popAndInvokeWeakPointerCallback(Visitor* visitor)
{
- return m_weakCallbackStack->popAndInvokeCallback(&m_weakCallbackStack, visitor);
+ return m_weakCallbackStack->popAndInvokeCallback<false>(&m_weakCallbackStack, visitor);
}
PersistentNode* ThreadState::globalRoots()
@@ -687,15 +737,27 @@ void ThreadState::prepareForGC()
for (int i = 0; i < NumberOfHeaps; i++) {
BaseHeap* heap = m_heaps[i];
heap->makeConsistentForGC();
- // If there are parked threads with outstanding sweep requests, clear their mark bits.
- // This happens if a thread did not have time to wake up and sweep,
- // before the next GC arrived.
+ // If there are parked threads with outstanding sweep requests, clear their mark bits,
haraken 2014/07/07 16:13:47 If a next GC is requested before processing a swee
wibling-chromium 2014/07/08 13:39:47 Rephrased it a bit.
+ // and mark any of their dead objects as dead. The latter is used to ensure the next
+ // GC marking does not revive already dead objects. If we revived a dead object we
Mads Ager (chromium) 2014/07/08 08:24:56 revive -> trace revived -> traced
wibling-chromium 2014/07/08 13:39:48 Done.
+ // could end up tracing into garbage or the middle of another object via the revived
+ // object.
haraken 2014/07/07 16:13:46 Just help me understand: Is this "revive" problem
wibling-chromium 2014/07/08 13:39:47 This is an issue we discovered while I was doing t
+ // The case of a thread missing a sweep happens if it did not have time to wake up
+ // and sweep, before the next GC arrived.
if (sweepRequested())
- heap->clearMarks();
+ heap->clearLiveAndMarkDead();
}
setSweepRequested();
}
+void ThreadState::setupHeapsForShutdown()
+{
+ for (int i = 0; i < NumberOfHeaps; i++) {
+ BaseHeap* heap = m_heaps[i];
+ heap->setShutdown();
haraken 2014/07/07 16:13:46 setShutdown => setHeapForShutdown
wibling-chromium 2014/07/08 13:39:47 Changed it to prepareHeapForShutdown.
+ }
+}
+
BaseHeapPage* ThreadState::heapPageFromAddress(Address address)
{
BaseHeapPage* cachedPage = heapContainsCache()->lookup(address);

Powered by Google App Engine
This is Rietveld 408576698