/* * 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 threads are // woken by calling wake(). 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 and wake the WaitBarrier. In debug builds // this is enforced. // // Expected Usage: // - Arming thread: // tag = ...; // non-zero value // barrier.arm(tag); // // // barrier.wake(); // // - After arm(tag) returns any thread calling wait(tag) will block. // - Calling wake() guarantees any thread calling or called wait(tag) will // return. Either they will see the WaitBarrier as disarmed or they will be // unblocked and eligible to execute again when wake() returns. // - After calling 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 when wake() has been called. // // It is a usage error to: // - call arm on a barrier that is already armed // - call wake 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 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 wake() is called, // if called with currently armed tag (otherwise returns immediately). // Implementations must guarantee no spurious wakeups. // 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