提交 5ee7f6f4 编写于 作者: I iveresov

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
上级 221e50e3
...@@ -30,7 +30,7 @@ PtrQueue::PtrQueue(PtrQueueSet* qset_, bool perm) : ...@@ -30,7 +30,7 @@ PtrQueue::PtrQueue(PtrQueueSet* qset_, bool perm) :
_perm(perm), _lock(NULL) _perm(perm), _lock(NULL)
{} {}
PtrQueue::~PtrQueue() { void PtrQueue::flush() {
if (!_perm && _buf != NULL) { if (!_perm && _buf != NULL) {
if (_index == _sz) { if (_index == _sz) {
// No work to do. // No work to do.
...@@ -41,8 +41,9 @@ PtrQueue::~PtrQueue() { ...@@ -41,8 +41,9 @@ PtrQueue::~PtrQueue() {
_buf[byte_index_to_index((int)i)] = NULL; _buf[byte_index_to_index((int)i)] = NULL;
} }
qset()->enqueue_complete_buffer(_buf); qset()->enqueue_complete_buffer(_buf);
_buf = NULL;
} }
_buf = NULL;
_index = 0;
} }
} }
......
...@@ -62,7 +62,9 @@ public: ...@@ -62,7 +62,9 @@ public:
// given PtrQueueSet. // given PtrQueueSet.
PtrQueue(PtrQueueSet*, bool perm = false); PtrQueue(PtrQueueSet*, bool perm = false);
// Release any contained resources. // Release any contained resources.
~PtrQueue(); void flush();
// Calls flush() when destroyed.
~PtrQueue() { flush(); }
// Associate a lock with a ptr queue. // Associate a lock with a ptr queue.
void set_lock(Mutex* lock) { _lock = lock; } void set_lock(Mutex* lock) { _lock = lock; }
......
...@@ -1422,6 +1422,7 @@ static void ensure_join(JavaThread* thread) { ...@@ -1422,6 +1422,7 @@ static void ensure_join(JavaThread* thread) {
thread->clear_pending_exception(); thread->clear_pending_exception();
} }
// For any new cleanup additions, please check to see if they need to be applied to // For any new cleanup additions, please check to see if they need to be applied to
// cleanup_failed_attach_current_thread as well. // cleanup_failed_attach_current_thread as well.
void JavaThread::exit(bool destroy_vm, ExitType exit_type) { void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
...@@ -1592,39 +1593,62 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { ...@@ -1592,39 +1593,62 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
JvmtiExport::cleanup_thread(this); 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 // Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread
Threads::remove(this); 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() { 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 (get_thread_profiler() != NULL) { if (active_handles() != NULL) {
get_thread_profiler()->disengage(); JNIHandleBlock* block = active_handles();
ResourceMark rm; set_active_handles(NULL);
get_thread_profiler()->print(get_thread_name()); JNIHandleBlock::release_block(block);
} }
if (active_handles() != NULL) { if (free_handle_block() != NULL) {
JNIHandleBlock* block = active_handles(); JNIHandleBlock* block = free_handle_block();
set_active_handles(NULL); set_free_handle_block(NULL);
JNIHandleBlock::release_block(block); JNIHandleBlock::release_block(block);
} }
if (free_handle_block() != NULL) { if (UseTLAB) {
JNIHandleBlock* block = free_handle_block(); tlab().make_parsable(true); // retire TLAB, if any
set_free_handle_block(NULL); }
JNIHandleBlock::release_block(block);
}
if (UseTLAB) { #ifndef SERIALGC
tlab().make_parsable(true); // retire TLAB, if any if (UseG1GC) {
} flush_barrier_queues();
}
#endif
Threads::remove(this); Threads::remove(this);
delete this; delete this;
} }
JavaThread* JavaThread::active() { JavaThread* JavaThread::active() {
Thread* thread = ThreadLocalStorage::thread(); Thread* thread = ThreadLocalStorage::thread();
assert(thread != NULL, "just checking"); assert(thread != NULL, "just checking");
......
...@@ -793,6 +793,8 @@ class JavaThread: public Thread { ...@@ -793,6 +793,8 @@ class JavaThread: public Thread {
DirtyCardQueue _dirty_card_queue; // Thread-local log for dirty cards. DirtyCardQueue _dirty_card_queue; // Thread-local log for dirty cards.
// Set of all such queues. // Set of all such queues.
static DirtyCardQueueSet _dirty_card_queue_set; static DirtyCardQueueSet _dirty_card_queue_set;
void flush_barrier_queues();
#endif // !SERIALGC #endif // !SERIALGC
friend class VMThread; friend class VMThread;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册