# HG changeset patch # Parent 7d2300506146683973ed45adf64cc3019ebca376 diff -r 7d2300506146 -r 75b74396b106 src/hotspot/share/gc/shared/collectedHeap.hpp --- a/src/hotspot/share/gc/shared/collectedHeap.hpp Tue Mar 19 12:55:05 2019 +0100 +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp Tue Mar 19 23:28:48 2019 +0100 @@ -502,6 +502,10 @@ // Iterator for all GC threads (other than VM thread) virtual void gc_threads_do(ThreadClosure* tc) const = 0; + // Iterator for all GC threads that need to participate + // in the thread claiming protocol. + virtual void gc_claim_threads_do(ThreadClosure* tc) const {} + // Print any relevant tracing info that flags imply. // Default implementation does nothing. virtual void print_tracing_info() const = 0; diff -r 7d2300506146 -r 75b74396b106 src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp Tue Mar 19 12:55:05 2019 +0100 +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp Tue Mar 19 23:28:48 2019 +0100 @@ -219,17 +219,13 @@ class ShenandoahSATBThreadsClosure : public ThreadClosure { private: ShenandoahSATBBufferClosure* _satb_cl; - int _thread_parity; public: ShenandoahSATBThreadsClosure(ShenandoahSATBBufferClosure* satb_cl) : - _satb_cl(satb_cl), - _thread_parity(Threads::thread_claim_parity()) {} + _satb_cl(satb_cl) {} void do_thread(Thread* thread) { - if (thread->claim_oops_do(true, _thread_parity)) { - ShenandoahThreadLocalData::satb_mark_queue(thread).apply_closure_and_empty(_satb_cl); - } + ShenandoahThreadLocalData::satb_mark_queue(thread).apply_closure_and_empty(_satb_cl); } }; @@ -259,7 +255,7 @@ SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set(); while (satb_mq_set.apply_closure_to_completed_buffer(&cl)); ShenandoahSATBThreadsClosure tc(&cl); - Threads::threads_do(&tc); + Threads::possibly_parallel_threads_do(true, &tc); } ReferenceProcessor* rp; @@ -412,6 +408,15 @@ assert(task_queues()->is_empty() || _heap->cancelled_gc(), "Should be empty when not cancelled"); } +#ifdef ASSERT +class AssertSATBEmptyThreadClosure : public ThreadClosure { +public: + void do_thread(Thread* thread) { + assert(ShenandoahThreadLocalData::satb_mark_queue(thread).is_empty(), "SATB queue must be empty"); + } +}; +#endif + void ShenandoahConcurrentMark::finish_mark_from_roots(bool full_gc) { assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint"); @@ -438,10 +443,16 @@ ShenandoahPhaseTimings::full_gc_mark_termination : ShenandoahPhaseTimings::termination); - StrongRootsScope scope(nworkers); - ShenandoahTaskTerminator terminator(nworkers, task_queues()); - ShenandoahFinalMarkingTask task(this, &terminator, ShenandoahStringDedup::is_enabled()); - _heap->workers()->run_task(&task); + { + StrongRootsScope scope(nworkers); + ShenandoahTaskTerminator terminator(nworkers, task_queues()); + ShenandoahFinalMarkingTask task(this, &terminator, ShenandoahStringDedup::is_enabled()); + _heap->workers()->run_task(&task); + } +#ifdef ASSERT + AssertSATBEmptyThreadClosure tc; + Threads::threads_do(&tc); +#endif } assert(task_queues()->is_empty(), "Should be empty"); diff -r 7d2300506146 -r 75b74396b106 src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp Tue Mar 19 12:55:05 2019 +0100 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp Tue Mar 19 23:28:48 2019 +0100 @@ -1224,6 +1224,12 @@ } } +void ShenandoahHeap::gc_claim_threads_do(ThreadClosure* tcl) const { + if (ShenandoahStringDedup::is_enabled()) { + ShenandoahStringDedup::threads_do(tcl); + } +} + void ShenandoahHeap::print_tracing_info() const { LogTarget(Info, gc, stats) lt; if (lt.is_enabled()) { diff -r 7d2300506146 -r 75b74396b106 src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp Tue Mar 19 12:55:05 2019 +0100 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp Tue Mar 19 23:28:48 2019 +0100 @@ -236,7 +236,8 @@ WorkGang* workers() const; WorkGang* get_safepoint_workers(); - void gc_threads_do(ThreadClosure* tcl) const; + virtual void gc_threads_do(ThreadClosure* tcl) const; + virtual void gc_claim_threads_do(ThreadClosure* tc) const; // ---------- Heap regions handling machinery // diff -r 7d2300506146 -r 75b74396b106 src/hotspot/share/runtime/thread.cpp --- a/src/hotspot/share/runtime/thread.cpp Tue Mar 19 12:55:05 2019 +0100 +++ b/src/hotspot/share/runtime/thread.cpp Tue Mar 19 23:28:48 2019 +0100 @@ -3529,17 +3529,29 @@ non_java_threads_do(tc); } +class ClaimAndThreadsDoClosure : public ThreadClosure { +private: + ThreadClosure* const _tc; + const bool _is_par; + const int _parity; +public: + ClaimAndThreadsDoClosure(ThreadClosure* tc, bool is_par) : + _tc(tc), _is_par(is_par), _parity(Threads::thread_claim_parity()) {} + + void do_thread(Thread* t) { + if (t->claim_oops_do(_is_par, _parity)) { + _tc->do_thread(t); + } + } +}; + void Threads::possibly_parallel_threads_do(bool is_par, ThreadClosure* tc) { - int cp = Threads::thread_claim_parity(); + ClaimAndThreadsDoClosure claim_do_cl(tc, is_par); ALL_JAVA_THREADS(p) { - if (p->claim_oops_do(is_par, cp)) { - tc->do_thread(p); - } - } - VMThread* vmt = VMThread::vm_thread(); - if (vmt->claim_oops_do(is_par, cp)) { - tc->do_thread(vmt); - } + claim_do_cl.do_thread(p); + } + claim_do_cl.do_thread(VMThread::vm_thread()); + Universe::heap()->gc_claim_threads_do(&claim_do_cl); } // The system initialization in the library has three phases. @@ -4534,16 +4546,26 @@ } #ifdef ASSERT +class CheckClaimedThreadClosure : public ThreadClosure { +private: + const int _parity; +public: + CheckClaimedThreadClosure() : _parity(Threads::thread_claim_parity()) {} + + void do_thread(Thread* t) { + const int thread_parity = t->oops_do_parity(); + assert((thread_parity == _parity), + "Thread " PTR_FORMAT " has incorrect parity %d != %d", p2i(t), thread_parity, _parity); + } +}; + void Threads::assert_all_threads_claimed() { + CheckClaimedThreadClosure check_claimed_cl; ALL_JAVA_THREADS(p) { - const int thread_parity = p->oops_do_parity(); - assert((thread_parity == _thread_claim_parity), - "Thread " PTR_FORMAT " has incorrect parity %d != %d", p2i(p), thread_parity, _thread_claim_parity); - } - VMThread* vmt = VMThread::vm_thread(); - const int thread_parity = vmt->oops_do_parity(); - assert((thread_parity == _thread_claim_parity), - "VMThread " PTR_FORMAT " has incorrect parity %d != %d", p2i(vmt), thread_parity, _thread_claim_parity); + check_claimed_cl.do_thread(p); + } + check_claimed_cl.do_thread(VMThread::vm_thread()); + Universe::heap()->gc_claim_threads_do(&check_claimed_cl); } #endif // ASSERT