/* * Copyright (c) 2018, 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_UTILITIES_WAITBARRIER_HPP #define SHARE_UTILITIES_WAITBARRIER_HPP #include "memory/allocation.hpp" #include "runtime/thread.hpp" #include "utilities/debug.hpp" #include "utilities/waitBarrier_generic.hpp" #if defined(LINUX) #include "waitBarrier_linux.hpp" typedef LinuxWaitBarrier WaitBarrierDefault; #else typedef GenericWaitBarrier WaitBarrierDefault; #endif // Platform independent WaitBarrier API. // An armed WaitBarrier prevents threads from advancing until the // barrier is disarmed and the waiting threads woken. The barrier is // armed by setting a non-zero value - the tag. // When the WaitBarrier is created, a thread is designated the owner // and is the thread that should arm/disarm/wake the WaitBarrier. In // debug builds this is enforced. // // Expected Usage: // - Arming thread: // tag = ...; // non-zero value // barrier.arm(tag); // // // barrier.disarm(); // barrier.wake(); // // - After arm(tag) returns any thread calling wait(tag) will block. // - After disarm() returns any subsequent calls to wait(tag) will not block. // - After wake() returns all blocked threads are unblocked and eligible to // execute again. // - After calling disarm() and wake() the barrier is ready to be re-armed // with a new tag. (may not be re-armed with last used tag) // // - Waiting threads // wait(tag); // don't execute following code unless 'safe' // // // - A call to wait(tag) will block if the barrier is armed with the value // 'tag'; else it will return immediately. // - A blocked thread is eligible to execute again once the barrier is // disarmed and wake() has been called. // // It is a usage error to: // - call wake on a barrier that is still armed // - call arm on a barrier that is already armed // - call disarm on a barrier that is not armed // - arm with the same tag as last used // Usage errors are checked in debug builds but may be ignored otherwise. // // A primary goal of the WaitBarrier implementation is to wake all waiting // threads as fast, and as concurrently, as possible. // template class WaitBarrierType : public CHeapObj { WaitBarrierImpl _impl; // Prevent copying and assignment of WaitBarrier instances. WaitBarrierType(const WaitBarrierDefault&); WaitBarrierType& operator=(const WaitBarrierDefault&); #ifdef ASSERT int _last_arm_tag; Thread* _owner; #endif public: WaitBarrierType(Thread* owner) : _impl() { #ifdef ASSERT _last_arm_tag = 0; _owner = owner; #endif } ~WaitBarrierType() {} // Returns implementation type. const char* description() { return _impl.description(); } // Guarantees any thread calling wait() with same tag will be blocked. // Provides a trailing fence. void arm(int barrier_tag) { #ifdef ASSERT assert(_last_arm_tag != barrier_tag, "Re-arming with same tag"); _last_arm_tag = barrier_tag; assert(_owner == Thread::current(), "Not owner thread"); #endif _impl.arm(barrier_tag); } // Guarantees any thread calling wait() with any tag will not be blocked. // Provides a trailing fence. void disarm() { assert(_owner == Thread::current(), "Not owner thread"); _impl.disarm(); } // Guarantees any thread called wait() will be awake when it returns. // Provides a trailing fence. void wake() { assert(_owner == Thread::current(), "Not owner thread"); _impl.wake(); } // Guarantees not to return until disarm() is called, // if called with currently armed tag (otherwise returns immediately). // Implementation must guarantee no spurious wakeups. // Guarantees to return if disarm() and wake() is called. // Provides a trailing fence. void wait(int barrier_tag) { assert(_owner != Thread::current(), "Trying to wait with owner thread"); _impl.wait(barrier_tag); } }; typedef WaitBarrierType WaitBarrier; #endif // SHARE_UTILITIES_WAITBARRIER_HPP