--- 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