# HG changeset patch # User iveresov # Date 1226701385 28800 # Node ID 1b328492b7f813580bcc261493aa1f7392cc2b96 # Parent 20339a90049b6cd124448c4f56a564d5596bef3e 6770608: G1: Mutator thread can flush barrier and satb queues during safepoint 6660573: G1: BigApps Failure : guarantee(satb_mq_set.completed_buffers_num() == 0,"invariant") Summary: When exiting a mutator thread is removed from the thread list before it has a chance to flush its SATB and barrier queues. If GC happens at this moment the objects that are refererred from these queues can be moved, which will case a crash. The fix is simply to flush the buffers before removing a thread from the list. Reviewed-by: jcoomes, tonyp diff -r 20339a90049b -r 1b328492b7f8 hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp Fri Nov 07 12:52:16 2008 -0800 +++ b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp Fri Nov 14 14:23:05 2008 -0800 @@ -30,7 +30,7 @@ _perm(perm), _lock(NULL) {} -PtrQueue::~PtrQueue() { +void PtrQueue::flush() { if (!_perm && _buf != NULL) { if (_index == _sz) { // No work to do. @@ -41,8 +41,9 @@ _buf[byte_index_to_index((int)i)] = NULL; } qset()->enqueue_complete_buffer(_buf); - _buf = NULL; } + _buf = NULL; + _index = 0; } } diff -r 20339a90049b -r 1b328492b7f8 hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp Fri Nov 07 12:52:16 2008 -0800 +++ b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp Fri Nov 14 14:23:05 2008 -0800 @@ -62,7 +62,9 @@ // given PtrQueueSet. PtrQueue(PtrQueueSet*, bool perm = false); // Release any contained resources. - ~PtrQueue(); + void flush(); + // Calls flush() when destroyed. + ~PtrQueue() { flush(); } // Associate a lock with a ptr queue. void set_lock(Mutex* lock) { _lock = lock; } diff -r 20339a90049b -r 1b328492b7f8 hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Fri Nov 07 12:52:16 2008 -0800 +++ b/hotspot/src/share/vm/runtime/thread.cpp Fri Nov 14 14:23:05 2008 -0800 @@ -1422,6 +1422,7 @@ thread->clear_pending_exception(); } + // For any new cleanup additions, please check to see if they need to be applied to // cleanup_failed_attach_current_thread as well. void JavaThread::exit(bool destroy_vm, ExitType exit_type) { @@ -1592,39 +1593,62 @@ JvmtiExport::cleanup_thread(this); } +#ifndef SERIALGC + // We must flush G1-related buffers before removing a thread from + // the list of active threads. + if (UseG1GC) { + flush_barrier_queues(); + } +#endif + // Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread Threads::remove(this); } +#ifndef SERIALGC +// Flush G1-related queues. +void JavaThread::flush_barrier_queues() { + satb_mark_queue().flush(); + dirty_card_queue().flush(); +} +#endif + void JavaThread::cleanup_failed_attach_current_thread() { - - if (get_thread_profiler() != NULL) { - get_thread_profiler()->disengage(); - ResourceMark rm; - get_thread_profiler()->print(get_thread_name()); - } - - if (active_handles() != NULL) { - JNIHandleBlock* block = active_handles(); - set_active_handles(NULL); - JNIHandleBlock::release_block(block); - } - - if (free_handle_block() != NULL) { - JNIHandleBlock* block = free_handle_block(); - set_free_handle_block(NULL); - JNIHandleBlock::release_block(block); - } - - if (UseTLAB) { - tlab().make_parsable(true); // retire TLAB, if any - } - - Threads::remove(this); - delete this; + if (get_thread_profiler() != NULL) { + get_thread_profiler()->disengage(); + ResourceMark rm; + get_thread_profiler()->print(get_thread_name()); + } + + if (active_handles() != NULL) { + JNIHandleBlock* block = active_handles(); + set_active_handles(NULL); + JNIHandleBlock::release_block(block); + } + + if (free_handle_block() != NULL) { + JNIHandleBlock* block = free_handle_block(); + set_free_handle_block(NULL); + JNIHandleBlock::release_block(block); + } + + if (UseTLAB) { + tlab().make_parsable(true); // retire TLAB, if any + } + +#ifndef SERIALGC + if (UseG1GC) { + flush_barrier_queues(); + } +#endif + + Threads::remove(this); + delete this; } + + JavaThread* JavaThread::active() { Thread* thread = ThreadLocalStorage::thread(); assert(thread != NULL, "just checking"); diff -r 20339a90049b -r 1b328492b7f8 hotspot/src/share/vm/runtime/thread.hpp --- a/hotspot/src/share/vm/runtime/thread.hpp Fri Nov 07 12:52:16 2008 -0800 +++ b/hotspot/src/share/vm/runtime/thread.hpp Fri Nov 14 14:23:05 2008 -0800 @@ -793,6 +793,8 @@ DirtyCardQueue _dirty_card_queue; // Thread-local log for dirty cards. // Set of all such queues. static DirtyCardQueueSet _dirty_card_queue_set; + + void flush_barrier_queues(); #endif // !SERIALGC friend class VMThread;