1 /*
2 * Copyright (c) 2017, 2019, Red Hat, Inc. 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_GC_SHENANDOAH_SHENANDOAHSHAREDVARIABLES_HPP
26 #define SHARE_GC_SHENANDOAH_SHENANDOAHSHAREDVARIABLES_HPP
27
28 #include "gc/shenandoah/shenandoahPadding.hpp"
29 #include "memory/allocation.hpp"
30 #include "runtime/atomic.hpp"
31
32 typedef jbyte ShenandoahSharedValue;
33
34 // Needed for cooperation with generated code.
35 STATIC_ASSERT(sizeof(ShenandoahSharedValue) == 1);
36
37 typedef struct ShenandoahSharedFlag {
38 enum {
39 UNSET = 0,
40 SET = 1
41 };
42
43 shenandoah_padding(0);
44 volatile ShenandoahSharedValue value;
45 shenandoah_padding(1);
46
47 ShenandoahSharedFlag() {
48 unset();
49 }
50
51 void set() {
52 Atomic::release_store_fence(&value, (ShenandoahSharedValue)SET);
53 }
54
55 void unset() {
56 Atomic::release_store_fence(&value, (ShenandoahSharedValue)UNSET);
57 }
58
59 bool is_set() const {
60 return Atomic::load_acquire(&value) == SET;
61 }
62
63 bool is_unset() const {
64 return Atomic::load_acquire(&value) == UNSET;
65 }
66
67 void set_cond(bool val) {
68 if (val) {
69 set();
70 } else {
71 unset();
72 }
73 }
74
75 bool try_set() {
76 if (is_set()) {
77 return false;
78 }
79 ShenandoahSharedValue old = Atomic::cmpxchg(&value, (ShenandoahSharedValue)UNSET, (ShenandoahSharedValue)SET);
80 return old == UNSET; // success
81 }
82
83 bool try_unset() {
84 if (!is_set()) {
85 return false;
86 }
87 ShenandoahSharedValue old = Atomic::cmpxchg(&value, (ShenandoahSharedValue)SET, (ShenandoahSharedValue)UNSET);
88 return old == SET; // success
89 }
90
91 volatile ShenandoahSharedValue* addr_of() {
92 return &value;
93 }
94
95 private:
96 volatile ShenandoahSharedValue* operator&() {
97 fatal("Use addr_of() instead");
98 return nullptr;
99 }
100
101 bool operator==(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
102 bool operator!=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
103 bool operator> (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
104 bool operator>=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
105 bool operator< (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
106 bool operator<=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
107
108 } ShenandoahSharedFlag;
109
110 typedef struct ShenandoahSharedBitmap {
111 shenandoah_padding(0);
112 volatile ShenandoahSharedValue value;
113 shenandoah_padding(1);
114
115 ShenandoahSharedBitmap() {
116 clear();
117 }
118
119 void set(uint mask) {
120 assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
121 ShenandoahSharedValue mask_val = (ShenandoahSharedValue) mask;
122 while (true) {
123 ShenandoahSharedValue ov = Atomic::load_acquire(&value);
124 // We require all bits of mask_val to be set
125 if ((ov & mask_val) == mask_val) {
126 // already set
127 return;
128 }
129
130 ShenandoahSharedValue nv = ov | mask_val;
131 if (Atomic::cmpxchg(&value, ov, nv) == ov) {
132 // successfully set: if value returned from cmpxchg equals ov, then nv has overwritten value.
133 return;
134 }
135 }
136 }
137
138 void unset(uint mask) {
139 assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
140 ShenandoahSharedValue mask_val = (ShenandoahSharedValue) mask;
141 while (true) {
142 ShenandoahSharedValue ov = Atomic::load_acquire(&value);
143 if ((ov & mask_val) == 0) {
144 // already unset
145 return;
146 }
147
148 ShenandoahSharedValue nv = ov & ~mask_val;
149 if (Atomic::cmpxchg(&value, ov, nv) == ov) {
150 // successfully unset
151 return;
152 }
153 }
154 }
155
156 void clear() {
157 Atomic::release_store_fence(&value, (ShenandoahSharedValue)0);
158 }
159
160 // Returns true iff any bit set in mask is set in this.value.
161 bool is_set(uint mask) const {
162 return !is_unset(mask);
163 }
164
165 // Returns true iff all bits set in mask are set in this.value.
166 bool is_set_exactly(uint mask) const {
167 assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
168 uint uvalue = Atomic::load_acquire(&value);
169 return (uvalue & mask) == mask;
170 }
171
172 // Returns true iff all bits set in mask are unset in this.value.
173 bool is_unset(uint mask) const {
174 assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
175 return (Atomic::load_acquire(&value) & (ShenandoahSharedValue) mask) == 0;
176 }
177
178 bool is_clear() const {
179 return (Atomic::load_acquire(&value)) == 0;
180 }
181
182 void set_cond(uint mask, bool val) {
183 if (val) {
184 set(mask);
185 } else {
186 unset(mask);
187 }
188 }
189
190 volatile ShenandoahSharedValue* addr_of() {
191 return &value;
192 }
193
194 ShenandoahSharedValue raw_value() const {
195 return value;
196 }
197
198 private:
199 volatile ShenandoahSharedValue* operator&() {
200 fatal("Use addr_of() instead");
201 return nullptr;
202 }
203
204 bool operator==(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
205 bool operator!=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
206 bool operator> (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
207 bool operator>=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
208 bool operator< (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
209 bool operator<=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
210
211 } ShenandoahSharedBitmap;
212
213 template<class T>
214 struct ShenandoahSharedEnumFlag {
215 typedef uint32_t EnumValueType;
216 shenandoah_padding(0);
217 volatile EnumValueType value;
218 shenandoah_padding(1);
219
220 ShenandoahSharedEnumFlag() {
221 value = 0;
222 }
223
224 void set(T v) {
225 assert (v >= 0, "sanity");
226 assert (v < (sizeof(EnumValueType) * CHAR_MAX), "sanity");
227 Atomic::release_store_fence(&value, (EnumValueType)v);
228 }
229
230 T get() const {
231 return (T)Atomic::load_acquire(&value);
232 }
233
234 T cmpxchg(T new_value, T expected) {
235 assert (new_value >= 0, "sanity");
236 assert (new_value < (sizeof(EnumValueType) * CHAR_MAX), "sanity");
237 return (T)Atomic::cmpxchg(&value, (EnumValueType)expected, (EnumValueType)new_value);
238 }
239
240 T xchg(T new_value) {
241 assert (new_value >= 0, "sanity");
242 assert (new_value < (sizeof(EnumValueType) * CHAR_MAX), "sanity");
243 return (T)Atomic::xchg(&value, (EnumValueType)new_value);
244 }
245
246 volatile EnumValueType* addr_of() {
247 return &value;
248 }
249
250 private:
251 volatile T* operator&() {
252 fatal("Use addr_of() instead");
253 return nullptr;
254 }
255
256 bool operator==(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
257 bool operator!=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
258 bool operator> (ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
259 bool operator>=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
260 bool operator< (ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
261 bool operator<=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
262
263 };
264
265 typedef struct ShenandoahSharedSemaphore {
266 shenandoah_padding(0);
267 volatile ShenandoahSharedValue value;
268 shenandoah_padding(1);
269
270 static uint max_tokens() {
271 return sizeof(ShenandoahSharedValue) * CHAR_MAX;
272 }
273
274 ShenandoahSharedSemaphore(uint tokens) {
275 assert(tokens <= max_tokens(), "sanity");
276 Atomic::release_store_fence(&value, (ShenandoahSharedValue)tokens);
277 }
278
279 bool try_acquire() {
280 while (true) {
281 ShenandoahSharedValue ov = Atomic::load_acquire(&value);
282 if (ov == 0) {
283 return false;
284 }
285 ShenandoahSharedValue nv = ov - 1;
286 if (Atomic::cmpxchg(&value, ov, nv) == ov) {
287 // successfully set
288 return true;
289 }
290 }
291 }
292
293 void claim_all() {
294 Atomic::release_store_fence(&value, (ShenandoahSharedValue)0);
295 }
296
297 } ShenandoahSharedSemaphore;
298
299 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHSHAREDVARIABLES_HPP