136 lines
4.7 KiB
C++
136 lines
4.7 KiB
C++
|
/*
|
||
|
* 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/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;
|
||
|
|
||
|
// 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 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
|