8039147: Cleanup SuspendibleThreadSet
authorpliden
Fri, 11 Apr 2014 12:29:24 +0200
changeset 24094 5dbf1f44de18
parent 24093 095cc0a63ed9
child 24095 5a5cf6765809
8039147: Cleanup SuspendibleThreadSet Reviewed-by: brutisso, tschatzl, mgerdin
hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp
hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp
hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp
hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp
hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp
hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.hpp
hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp
hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp
hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp
hotspot/src/share/vm/gc_implementation/shared/suspendibleThreadSet.cpp
hotspot/src/share/vm/gc_implementation/shared/suspendibleThreadSet.hpp
hotspot/src/share/vm/runtime/mutexLocker.cpp
hotspot/src/share/vm/runtime/mutexLocker.hpp
hotspot/src/share/vm/runtime/safepoint.cpp
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp	Fri Apr 11 11:00:12 2014 +0200
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp	Fri Apr 11 12:29:24 2014 +0200
@@ -71,6 +71,7 @@
 }
 
 void ConcurrentG1RefineThread::sample_young_list_rs_lengths() {
+  SuspendibleThreadSetJoiner sts;
   G1CollectedHeap* g1h = G1CollectedHeap::heap();
   G1CollectorPolicy* g1p = g1h->g1_policy();
   if (g1p->adaptive_young_list_length()) {
@@ -82,8 +83,8 @@
 
       // we try to yield every time we visit 10 regions
       if (regions_visited == 10) {
-        if (_sts.should_yield()) {
-          _sts.yield("G1 refine");
+        if (sts.should_yield()) {
+          sts.yield();
           // we just abandon the iteration
           break;
         }
@@ -99,9 +100,7 @@
   DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   _vtime_start = os::elapsedVTime();
   while(!_should_terminate) {
-    _sts.join();
     sample_young_list_rs_lengths();
-    _sts.leave();
 
     if (os::supports_vtime()) {
       _vtime_accum = (os::elapsedVTime() - _vtime_start);
@@ -182,37 +181,37 @@
       break;
     }
 
-    _sts.join();
+    {
+      SuspendibleThreadSetJoiner sts;
+
+      do {
+        int curr_buffer_num = (int)dcqs.completed_buffers_num();
+        // If the number of the buffers falls down into the yellow zone,
+        // that means that the transition period after the evacuation pause has ended.
+        if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) {
+          dcqs.set_completed_queue_padding(0);
+        }
 
-    do {
-      int curr_buffer_num = (int)dcqs.completed_buffers_num();
-      // If the number of the buffers falls down into the yellow zone,
-      // that means that the transition period after the evacuation pause has ended.
-      if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) {
-        dcqs.set_completed_queue_padding(0);
-      }
+        if (_worker_id > 0 && curr_buffer_num <= _deactivation_threshold) {
+          // If the number of the buffer has fallen below our threshold
+          // we should deactivate. The predecessor will reactivate this
+          // thread should the number of the buffers cross the threshold again.
+          deactivate();
+          break;
+        }
 
-      if (_worker_id > 0 && curr_buffer_num <= _deactivation_threshold) {
-        // If the number of the buffer has fallen below our threshold
-        // we should deactivate. The predecessor will reactivate this
-        // thread should the number of the buffers cross the threshold again.
+        // Check if we need to activate the next thread.
+        if (_next != NULL && !_next->is_active() && curr_buffer_num > _next->_threshold) {
+          _next->activate();
+        }
+      } while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, cg1r()->green_zone()));
+
+      // We can exit the loop above while being active if there was a yield request.
+      if (is_active()) {
         deactivate();
-        break;
       }
-
-      // Check if we need to activate the next thread.
-      if (_next != NULL && !_next->is_active() && curr_buffer_num > _next->_threshold) {
-        _next->activate();
-      }
-    } while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, cg1r()->green_zone()));
-
-    // We can exit the loop above while being active if there was a yield request.
-    if (is_active()) {
-      deactivate();
     }
 
-    _sts.leave();
-
     if (os::supports_vtime()) {
       _vtime_accum = (os::elapsedVTime() - _vtime_start);
     } else {
@@ -223,17 +222,6 @@
   terminate();
 }
 
-
-void ConcurrentG1RefineThread::yield() {
-  if (G1TraceConcRefinement) {
-    gclog_or_tty->print_cr("G1-Refine-yield");
-  }
-  _sts.yield("G1 refine");
-  if (G1TraceConcRefinement) {
-    gclog_or_tty->print_cr("G1-Refine-yield-end");
-  }
-}
-
 void ConcurrentG1RefineThread::stop() {
   // it is ok to take late safepoints here, if needed
   {
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp	Fri Apr 11 11:00:12 2014 +0200
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp	Fri Apr 11 12:29:24 2014 +0200
@@ -64,9 +64,6 @@
   void activate();
   void deactivate();
 
-  // For use by G1CollectedHeap, which is a friend.
-  static SuspendibleThreadSet* sts() { return &_sts; }
-
 public:
   virtual void run();
   // Constructor
@@ -84,8 +81,6 @@
 
   ConcurrentG1Refine* cg1r() { return _cg1r;     }
 
-  // Yield for GC
-  void yield();
   // shutdown
   void stop();
 };
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Fri Apr 11 11:00:12 2014 +0200
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Fri Apr 11 12:29:24 2014 +0200
@@ -976,11 +976,11 @@
   }
 
   if (concurrent()) {
-    ConcurrentGCThread::stsLeave();
+    SuspendibleThreadSet::leave();
   }
   _first_overflow_barrier_sync.enter();
   if (concurrent()) {
-    ConcurrentGCThread::stsJoin();
+    SuspendibleThreadSet::join();
   }
   // at this point everyone should have synced up and not be doing any
   // more work
@@ -1024,11 +1024,11 @@
   }
 
   if (concurrent()) {
-    ConcurrentGCThread::stsLeave();
+    SuspendibleThreadSet::leave();
   }
   _second_overflow_barrier_sync.enter();
   if (concurrent()) {
-    ConcurrentGCThread::stsJoin();
+    SuspendibleThreadSet::join();
   }
   // at this point everything should be re-initialized and ready to go
 
@@ -1076,7 +1076,7 @@
 
     double start_vtime = os::elapsedVTime();
 
-    ConcurrentGCThread::stsJoin();
+    SuspendibleThreadSet::join();
 
     assert(worker_id < _cm->active_tasks(), "invariant");
     CMTask* the_task = _cm->task(worker_id);
@@ -1103,9 +1103,9 @@
         if (!_cm->has_aborted() && the_task->has_aborted()) {
           sleep_time_ms =
             (jlong) (elapsed_vtime_sec * _cm->sleep_factor() * 1000.0);
-          ConcurrentGCThread::stsLeave();
+          SuspendibleThreadSet::leave();
           os::sleep(Thread::current(), sleep_time_ms, false);
-          ConcurrentGCThread::stsJoin();
+          SuspendibleThreadSet::join();
         }
         double end_time2_sec = os::elapsedTime();
         double elapsed_time2_sec = end_time2_sec - start_time_sec;
@@ -1123,7 +1123,7 @@
     the_task->record_end_time();
     guarantee(!the_task->has_aborted() || _cm->has_aborted(), "invariant");
 
-    ConcurrentGCThread::stsLeave();
+    SuspendibleThreadSet::leave();
 
     double end_vtime = os::elapsedVTime();
     _cm->update_accum_task_vtime(worker_id, end_vtime - start_vtime);
@@ -3302,21 +3302,17 @@
 
 // We take a break if someone is trying to stop the world.
 bool ConcurrentMark::do_yield_check(uint worker_id) {
-  if (should_yield()) {
+  if (SuspendibleThreadSet::should_yield()) {
     if (worker_id == 0) {
       _g1h->g1_policy()->record_concurrent_pause();
     }
-    cmThread()->yield();
+    SuspendibleThreadSet::yield();
     return true;
   } else {
     return false;
   }
 }
 
-bool ConcurrentMark::should_yield() {
-  return cmThread()->should_yield();
-}
-
 bool ConcurrentMark::containing_card_is_marked(void* p) {
   size_t offset = pointer_delta(p, _g1h->reserved_region().start(), 1);
   return _card_bm.at(offset >> CardTableModRefBS::card_shift);
@@ -3605,7 +3601,7 @@
 #endif // _MARKING_STATS_
 
   // (4) We check whether we should yield. If we have to, then we abort.
-  if (_cm->should_yield()) {
+  if (SuspendibleThreadSet::should_yield()) {
     // We should yield. To do this we abort the task. The caller is
     // responsible for yielding.
     set_has_aborted();
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp	Fri Apr 11 11:00:12 2014 +0200
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp	Fri Apr 11 12:29:24 2014 +0200
@@ -814,7 +814,6 @@
   }
 
   inline bool do_yield_check(uint worker_i = 0);
-  inline bool should_yield();
 
   // Called to abort the marking cycle after a Full GC takes place.
   void abort();
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp	Fri Apr 11 11:00:12 2014 +0200
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp	Fri Apr 11 12:29:24 2014 +0200
@@ -194,9 +194,8 @@
       } else {
         // We don't want to update the marking status if a GC pause
         // is already underway.
-        _sts.join();
+        SuspendibleThreadSetJoiner sts;
         g1h->set_marking_complete();
-        _sts.leave();
       }
 
       // Check if cleanup set the free_regions_coming flag. If it
@@ -266,11 +265,12 @@
       // record_concurrent_mark_cleanup_completed() (and, in fact, it's
       // not needed any more as the concurrent mark state has been
       // already reset).
-      _sts.join();
-      if (!cm()->has_aborted()) {
-        g1_policy->record_concurrent_mark_cleanup_completed();
+      {
+        SuspendibleThreadSetJoiner sts;
+        if (!cm()->has_aborted()) {
+          g1_policy->record_concurrent_mark_cleanup_completed();
+        }
       }
-      _sts.leave();
 
       if (cm()->has_aborted()) {
         if (G1Log::fine()) {
@@ -282,30 +282,27 @@
 
       // We now want to allow clearing of the marking bitmap to be
       // suspended by a collection pause.
-      _sts.join();
-      _cm->clearNextBitmap();
-      _sts.leave();
+      {
+        SuspendibleThreadSetJoiner sts;
+        _cm->clearNextBitmap();
+      }
     }
 
     // Update the number of full collections that have been
     // completed. This will also notify the FullGCCount_lock in case a
     // Java thread is waiting for a full GC to happen (e.g., it
     // called System.gc() with +ExplicitGCInvokesConcurrent).
-    _sts.join();
-    g1h->increment_old_marking_cycles_completed(true /* concurrent */);
-    g1h->register_concurrent_cycle_end();
-    _sts.leave();
+    {
+      SuspendibleThreadSetJoiner sts;
+      g1h->increment_old_marking_cycles_completed(true /* concurrent */);
+      g1h->register_concurrent_cycle_end();
+    }
   }
   assert(_should_terminate, "just checking");
 
   terminate();
 }
 
-
-void ConcurrentMarkThread::yield() {
-  _sts.yield("Concurrent Mark");
-}
-
 void ConcurrentMarkThread::stop() {
   {
     MutexLockerEx ml(Terminator_lock);
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.hpp	Fri Apr 11 11:00:12 2014 +0200
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.hpp	Fri Apr 11 12:29:24 2014 +0200
@@ -89,9 +89,6 @@
   // that started() is set and set in_progress().
   bool during_cycle()      { return started() || in_progress(); }
 
-  // Yield for GC
-  void            yield();
-
   // shutdown
   void stop();
 };
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Fri Apr 11 11:00:12 2014 +0200
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Fri Apr 11 12:29:24 2014 +0200
@@ -92,15 +92,13 @@
 // Local to this file.
 
 class RefineCardTableEntryClosure: public CardTableEntryClosure {
-  SuspendibleThreadSet* _sts;
   G1RemSet* _g1rs;
   ConcurrentG1Refine* _cg1r;
   bool _concurrent;
 public:
-  RefineCardTableEntryClosure(SuspendibleThreadSet* sts,
-                              G1RemSet* g1rs,
+  RefineCardTableEntryClosure(G1RemSet* g1rs,
                               ConcurrentG1Refine* cg1r) :
-    _sts(sts), _g1rs(g1rs), _cg1r(cg1r), _concurrent(true)
+    _g1rs(g1rs), _cg1r(cg1r), _concurrent(true)
   {}
   bool do_card_ptr(jbyte* card_ptr, uint worker_i) {
     bool oops_into_cset = _g1rs->refine_card(card_ptr, worker_i, false);
@@ -109,7 +107,7 @@
     // that point into the collection set.
     assert(!oops_into_cset, "should be");
 
-    if (_concurrent && _sts->should_yield()) {
+    if (_concurrent && SuspendibleThreadSet::should_yield()) {
       // Caller will actually yield.
       return false;
     }
@@ -2117,8 +2115,7 @@
   g1_policy()->init();
 
   _refine_cte_cl =
-    new RefineCardTableEntryClosure(ConcurrentG1RefineThread::sts(),
-                                    g1_rem_set(),
+    new RefineCardTableEntryClosure(g1_rem_set(),
                                     concurrent_g1_refine());
   JavaThread::dirty_card_queue_set().set_closure(_refine_cte_cl);
 
@@ -4317,7 +4314,7 @@
     // this point does not assume that we are the only GC thread
     // running. Note: of course, the actual marking work will
     // not start until the safepoint itself is released in
-    // ConcurrentGCThread::safepoint_desynchronize().
+    // SuspendibleThreadSet::desynchronize().
     doConcurrentMark();
   }
 
--- a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp	Fri Apr 11 11:00:12 2014 +0200
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp	Fri Apr 11 12:29:24 2014 +0200
@@ -77,38 +77,37 @@
       break;
     }
 
-    // Include this thread in safepoints
-    stsJoin();
+    {
+      // Include thread in safepoints
+      SuspendibleThreadSetJoiner sts;
 
-    stat.mark_exec();
+      stat.mark_exec();
 
-    // Process the queue
-    for (;;) {
-      oop java_string = G1StringDedupQueue::pop();
-      if (java_string == NULL) {
-        break;
+      // Process the queue
+      for (;;) {
+        oop java_string = G1StringDedupQueue::pop();
+        if (java_string == NULL) {
+          break;
+        }
+
+        G1StringDedupTable::deduplicate(java_string, stat);
+
+        // Safepoint this thread if needed
+        if (sts.should_yield()) {
+          stat.mark_block();
+          sts.yield();
+          stat.mark_unblock();
+        }
       }
 
-      G1StringDedupTable::deduplicate(java_string, stat);
+      G1StringDedupTable::trim_entry_cache();
 
-      // Safepoint this thread if needed
-      if (stsShouldYield()) {
-        stat.mark_block();
-        stsYield(NULL);
-        stat.mark_unblock();
-      }
-    }
+      stat.mark_done();
 
-    G1StringDedupTable::trim_entry_cache();
-
-    stat.mark_done();
-
-    // Print statistics
-    total_stat.add(stat);
-    print(gclog_or_tty, stat, total_stat);
-
-    // Exclude this thread from safepoints
-    stsLeave();
+      // Print statistics
+      total_stat.add(stat);
+      print(gclog_or_tty, stat, total_stat);
+    }
   }
 
   terminate();
--- a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp	Fri Apr 11 11:00:12 2014 +0200
+++ b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp	Fri Apr 11 12:29:24 2014 +0200
@@ -37,21 +37,10 @@
 
 int  ConcurrentGCThread::_CGC_flag            = CGC_nil;
 
-SuspendibleThreadSet ConcurrentGCThread::_sts;
-
 ConcurrentGCThread::ConcurrentGCThread() :
   _should_terminate(false), _has_terminated(false) {
-  _sts.initialize();
 };
 
-void ConcurrentGCThread::safepoint_synchronize() {
-  _sts.suspend_all();
-}
-
-void ConcurrentGCThread::safepoint_desynchronize() {
-  _sts.resume_all();
-}
-
 void ConcurrentGCThread::create_and_start() {
   if (os::create_thread(this, os::cgc_thread)) {
     // XXX: need to set this to low priority
@@ -92,78 +81,6 @@
   ThreadLocalStorage::set_thread(NULL);
 }
 
-
-void SuspendibleThreadSet::initialize_work() {
-  MutexLocker x(STS_init_lock);
-  if (!_initialized) {
-    _m             = new Monitor(Mutex::leaf,
-                                 "SuspendibleThreadSetLock", true);
-    _async         = 0;
-    _async_stop    = false;
-    _async_stopped = 0;
-    _initialized   = true;
-  }
-}
-
-void SuspendibleThreadSet::join() {
-  initialize();
-  MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
-  while (_async_stop) _m->wait(Mutex::_no_safepoint_check_flag);
-  _async++;
-  assert(_async > 0, "Huh.");
-}
-
-void SuspendibleThreadSet::leave() {
-  assert(_initialized, "Must be initialized.");
-  MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
-  _async--;
-  assert(_async >= 0, "Huh.");
-  if (_async_stop) _m->notify_all();
-}
-
-void SuspendibleThreadSet::yield(const char* id) {
-  assert(_initialized, "Must be initialized.");
-  if (_async_stop) {
-    MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
-    if (_async_stop) {
-      _async_stopped++;
-      assert(_async_stopped > 0, "Huh.");
-      if (_async_stopped == _async) {
-        if (ConcGCYieldTimeout > 0) {
-          double now = os::elapsedTime();
-          guarantee((now - _suspend_all_start) * 1000.0 <
-                    (double)ConcGCYieldTimeout,
-                    "Long delay; whodunit?");
-        }
-      }
-      _m->notify_all();
-      while (_async_stop) _m->wait(Mutex::_no_safepoint_check_flag);
-      _async_stopped--;
-      assert(_async >= 0, "Huh");
-      _m->notify_all();
-    }
-  }
-}
-
-void SuspendibleThreadSet::suspend_all() {
-  initialize();  // If necessary.
-  if (ConcGCYieldTimeout > 0) {
-    _suspend_all_start = os::elapsedTime();
-  }
-  MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
-  assert(!_async_stop, "Only one at a time.");
-  _async_stop = true;
-  while (_async_stopped < _async) _m->wait(Mutex::_no_safepoint_check_flag);
-}
-
-void SuspendibleThreadSet::resume_all() {
-  assert(_initialized, "Must be initialized.");
-  MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
-  assert(_async_stopped == _async, "Huh.");
-  _async_stop = false;
-  _m->notify_all();
-}
-
 static void _sltLoop(JavaThread* thread, TRAPS) {
   SurrogateLockerThread* slt = (SurrogateLockerThread*)thread;
   slt->loop();
@@ -283,30 +200,3 @@
   }
   assert(!_monitor.owned_by_self(), "Should unlock before exit.");
 }
-
-
-// ===== STS Access From Outside CGCT =====
-
-void ConcurrentGCThread::stsYield(const char* id) {
-  assert( Thread::current()->is_ConcurrentGC_thread(),
-          "only a conc GC thread can call this" );
-  _sts.yield(id);
-}
-
-bool ConcurrentGCThread::stsShouldYield() {
-  assert( Thread::current()->is_ConcurrentGC_thread(),
-          "only a conc GC thread can call this" );
-  return _sts.should_yield();
-}
-
-void ConcurrentGCThread::stsJoin() {
-  assert( Thread::current()->is_ConcurrentGC_thread(),
-          "only a conc GC thread can call this" );
-  _sts.join();
-}
-
-void ConcurrentGCThread::stsLeave() {
-  assert( Thread::current()->is_ConcurrentGC_thread(),
-          "only a conc GC thread can call this" );
-  _sts.leave();
-}
--- a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp	Fri Apr 11 11:00:12 2014 +0200
+++ b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp	Fri Apr 11 12:29:24 2014 +0200
@@ -26,55 +26,8 @@
 #define SHARE_VM_GC_IMPLEMENTATION_SHARED_CONCURRENTGCTHREAD_HPP
 
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
+#include "gc_implementation/shared/suspendibleThreadSet.hpp"
 #include "runtime/thread.hpp"
-#endif // INCLUDE_ALL_GCS
-
-class VoidClosure;
-
-// A SuspendibleThreadSet is (obviously) a set of threads that can be
-// suspended.  A thread can join and later leave the set, and periodically
-// yield.  If some thread (not in the set) requests, via suspend_all, that
-// the threads be suspended, then the requesting thread is blocked until
-// all the threads in the set have yielded or left the set.  (Threads may
-// not enter the set when an attempted suspension is in progress.)  The
-// suspending thread later calls resume_all, allowing the suspended threads
-// to continue.
-
-class SuspendibleThreadSet {
-  Monitor* _m;
-  int      _async;
-  bool     _async_stop;
-  int      _async_stopped;
-  bool     _initialized;
-  double   _suspend_all_start;
-
-  void initialize_work();
-
- public:
-  SuspendibleThreadSet() : _initialized(false) {}
-
-  // Add the current thread to the set.  May block if a suspension
-  // is in progress.
-  void join();
-  // Removes the current thread from the set.
-  void leave();
-  // Returns "true" iff an suspension is in progress.
-  bool should_yield() { return _async_stop; }
-  // Suspends the current thread if a suspension is in progress (for
-  // the duration of the suspension.)
-  void yield(const char* id);
-  // Return when all threads in the set are suspended.
-  void suspend_all();
-  // Allow suspended threads to resume.
-  void resume_all();
-  // Redundant initializations okay.
-  void initialize() {
-    // Double-check dirty read idiom.
-    if (!_initialized) initialize_work();
-  }
-};
-
 
 class ConcurrentGCThread: public NamedThread {
   friend class VMStructs;
@@ -96,9 +49,6 @@
   static int set_CGC_flag(int b)           { return _CGC_flag |= b; }
   static int reset_CGC_flag(int b)         { return _CGC_flag &= ~b; }
 
-  // All instances share this one set.
-  static SuspendibleThreadSet _sts;
-
   // Create and start the thread (setting it's priority high.)
   void create_and_start();
 
@@ -121,25 +71,6 @@
 
   // Tester
   bool is_ConcurrentGC_thread() const          { return true;       }
-
-  static void safepoint_synchronize();
-  static void safepoint_desynchronize();
-
-  // All overridings should probably do _sts::yield, but we allow
-  // overriding for distinguished debugging messages.  Default is to do
-  // nothing.
-  virtual void yield() {}
-
-  bool should_yield() { return _sts.should_yield(); }
-
-  // they are prefixed by sts since there are already yield() and
-  // should_yield() (non-static) methods in this class and it was an
-  // easy way to differentiate them.
-  static void stsYield(const char* id);
-  static bool stsShouldYield();
-  static void stsJoin();
-  static void stsLeave();
-
 };
 
 // The SurrogateLockerThread is used by concurrent GC threads for
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/shared/suspendibleThreadSet.cpp	Fri Apr 11 12:29:24 2014 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc_implementation/shared/suspendibleThreadSet.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/thread.inline.hpp"
+
+uint   SuspendibleThreadSet::_nthreads          = 0;
+uint   SuspendibleThreadSet::_nthreads_stopped  = 0;
+bool   SuspendibleThreadSet::_suspend_all       = false;
+double SuspendibleThreadSet::_suspend_all_start = 0.0;
+
+void SuspendibleThreadSet::join() {
+  MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag);
+  while (_suspend_all) {
+    ml.wait(Mutex::_no_safepoint_check_flag);
+  }
+  _nthreads++;
+}
+
+void SuspendibleThreadSet::leave() {
+  MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag);
+  assert(_nthreads > 0, "Invalid");
+  _nthreads--;
+  if (_suspend_all) {
+    ml.notify_all();
+  }
+}
+
+void SuspendibleThreadSet::yield() {
+  if (_suspend_all) {
+    MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag);
+    if (_suspend_all) {
+      _nthreads_stopped++;
+      if (_nthreads_stopped == _nthreads) {
+        if (ConcGCYieldTimeout > 0) {
+          double now = os::elapsedTime();
+          guarantee((now - _suspend_all_start) * 1000.0 < (double)ConcGCYieldTimeout, "Long delay");
+        }
+      }
+      ml.notify_all();
+      while (_suspend_all) {
+        ml.wait(Mutex::_no_safepoint_check_flag);
+      }
+      assert(_nthreads_stopped > 0, "Invalid");
+      _nthreads_stopped--;
+      ml.notify_all();
+    }
+  }
+}
+
+void SuspendibleThreadSet::synchronize() {
+  assert(Thread::current()->is_VM_thread(), "Must be the VM thread");
+  if (ConcGCYieldTimeout > 0) {
+    _suspend_all_start = os::elapsedTime();
+  }
+  MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag);
+  assert(!_suspend_all, "Only one at a time");
+  _suspend_all = true;
+  while (_nthreads_stopped < _nthreads) {
+    ml.wait(Mutex::_no_safepoint_check_flag);
+  }
+}
+
+void SuspendibleThreadSet::desynchronize() {
+  assert(Thread::current()->is_VM_thread(), "Must be the VM thread");
+  MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag);
+  assert(_nthreads_stopped == _nthreads, "Invalid");
+  _suspend_all = false;
+  ml.notify_all();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/shared/suspendibleThreadSet.hpp	Fri Apr 11 12:29:24 2014 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_SUSPENDIBLETHREADSET_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_SHARED_SUSPENDIBLETHREADSET_HPP
+
+#include "memory/allocation.hpp"
+
+// A SuspendibleThreadSet is a set of threads that can be suspended.
+// A thread can join and later leave the set, and periodically yield.
+// If some thread (not in the set) requests, via synchronize(), that
+// the threads be suspended, then the requesting thread is blocked
+// until all the threads in the set have yielded or left the set. Threads
+// may not enter the set when an attempted suspension is in progress. The
+// suspending thread later calls desynchronize(), allowing the suspended
+// threads to continue.
+class SuspendibleThreadSet : public AllStatic {
+private:
+  static uint   _nthreads;
+  static uint   _nthreads_stopped;
+  static bool   _suspend_all;
+  static double _suspend_all_start;
+
+public:
+  // Add the current thread to the set. May block if a suspension is in progress.
+  static void join();
+
+  // Removes the current thread from the set.
+  static void leave();
+
+  // Returns true if an suspension is in progress.
+  static bool should_yield() { return _suspend_all; }
+
+  // Suspends the current thread if a suspension is in progress.
+  static void yield();
+
+  // Returns when all threads in the set are suspended.
+  static void synchronize();
+
+  // Resumes all suspended threads in the set.
+  static void desynchronize();
+};
+
+class SuspendibleThreadSetJoiner : public StackObj {
+public:
+  SuspendibleThreadSetJoiner() {
+    SuspendibleThreadSet::join();
+  }
+
+  ~SuspendibleThreadSetJoiner() {
+    SuspendibleThreadSet::leave();
+  }
+
+  bool should_yield() {
+    return SuspendibleThreadSet::should_yield();
+  }
+
+  void yield() {
+    SuspendibleThreadSet::yield();
+  }
+};
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_SUSPENDIBLETHREADSET_HPP
--- a/hotspot/src/share/vm/runtime/mutexLocker.cpp	Fri Apr 11 11:00:12 2014 +0200
+++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp	Fri Apr 11 12:29:24 2014 +0200
@@ -69,7 +69,7 @@
 Monitor* SerializePage_lock           = NULL;
 Monitor* Threads_lock                 = NULL;
 Monitor* CGC_lock                     = NULL;
-Mutex*   STS_init_lock                = NULL;
+Monitor* STS_lock                     = NULL;
 Monitor* SLT_lock                     = NULL;
 Monitor* iCMS_lock                    = NULL;
 Monitor* FullGCCount_lock             = NULL;
@@ -173,7 +173,7 @@
   def(tty_lock                     , Mutex  , event,       true ); // allow to lock in VM
 
   def(CGC_lock                   , Monitor, special,     true ); // coordinate between fore- and background GC
-  def(STS_init_lock              , Mutex,   leaf,        true );
+  def(STS_lock                   , Monitor, leaf,        true );
   if (UseConcMarkSweepGC) {
     def(iCMS_lock                  , Monitor, special,     true ); // CMS incremental mode start/stop notification
   }
--- a/hotspot/src/share/vm/runtime/mutexLocker.hpp	Fri Apr 11 11:00:12 2014 +0200
+++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp	Fri Apr 11 12:29:24 2014 +0200
@@ -79,7 +79,7 @@
                                                  // (also used by Safepoints too to block threads creation/destruction)
 extern Monitor* CGC_lock;                        // used for coordination between
                                                  // fore- & background GC threads.
-extern Mutex*   STS_init_lock;                   // coordinate initialization of SuspendibleThreadSets.
+extern Monitor* STS_lock;                        // used for joining/leaving SuspendibleThreadSet.
 extern Monitor* SLT_lock;                        // used in CMS GC for acquiring PLL
 extern Monitor* iCMS_lock;                       // CMS incremental mode start/stop notification
 extern Monitor* FullGCCount_lock;                // in support of "concurrent" full gc
--- a/hotspot/src/share/vm/runtime/safepoint.cpp	Fri Apr 11 11:00:12 2014 +0200
+++ b/hotspot/src/share/vm/runtime/safepoint.cpp	Fri Apr 11 12:29:24 2014 +0200
@@ -75,7 +75,7 @@
 #endif
 #if INCLUDE_ALL_GCS
 #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp"
-#include "gc_implementation/shared/concurrentGCThread.hpp"
+#include "gc_implementation/shared/suspendibleThreadSet.hpp"
 #endif // INCLUDE_ALL_GCS
 #ifdef COMPILER1
 #include "c1/c1_globals.hpp"
@@ -110,7 +110,7 @@
     // more-general mechanism below.  DLD (01/05).
     ConcurrentMarkSweepThread::synchronize(false);
   } else if (UseG1GC) {
-    ConcurrentGCThread::safepoint_synchronize();
+    SuspendibleThreadSet::synchronize();
   }
 #endif // INCLUDE_ALL_GCS
 
@@ -486,7 +486,7 @@
   if (UseConcMarkSweepGC) {
     ConcurrentMarkSweepThread::desynchronize(false);
   } else if (UseG1GC) {
-    ConcurrentGCThread::safepoint_desynchronize();
+    SuspendibleThreadSet::desynchronize();
   }
 #endif // INCLUDE_ALL_GCS
   // record this time so VMThread can keep track how much time has elapsed