1/*
2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#ifndef SHARE_UTILITIES_WAITBARRIER_HPP
26#define SHARE_UTILITIES_WAITBARRIER_HPP
27
28#include "memory/allocation.hpp"
29#include "runtime/thread.hpp"
30#include "utilities/debug.hpp"
31#include "utilities/waitBarrier_generic.hpp"
32
33#if defined(LINUX)
34#include "waitBarrier_linux.hpp"
35typedef LinuxWaitBarrier WaitBarrierDefault;
36#else
37typedef GenericWaitBarrier WaitBarrierDefault;
38#endif
39
40// Platform independent WaitBarrier API.
41// An armed WaitBarrier prevents threads from advancing until the threads are
42// woken by calling disarm(). The barrier is armed by setting a non-zero value
43// - the tag. When the WaitBarrier is created, a thread is designated the owner
44// and is the thread that should arm and disarm the WaitBarrier. In debug builds
45// this is enforced.
46//
47// Expected Usage:
48// - Arming thread:
49// tag = ...; // non-zero value
50// barrier.arm(tag);
51// <publish tag>
52// <work>
53// barrier.disarm();
54//
55// - After arm(tag) returns any thread calling wait(tag) will block.
56// - Calling disarm() guarantees any thread calling or that has wait(tag) will
57// return. Either they will see the WaitBarrier as disarmed or they will be
58// unblocked and eligible to execute again when disarm() returns.
59// - After calling disarm() the barrier is ready to be re-armed with a new tag.
60// (may not be re-armed with last used tag)
61//
62// - Waiting threads
63// wait(tag); // don't execute following code unless 'safe'
64// <work>
65//
66// - A call to wait(tag) will block if the barrier is armed with the value
67// 'tag'; else it will return immediately.
68// - A blocked thread is eligible to execute again once the barrier is
69// disarmed when disarm() has been called.
70//
71// It is a usage error to:
72// - call arm on a barrier that is already armed
73// - call disarm on a barrier that is not armed
74// - arm with the same tag as last used
75// Usage errors are checked in debug builds but may be ignored otherwise.
76//
77// A primary goal of the WaitBarrier implementation is to wake all waiting
78// threads as fast, and as concurrently, as possible.
79//
80template <typename WaitBarrierImpl>
81class WaitBarrierType : public CHeapObj<mtInternal> {
82 WaitBarrierImpl _impl;
83
84 // Prevent copying and assignment of WaitBarrier instances.
85 WaitBarrierType(const WaitBarrierDefault&);
86 WaitBarrierType& operator=(const WaitBarrierDefault&);
87
88#ifdef ASSERT
89 int _last_arm_tag;
90 Thread* _owner;
91#endif
92
93 public:
94 WaitBarrierType(Thread* owner) : _impl() {
95#ifdef ASSERT
96 _last_arm_tag = 0;
97 _owner = owner;
98#endif
99 }
100 ~WaitBarrierType() {}
101
102 // Returns implementation description.
103 const char* description() { return _impl.description(); }
104
105 // Guarantees any thread calling wait() with same tag will be blocked.
106 // Provides a trailing fence.
107 void arm(int barrier_tag) {
108#ifdef ASSERT
109 assert(_last_arm_tag != barrier_tag, "Re-arming with same tag");
110 _last_arm_tag = barrier_tag;
111 assert(_owner == Thread::current(), "Not owner thread");
112#endif
113 _impl.arm(barrier_tag);
114 }
115
116 // Guarantees any thread that called wait() will be awake when it returns.
117 // Provides a trailing fence.
118 void disarm() {
119 assert(_owner == Thread::current(), "Not owner thread");
120 _impl.disarm();
121 }
122
123 // Guarantees not to return until disarm() is called,
124 // if called with currently armed tag (otherwise returns immediately).
125 // Implementations must guarantee no spurious wakeups.
126 // Provides a trailing fence.
127 void wait(int barrier_tag) {
128 assert(_owner != Thread::current(), "Trying to wait with owner thread");
129 _impl.wait(barrier_tag);
130 }
131};
132
133typedef WaitBarrierType<WaitBarrierDefault> WaitBarrier;
134
135#endif // SHARE_UTILITIES_WAITBARRIER_HPP
136