jdk-24/src/hotspot/share/utilities/waitBarrier.hpp

135 lines
4.6 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2019, 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/globalDefinitions.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 disarm(). 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 disarm the WaitBarrier. In debug builds
// this is enforced.
//
// Expected Usage:
// - Arming thread:
// tag = ...; // non-zero value
// barrier.arm(tag);
// <publish tag>
// <work>
// barrier.disarm();
//
// - After arm(tag) returns any thread calling wait(tag) will block.
// - Calling disarm() guarantees any thread calling or that has wait(tag) will
// return. Either they will see the WaitBarrier as disarmed or they will be
// unblocked and eligible to execute again when disarm() returns.
// - After calling disarm() 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'
// <work>
//
// - 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 disarm() has been called.
//
// It is a usage error to:
// - 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 <typename WaitBarrierImpl>
class WaitBarrierType : public CHeapObj<mtInternal> {
WaitBarrierImpl _impl;
NONCOPYABLE(WaitBarrierType);
#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 description.
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 that called wait() will be awake when it returns.
// Provides a trailing fence.
void disarm() {
assert(_owner == Thread::current(), "Not owner thread");
_impl.disarm();
}
// Guarantees not to return until disarm() 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<WaitBarrierDefault> WaitBarrier;
#endif // SHARE_UTILITIES_WAITBARRIER_HPP