Fri, 14 Nov 2008 14:23:05 -0800
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
1.1 --- a/src/share/vm/gc_implementation/g1/ptrQueue.cpp Fri Nov 07 12:52:16 2008 -0800 1.2 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.cpp Fri Nov 14 14:23:05 2008 -0800 1.3 @@ -30,7 +30,7 @@ 1.4 _perm(perm), _lock(NULL) 1.5 {} 1.6 1.7 -PtrQueue::~PtrQueue() { 1.8 +void PtrQueue::flush() { 1.9 if (!_perm && _buf != NULL) { 1.10 if (_index == _sz) { 1.11 // No work to do. 1.12 @@ -41,8 +41,9 @@ 1.13 _buf[byte_index_to_index((int)i)] = NULL; 1.14 } 1.15 qset()->enqueue_complete_buffer(_buf); 1.16 - _buf = NULL; 1.17 } 1.18 + _buf = NULL; 1.19 + _index = 0; 1.20 } 1.21 } 1.22
2.1 --- a/src/share/vm/gc_implementation/g1/ptrQueue.hpp Fri Nov 07 12:52:16 2008 -0800 2.2 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.hpp Fri Nov 14 14:23:05 2008 -0800 2.3 @@ -62,7 +62,9 @@ 2.4 // given PtrQueueSet. 2.5 PtrQueue(PtrQueueSet*, bool perm = false); 2.6 // Release any contained resources. 2.7 - ~PtrQueue(); 2.8 + void flush(); 2.9 + // Calls flush() when destroyed. 2.10 + ~PtrQueue() { flush(); } 2.11 2.12 // Associate a lock with a ptr queue. 2.13 void set_lock(Mutex* lock) { _lock = lock; }
3.1 --- a/src/share/vm/runtime/thread.cpp Fri Nov 07 12:52:16 2008 -0800 3.2 +++ b/src/share/vm/runtime/thread.cpp Fri Nov 14 14:23:05 2008 -0800 3.3 @@ -1422,6 +1422,7 @@ 3.4 thread->clear_pending_exception(); 3.5 } 3.6 3.7 + 3.8 // For any new cleanup additions, please check to see if they need to be applied to 3.9 // cleanup_failed_attach_current_thread as well. 3.10 void JavaThread::exit(bool destroy_vm, ExitType exit_type) { 3.11 @@ -1592,39 +1593,62 @@ 3.12 JvmtiExport::cleanup_thread(this); 3.13 } 3.14 3.15 +#ifndef SERIALGC 3.16 + // We must flush G1-related buffers before removing a thread from 3.17 + // the list of active threads. 3.18 + if (UseG1GC) { 3.19 + flush_barrier_queues(); 3.20 + } 3.21 +#endif 3.22 + 3.23 // Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread 3.24 Threads::remove(this); 3.25 } 3.26 3.27 +#ifndef SERIALGC 3.28 +// Flush G1-related queues. 3.29 +void JavaThread::flush_barrier_queues() { 3.30 + satb_mark_queue().flush(); 3.31 + dirty_card_queue().flush(); 3.32 +} 3.33 +#endif 3.34 + 3.35 void JavaThread::cleanup_failed_attach_current_thread() { 3.36 - 3.37 - if (get_thread_profiler() != NULL) { 3.38 - get_thread_profiler()->disengage(); 3.39 - ResourceMark rm; 3.40 - get_thread_profiler()->print(get_thread_name()); 3.41 - } 3.42 - 3.43 - if (active_handles() != NULL) { 3.44 - JNIHandleBlock* block = active_handles(); 3.45 - set_active_handles(NULL); 3.46 - JNIHandleBlock::release_block(block); 3.47 - } 3.48 - 3.49 - if (free_handle_block() != NULL) { 3.50 - JNIHandleBlock* block = free_handle_block(); 3.51 - set_free_handle_block(NULL); 3.52 - JNIHandleBlock::release_block(block); 3.53 - } 3.54 - 3.55 - if (UseTLAB) { 3.56 - tlab().make_parsable(true); // retire TLAB, if any 3.57 - } 3.58 - 3.59 - Threads::remove(this); 3.60 - delete this; 3.61 + if (get_thread_profiler() != NULL) { 3.62 + get_thread_profiler()->disengage(); 3.63 + ResourceMark rm; 3.64 + get_thread_profiler()->print(get_thread_name()); 3.65 + } 3.66 + 3.67 + if (active_handles() != NULL) { 3.68 + JNIHandleBlock* block = active_handles(); 3.69 + set_active_handles(NULL); 3.70 + JNIHandleBlock::release_block(block); 3.71 + } 3.72 + 3.73 + if (free_handle_block() != NULL) { 3.74 + JNIHandleBlock* block = free_handle_block(); 3.75 + set_free_handle_block(NULL); 3.76 + JNIHandleBlock::release_block(block); 3.77 + } 3.78 + 3.79 + if (UseTLAB) { 3.80 + tlab().make_parsable(true); // retire TLAB, if any 3.81 + } 3.82 + 3.83 +#ifndef SERIALGC 3.84 + if (UseG1GC) { 3.85 + flush_barrier_queues(); 3.86 + } 3.87 +#endif 3.88 + 3.89 + Threads::remove(this); 3.90 + delete this; 3.91 } 3.92 3.93 3.94 + 3.95 + 3.96 JavaThread* JavaThread::active() { 3.97 Thread* thread = ThreadLocalStorage::thread(); 3.98 assert(thread != NULL, "just checking");
4.1 --- a/src/share/vm/runtime/thread.hpp Fri Nov 07 12:52:16 2008 -0800 4.2 +++ b/src/share/vm/runtime/thread.hpp Fri Nov 14 14:23:05 2008 -0800 4.3 @@ -793,6 +793,8 @@ 4.4 DirtyCardQueue _dirty_card_queue; // Thread-local log for dirty cards. 4.5 // Set of all such queues. 4.6 static DirtyCardQueueSet _dirty_card_queue_set; 4.7 + 4.8 + void flush_barrier_queues(); 4.9 #endif // !SERIALGC 4.10 4.11 friend class VMThread;