changeset 446:da9cb4e97a5f

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
author iveresov
date Fri, 14 Nov 2008 14:23:05 -0800
parents 96c6da8f095c
children 8fa025608ec6
files src/share/vm/gc_implementation/g1/ptrQueue.cpp src/share/vm/gc_implementation/g1/ptrQueue.hpp src/share/vm/runtime/thread.cpp src/share/vm/runtime/thread.hpp
diffstat 4 files changed, 57 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/gc_implementation/g1/ptrQueue.cpp	Fri Nov 07 12:52:16 2008 -0800
+++ b/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;
   }
 }
 
--- a/src/share/vm/gc_implementation/g1/ptrQueue.hpp	Fri Nov 07 12:52:16 2008 -0800
+++ b/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; }
--- a/src/share/vm/runtime/thread.cpp	Fri Nov 07 12:52:16 2008 -0800
+++ b/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");
--- a/src/share/vm/runtime/thread.hpp	Fri Nov 07 12:52:16 2008 -0800
+++ b/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;