--- old/make/hotspot/lib/JvmFeatures.gmk 2017-10-18 16:45:42.364068208 +0200 +++ new/make/hotspot/lib/JvmFeatures.gmk 2017-10-18 16:45:42.041067370 +0200 @@ -132,6 +132,7 @@ cms/ g1/ parallel/ JVM_EXCLUDE_FILES += \ concurrentGCThread.cpp \ + suspendibleThreadSet.cpp \ plab.cpp JVM_EXCLUDE_FILES += \ g1MemoryPool.cpp \ --- old/src/hotspot/share/gc/g1/concurrentG1RefineThread.cpp 2017-10-18 16:45:43.370070818 +0200 +++ new/src/hotspot/share/gc/g1/concurrentG1RefineThread.cpp 2017-10-18 16:45:43.075070053 +0200 @@ -23,11 +23,11 @@ */ #include "precompiled.hpp" -#include "gc/common/suspendibleThreadSet.hpp" #include "gc/g1/concurrentG1Refine.hpp" #include "gc/g1/concurrentG1RefineThread.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1RemSet.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "runtime/handles.inline.hpp" --- old/src/hotspot/share/gc/g1/concurrentMarkThread.cpp 2017-10-18 16:45:44.385073451 +0200 +++ new/src/hotspot/share/gc/g1/concurrentMarkThread.cpp 2017-10-18 16:45:44.089072683 +0200 @@ -24,7 +24,6 @@ #include "precompiled.hpp" #include "classfile/classLoaderData.hpp" -#include "gc/common/suspendibleThreadSet.hpp" #include "gc/g1/concurrentMarkThread.inline.hpp" #include "gc/g1/g1Analytics.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" @@ -36,6 +35,7 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/gcTraceTime.inline.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "runtime/vmThread.hpp" --- old/src/hotspot/share/gc/g1/g1CardLiveData.cpp 2017-10-18 16:45:45.387076050 +0200 +++ new/src/hotspot/share/gc/g1/g1CardLiveData.cpp 2017-10-18 16:45:45.091075282 +0200 @@ -23,10 +23,10 @@ */ #include "precompiled.hpp" -#include "gc/common/suspendibleThreadSet.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1CardLiveData.inline.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/workgroup.hpp" #include "logging/log.hpp" #include "memory/universe.hpp" --- old/src/hotspot/share/gc/g1/g1CollectedHeap.cpp 2017-10-18 16:45:46.415078716 +0200 +++ new/src/hotspot/share/gc/g1/g1CollectedHeap.cpp 2017-10-18 16:45:46.120077951 +0200 @@ -28,7 +28,6 @@ #include "classfile/symbolTable.hpp" #include "code/codeCache.hpp" #include "code/icBuffer.hpp" -#include "gc/common/suspendibleThreadSet.hpp" #include "gc/g1/bufferingOopClosure.hpp" #include "gc/g1/concurrentG1Refine.hpp" #include "gc/g1/concurrentG1RefineThread.hpp" @@ -68,6 +67,7 @@ #include "gc/shared/generationSpec.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "gc/shared/preservedMarks.inline.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/referenceProcessor.inline.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "logging/log.hpp" --- old/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp 2017-10-18 16:45:47.497081523 +0200 +++ new/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp 2017-10-18 16:45:47.195080739 +0200 @@ -26,7 +26,6 @@ #include "classfile/metadataOnStackMark.hpp" #include "classfile/symbolTable.hpp" #include "code/codeCache.hpp" -#include "gc/common/suspendibleThreadSet.hpp" #include "gc/g1/concurrentMarkThread.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorState.hpp" @@ -46,6 +45,7 @@ #include "gc/shared/genOopClosures.inline.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/strongRootsScope.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "gc/shared/vmGCOperations.hpp" #include "logging/log.hpp" --- old/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp 2017-10-18 16:45:48.531084205 +0200 +++ new/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp 2017-10-18 16:45:48.237083442 +0200 @@ -25,11 +25,11 @@ #ifndef SHARE_VM_GC_G1_G1CONCURRENTMARK_INLINE_HPP #define SHARE_VM_GC_G1_G1CONCURRENTMARK_INLINE_HPP -#include "gc/common/suspendibleThreadSet.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentMark.hpp" #include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" #include "gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "utilities/bitMap.inline.hpp" --- old/src/hotspot/share/gc/g1/g1RemSet.cpp 2017-10-18 16:45:49.556086863 +0200 +++ new/src/hotspot/share/gc/g1/g1RemSet.cpp 2017-10-18 16:45:49.258086090 +0200 @@ -23,7 +23,6 @@ */ #include "precompiled.hpp" -#include "gc/common/suspendibleThreadSet.hpp" #include "gc/g1/concurrentG1Refine.hpp" #include "gc/g1/dirtyCardQueue.hpp" #include "gc/g1/g1BlockOffsetTable.inline.hpp" @@ -38,6 +37,7 @@ #include "gc/g1/heapRegionManager.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "gc/shared/gcTraceTime.inline.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" --- old/src/hotspot/share/gc/g1/g1StringDedupThread.cpp 2017-10-18 16:45:50.581089522 +0200 +++ new/src/hotspot/share/gc/g1/g1StringDedupThread.cpp 2017-10-18 16:45:50.287088759 +0200 @@ -24,11 +24,11 @@ #include "precompiled.hpp" #include "classfile/stringTable.hpp" -#include "gc/common/suspendibleThreadSet.hpp" #include "gc/g1/g1StringDedup.hpp" #include "gc/g1/g1StringDedupQueue.hpp" #include "gc/g1/g1StringDedupTable.hpp" #include "gc/g1/g1StringDedupThread.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" --- old/src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp 2017-10-18 16:45:51.600092165 +0200 +++ new/src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp 2017-10-18 16:45:51.303091395 +0200 @@ -23,13 +23,13 @@ */ #include "precompiled.hpp" -#include "gc/common/suspendibleThreadSet.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1Policy.hpp" #include "gc/g1/g1YoungRemSetSamplingThread.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" +#include "gc/shared/suspendibleThreadSet.hpp" #include "runtime/mutexLocker.hpp" G1YoungRemSetSamplingThread::G1YoungRemSetSamplingThread() : --- old/src/hotspot/share/gc/common/suspendibleThreadSet.cpp 2017-10-18 16:45:52.457094388 +0200 +++ /dev/null 2017-10-18 15:43:18.558225985 +0200 @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2014, 2017, 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/common/suspendibleThreadSet.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/semaphore.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; - -static Semaphore* _synchronize_wakeup = NULL; - -void SuspendibleThreadSet_init() { - assert(_synchronize_wakeup == NULL, "STS already initialized"); - _synchronize_wakeup = new Semaphore(); -} - -bool SuspendibleThreadSet::is_synchronized() { - assert_lock_strong(STS_lock); - assert(_nthreads_stopped <= _nthreads, "invariant"); - return _nthreads_stopped == _nthreads; -} - -void SuspendibleThreadSet::join() { - assert(!Thread::current()->is_suspendible_thread(), "Thread already joined"); - MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); - while (_suspend_all) { - ml.wait(Mutex::_no_safepoint_check_flag); - } - _nthreads++; - DEBUG_ONLY(Thread::current()->set_suspendible_thread();) -} - -void SuspendibleThreadSet::leave() { - assert(Thread::current()->is_suspendible_thread(), "Thread not joined"); - MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); - assert(_nthreads > 0, "Invalid"); - DEBUG_ONLY(Thread::current()->clear_suspendible_thread();) - _nthreads--; - if (_suspend_all && is_synchronized()) { - // This leave completes a request, so inform the requestor. - _synchronize_wakeup->signal(); - } -} - -void SuspendibleThreadSet::yield() { - assert(Thread::current()->is_suspendible_thread(), "Must have joined"); - MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); - if (_suspend_all) { - _nthreads_stopped++; - if (is_synchronized()) { - if (ConcGCYieldTimeout > 0) { - double now = os::elapsedTime(); - guarantee((now - _suspend_all_start) * 1000.0 < (double)ConcGCYieldTimeout, "Long delay"); - } - // This yield completes the request, so inform the requestor. - _synchronize_wakeup->signal(); - } - while (_suspend_all) { - ml.wait(Mutex::_no_safepoint_check_flag); - } - assert(_nthreads_stopped > 0, "Invalid"); - _nthreads_stopped--; - } -} - -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; - if (is_synchronized()) { - return; - } - } // Release lock before semaphore wait. - - // Semaphore initial count is zero. To reach here, there must be at - // least one not yielded thread in the set, e.g. is_synchronized() - // was false before the lock was released. A thread in the set will - // signal the semaphore iff it is the last to yield or leave while - // there is an active suspend request. So there will be exactly one - // signal, which will increment the semaphore count to one, which - // will then be consumed by this wait, returning it to zero. No - // thread can exit yield or enter the set until desynchronize is - // called, so there are no further opportunities for the semaphore - // being signaled until we get back here again for some later - // synchronize call. Hence, there is no need to re-check for - // is_synchronized after the wait; it will always be true there. - _synchronize_wakeup->wait(); - -#ifdef ASSERT - MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); - assert(_suspend_all, "STS not synchronizing"); - assert(is_synchronized(), "STS not synchronized"); -#endif -} - -void SuspendibleThreadSet::desynchronize() { - assert(Thread::current()->is_VM_thread(), "Must be the VM thread"); - MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); - assert(_suspend_all, "STS not synchronizing"); - assert(is_synchronized(), "STS not synchronized"); - _suspend_all = false; - ml.notify_all(); -} --- /dev/null 2017-10-18 15:43:18.558225985 +0200 +++ new/src/hotspot/share/gc/shared/suspendibleThreadSet.cpp 2017-10-18 16:45:52.108093483 +0200 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2014, 2017, 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/common/suspendibleThreadSet.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/semaphore.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; + +static Semaphore* _synchronize_wakeup = NULL; + +void SuspendibleThreadSet_init() { + assert(_synchronize_wakeup == NULL, "STS already initialized"); + _synchronize_wakeup = new Semaphore(); +} + +bool SuspendibleThreadSet::is_synchronized() { + assert_lock_strong(STS_lock); + assert(_nthreads_stopped <= _nthreads, "invariant"); + return _nthreads_stopped == _nthreads; +} + +void SuspendibleThreadSet::join() { + assert(!Thread::current()->is_suspendible_thread(), "Thread already joined"); + MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); + while (_suspend_all) { + ml.wait(Mutex::_no_safepoint_check_flag); + } + _nthreads++; + DEBUG_ONLY(Thread::current()->set_suspendible_thread();) +} + +void SuspendibleThreadSet::leave() { + assert(Thread::current()->is_suspendible_thread(), "Thread not joined"); + MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); + assert(_nthreads > 0, "Invalid"); + DEBUG_ONLY(Thread::current()->clear_suspendible_thread();) + _nthreads--; + if (_suspend_all && is_synchronized()) { + // This leave completes a request, so inform the requestor. + _synchronize_wakeup->signal(); + } +} + +void SuspendibleThreadSet::yield() { + assert(Thread::current()->is_suspendible_thread(), "Must have joined"); + MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); + if (_suspend_all) { + _nthreads_stopped++; + if (is_synchronized()) { + if (ConcGCYieldTimeout > 0) { + double now = os::elapsedTime(); + guarantee((now - _suspend_all_start) * 1000.0 < (double)ConcGCYieldTimeout, "Long delay"); + } + // This yield completes the request, so inform the requestor. + _synchronize_wakeup->signal(); + } + while (_suspend_all) { + ml.wait(Mutex::_no_safepoint_check_flag); + } + assert(_nthreads_stopped > 0, "Invalid"); + _nthreads_stopped--; + } +} + +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; + if (is_synchronized()) { + return; + } + } // Release lock before semaphore wait. + + // Semaphore initial count is zero. To reach here, there must be at + // least one not yielded thread in the set, e.g. is_synchronized() + // was false before the lock was released. A thread in the set will + // signal the semaphore iff it is the last to yield or leave while + // there is an active suspend request. So there will be exactly one + // signal, which will increment the semaphore count to one, which + // will then be consumed by this wait, returning it to zero. No + // thread can exit yield or enter the set until desynchronize is + // called, so there are no further opportunities for the semaphore + // being signaled until we get back here again for some later + // synchronize call. Hence, there is no need to re-check for + // is_synchronized after the wait; it will always be true there. + _synchronize_wakeup->wait(); + +#ifdef ASSERT + MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); + assert(_suspend_all, "STS not synchronizing"); + assert(is_synchronized(), "STS not synchronized"); +#endif +} + +void SuspendibleThreadSet::desynchronize() { + assert(Thread::current()->is_VM_thread(), "Must be the VM thread"); + MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); + assert(_suspend_all, "STS not synchronizing"); + assert(is_synchronized(), "STS not synchronized"); + _suspend_all = false; + ml.notify_all(); +} --- old/src/hotspot/share/gc/common/suspendibleThreadSet.hpp 2017-10-18 16:45:53.011095825 +0200 +++ /dev/null 2017-10-18 15:43:18.558225985 +0200 @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2014, 2017, 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_GC_COMMON_SUSPENDIBLETHREADSET_HPP -#define SHARE_GC_COMMON_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 { - friend class SuspendibleThreadSetJoiner; - friend class SuspendibleThreadSetLeaver; - -private: - static uint _nthreads; - static uint _nthreads_stopped; - static bool _suspend_all; - static double _suspend_all_start; - - static bool is_synchronized(); - - // 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(); - -public: - // 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 { -private: - bool _active; - -public: - SuspendibleThreadSetJoiner(bool active = true) : _active(active) { - if (_active) { - SuspendibleThreadSet::join(); - } - } - - ~SuspendibleThreadSetJoiner() { - if (_active) { - SuspendibleThreadSet::leave(); - } - } - - bool should_yield() { - if (_active) { - return SuspendibleThreadSet::should_yield(); - } else { - return false; - } - } - - void yield() { - assert(_active, "Thread has not joined the suspendible thread set"); - SuspendibleThreadSet::yield(); - } -}; - -class SuspendibleThreadSetLeaver : public StackObj { -private: - bool _active; - -public: - SuspendibleThreadSetLeaver(bool active = true) : _active(active) { - if (_active) { - SuspendibleThreadSet::leave(); - } - } - - ~SuspendibleThreadSetLeaver() { - if (_active) { - SuspendibleThreadSet::join(); - } - } -}; - -#endif // SHARE_GC_COMMON_SUSPENDIBLETHREADSET_HPP --- /dev/null 2017-10-18 15:43:18.558225985 +0200 +++ new/src/hotspot/share/gc/shared/suspendibleThreadSet.hpp 2017-10-18 16:45:52.661094917 +0200 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014, 2017, 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_GC_COMMON_SUSPENDIBLETHREADSET_HPP +#define SHARE_GC_COMMON_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 { + friend class SuspendibleThreadSetJoiner; + friend class SuspendibleThreadSetLeaver; + +private: + static uint _nthreads; + static uint _nthreads_stopped; + static bool _suspend_all; + static double _suspend_all_start; + + static bool is_synchronized(); + + // 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(); + +public: + // 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 { +private: + bool _active; + +public: + SuspendibleThreadSetJoiner(bool active = true) : _active(active) { + if (_active) { + SuspendibleThreadSet::join(); + } + } + + ~SuspendibleThreadSetJoiner() { + if (_active) { + SuspendibleThreadSet::leave(); + } + } + + bool should_yield() { + if (_active) { + return SuspendibleThreadSet::should_yield(); + } else { + return false; + } + } + + void yield() { + assert(_active, "Thread has not joined the suspendible thread set"); + SuspendibleThreadSet::yield(); + } +}; + +class SuspendibleThreadSetLeaver : public StackObj { +private: + bool _active; + +public: + SuspendibleThreadSetLeaver(bool active = true) : _active(active) { + if (_active) { + SuspendibleThreadSet::leave(); + } + } + + ~SuspendibleThreadSetLeaver() { + if (_active) { + SuspendibleThreadSet::join(); + } + } +}; + +#endif // SHARE_GC_COMMON_SUSPENDIBLETHREADSET_HPP