diff --git a/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp b/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp index ee53c3ba6e35558d1890c6329440e111d6f0ac93..5b396f23eed4dca2f1ad2378bb591eaef4fdc647 100644 --- a/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp +++ b/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp @@ -89,6 +89,10 @@ void ConcurrentMarkThread::run() { while (!_should_terminate) { // wait until started is set. sleepBeforeNextCycle(); + if (_should_terminate) { + break; + } + { ResourceMark rm; HandleMark hm; @@ -303,11 +307,21 @@ void ConcurrentMarkThread::yield() { } void ConcurrentMarkThread::stop() { - // it is ok to take late safepoints here, if needed - MutexLockerEx mu(Terminator_lock); - _should_terminate = true; - while (!_has_terminated) { - Terminator_lock->wait(); + { + MutexLockerEx ml(Terminator_lock); + _should_terminate = true; + } + + { + MutexLockerEx ml(CGC_lock, Mutex::_no_safepoint_check_flag); + CGC_lock->notify_all(); + } + + { + MutexLockerEx ml(Terminator_lock); + while (!_has_terminated) { + Terminator_lock->wait(); + } } } @@ -327,11 +341,14 @@ void ConcurrentMarkThread::sleepBeforeNextCycle() { assert(!in_progress(), "should have been cleared"); MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); - while (!started()) { + while (!started() && !_should_terminate) { CGC_lock->wait(Mutex::_no_safepoint_check_flag); } - set_in_progress(); - clear_started(); + + if (started()) { + set_in_progress(); + clear_started(); + } } // Note: As is the case with CMS - this method, although exported diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index bd0577d70a1d646d8c272a29dd8424a5bd950d67..8209e7becabfc7f0bb4e559e1ad8953b8df3ebf4 100644 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -435,6 +435,9 @@ HeapRegion* G1CollectedHeap::pop_dirty_cards_region() void G1CollectedHeap::stop_conc_gc_threads() { _cg1r->stop(); _cmThread->stop(); + if (G1StringDedup::is_enabled()) { + G1StringDedup::stop(); + } } #ifdef ASSERT @@ -2182,6 +2185,16 @@ jint G1CollectedHeap::initialize() { return JNI_OK; } +void G1CollectedHeap::stop() { + // Abort any ongoing concurrent root region scanning and stop all + // concurrent threads. We do this to make sure these threads do + // not continue to execute and access resources (e.g. gclog_or_tty) + // that are destroyed during shutdown. + _cm->root_regions()->abort(); + _cm->root_regions()->wait_until_scan_finished(); + stop_conc_gc_threads(); +} + size_t G1CollectedHeap::conservative_max_heap_alignment() { return HeapRegion::max_region_size(); } diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 4fcb47111317b608cca3a50d18dd511c34e12f40..4304efcdd175cdd894b3add477a0f1c9e2b2ce08 100644 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -1082,6 +1082,8 @@ public: // specified by the policy object. jint initialize(); + virtual void stop(); + // Return the (conservative) maximum heap alignment for any G1 heap static size_t conservative_max_heap_alignment(); diff --git a/src/share/vm/gc_implementation/g1/g1StringDedup.cpp b/src/share/vm/gc_implementation/g1/g1StringDedup.cpp index b1f8e01524e18f77d9746893a4d0dd8c3a3816e4..d353d7ebd2d06ff76307923963d93bb691c6aeeb 100644 --- a/src/share/vm/gc_implementation/g1/g1StringDedup.cpp +++ b/src/share/vm/gc_implementation/g1/g1StringDedup.cpp @@ -44,6 +44,11 @@ void G1StringDedup::initialize() { } } +void G1StringDedup::stop() { + assert(is_enabled(), "String deduplication not enabled"); + G1StringDedupThread::stop(); +} + bool G1StringDedup::is_candidate_from_mark(oop obj) { if (java_lang_String::is_instance(obj)) { bool from_young = G1CollectedHeap::heap()->heap_region_containing_raw(obj)->is_young(); diff --git a/src/share/vm/gc_implementation/g1/g1StringDedup.hpp b/src/share/vm/gc_implementation/g1/g1StringDedup.hpp index 80af6b661d256581dfd0d05f0ea4d713953ec116..68f700f6585ed4c6ccdb43949635a8adf70dfd08 100644 --- a/src/share/vm/gc_implementation/g1/g1StringDedup.hpp +++ b/src/share/vm/gc_implementation/g1/g1StringDedup.hpp @@ -110,8 +110,12 @@ public: return _enabled; } + // Initialize string deduplication. static void initialize(); + // Stop the deduplication thread. + static void stop(); + // Immediately deduplicates the given String object, bypassing the // the deduplication queue. static void deduplicate(oop java_string); diff --git a/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp b/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp index 330b5a434c2920fa47fc480e233fd9e97c3c81f8..8ae53e353bc051d65093a55495cbe07631627bad 100644 --- a/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp +++ b/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp @@ -35,6 +35,7 @@ const size_t G1StringDedupQueue::_max_cache_size = 0; // Max cache size p G1StringDedupQueue::G1StringDedupQueue() : _cursor(0), + _cancel(false), _empty(true), _dropped(0) { _nqueues = MAX2(ParallelGCThreads, (size_t)1); @@ -55,11 +56,17 @@ void G1StringDedupQueue::create() { void G1StringDedupQueue::wait() { MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); - while (_queue->_empty) { + while (_queue->_empty && !_queue->_cancel) { ml.wait(Mutex::_no_safepoint_check_flag); } } +void G1StringDedupQueue::cancel_wait() { + MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); + _queue->_cancel = true; + ml.notify(); +} + void G1StringDedupQueue::push(uint worker_id, oop java_string) { assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint"); assert(worker_id < _queue->_nqueues, "Invalid queue"); diff --git a/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp b/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp index 1690247b769125f25dde4f50e9cc0eb5bd632fcc..99f555b7076ddc689135a7395511a72486ac3e3c 100644 --- a/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp +++ b/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp @@ -65,6 +65,7 @@ private: G1StringDedupWorkerQueue* _queues; size_t _nqueues; size_t _cursor; + bool _cancel; volatile bool _empty; // Statistics counter, only used for logging. @@ -81,6 +82,9 @@ public: // Blocks and waits for the queue to become non-empty. static void wait(); + // Wakes up any thread blocked waiting for the queue to become non-empty. + static void cancel_wait(); + // Pushes a deduplication candidate onto a specific GC worker queue. static void push(uint worker_id, oop java_string); diff --git a/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp b/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp index 7263220a3915ae35ba844daae569da39da0b0899..4a6dc279b510fbf6ebd3b2a2a132c9a1fad4c745 100644 --- a/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp +++ b/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp @@ -73,6 +73,9 @@ void G1StringDedupThread::run() { // Wait for the queue to become non-empty G1StringDedupQueue::wait(); + if (_should_terminate) { + break; + } // Include this thread in safepoints stsJoin(); @@ -108,7 +111,23 @@ void G1StringDedupThread::run() { stsLeave(); } - ShouldNotReachHere(); + terminate(); +} + +void G1StringDedupThread::stop() { + { + MonitorLockerEx ml(Terminator_lock); + _thread->_should_terminate = true; + } + + G1StringDedupQueue::cancel_wait(); + + { + MonitorLockerEx ml(Terminator_lock); + while (!_thread->_has_terminated) { + ml.wait(); + } + } } void G1StringDedupThread::print(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { diff --git a/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp b/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp index 8a93058fd1ea44a6e1947cd0330fc70763998fd2..eb60a0b76148997cc522b1a9f4d7c784dfefc9a9 100644 --- a/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp +++ b/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp @@ -47,6 +47,8 @@ private: public: static void create(); + static void stop(); + static G1StringDedupThread* thread(); virtual void run(); diff --git a/src/share/vm/gc_interface/collectedHeap.hpp b/src/share/vm/gc_interface/collectedHeap.hpp index a9d271be2c2b5abbce6a6675ca08bc26c9469f4e..4b56f00e746ed89349d711569c4d199270b965f0 100644 --- a/src/share/vm/gc_interface/collectedHeap.hpp +++ b/src/share/vm/gc_interface/collectedHeap.hpp @@ -208,6 +208,9 @@ class CollectedHeap : public CHeapObj { // This is the correct place to place such initialization methods. virtual void post_initialize() = 0; + // Stop any onging concurrent work and prepare for exit. + virtual void stop() {} + MemRegion reserved_region() const { return _reserved; } address base() const { return (address)reserved_region().start(); } diff --git a/src/share/vm/runtime/java.cpp b/src/share/vm/runtime/java.cpp index 2607688f34caf4b97be20bc046fd2f8d64af6b8d..889d02a4663c24b00df7f7b4eed1aa6c2cbe1969 100644 --- a/src/share/vm/runtime/java.cpp +++ b/src/share/vm/runtime/java.cpp @@ -497,6 +497,9 @@ void before_exit(JavaThread * thread) { os::infinite_sleep(); } + // Stop any ongoing concurrent GC work + Universe::heap()->stop(); + // Terminate watcher thread - must before disenrolling any periodic task if (PeriodicTask::num_tasks() > 0) WatcherThread::stop();