--- old/src/hotspot/share/utilities/waitBarrier.hpp 2018-12-18 11:15:43.079321229 +0100 +++ new/src/hotspot/share/utilities/waitBarrier.hpp 2018-12-18 11:15:42.759309723 +0100 @@ -26,6 +26,8 @@ #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) @@ -36,21 +38,38 @@ #endif // Platform independent WaitBarrier API. -// The WaitBarrier primary objective is to wake threads waiting in wait() fast. -// It can be arm with any int, the tag, that is not 0. -// - After arm() returns any thread calling wait(tag) with the correct tag will be blocked. -// - After disarm() is called any thread calling wait(...) will never block. -// - When wake() returns no threads are blocked any more, if it was disarmed before. -// - After calling disarm() and wake() it my be re-armed immediately with a different tag. -// - Re-arming with the same tag before all threads returned from previously wait -// is implementation defined. They may or may not return from the previously wait(). -// Wake thread: -// - arm(tag) -// - *work* -// - disarm() -// - wake() -// Wait thread: -// - wait(tag) +// 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. +// +// 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. +// +// 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; @@ -59,8 +78,18 @@ WaitBarrierType(const WaitBarrierDefault&); WaitBarrierType& operator=(const WaitBarrierDefault&); +#ifdef ASSERT + int _last_arm_tag; + Thread* _owner; +#endif + public: - WaitBarrierType() : _impl() {} + WaitBarrierType(Thread* owner) : _impl() { +#ifdef ASSERT + _last_arm_tag = 0; + _owner = owner; +#endif + } ~WaitBarrierType() {} // Returns implementation type. @@ -68,19 +97,35 @@ // Guarantees any thread calling wait() with same tag will be blocked. // Provides a trailing fence. - void arm(int barrier_tag) { _impl.arm(barrier_tag); } + 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() { _impl.disarm(); } + 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() { _impl.wake(); } + void wake() { + assert(_owner == Thread::current(), "Not owner thread"); + _impl.wake(); + } // Guarantees to return if disarm() and wake() is called. // Provides a trailing fence. - void wait(int barrier_tag) { _impl.wait(barrier_tag); } + void wait(int barrier_tag) { + assert(_owner != Thread::current(), "Trying to wait with owner thread"); + _impl.wait(barrier_tag); + } }; typedef WaitBarrierType WaitBarrier;