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 if ((ov & mask_val) != 0) {
125 // already set
126 return;
127 }
128
129 ShenandoahSharedValue nv = ov | mask_val;
130 if (Atomic::cmpxchg(&value, ov, nv) == ov) {
131 // successfully set
132 return;
133 }
134 }
135 }
136
137 void unset(uint mask) {
138 assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
139 ShenandoahSharedValue mask_val = (ShenandoahSharedValue) mask;
140 while (true) {
141 ShenandoahSharedValue ov = Atomic::load_acquire(&value);
142 if ((ov & mask_val) == 0) {
143 // already unset
144 return;
145 }
146
147 ShenandoahSharedValue nv = ov & ~mask_val;
148 if (Atomic::cmpxchg(&value, ov, nv) == ov) {
149 // successfully unset
150 return;
151 }
152 }
153 }
154
155 void clear() {
156 Atomic::release_store_fence(&value, (ShenandoahSharedValue)0);
157 }
158
159 bool is_set(uint mask) const {
160 return !is_unset(mask);
161 }
162
163 bool is_unset(uint mask) const {
164 assert (mask < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
165 return (Atomic::load_acquire(&value) & (ShenandoahSharedValue) mask) == 0;
166 }
167
168 bool is_clear() const {
169 return (Atomic::load_acquire(&value)) == 0;
170 }
171
172 void set_cond(uint mask, bool val) {
173 if (val) {
174 set(mask);
175 } else {
176 unset(mask);
177 }
178 }
179
180 volatile ShenandoahSharedValue* addr_of() {
181 return &value;
182 }
183
184 ShenandoahSharedValue raw_value() const {
185 return value;
186 }
187
188 private:
189 volatile ShenandoahSharedValue* operator&() {
190 fatal("Use addr_of() instead");
191 return nullptr;
192 }
193
194 bool operator==(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
195 bool operator!=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
196 bool operator> (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
197 bool operator>=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
198 bool operator< (ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
199 bool operator<=(ShenandoahSharedFlag& other) { fatal("Use is_set() instead"); return false; }
200
201 } ShenandoahSharedBitmap;
202
203 template<class T>
204 struct ShenandoahSharedEnumFlag {
205 shenandoah_padding(0);
206 volatile ShenandoahSharedValue value;
207 shenandoah_padding(1);
208
209 ShenandoahSharedEnumFlag() {
210 value = 0;
211 }
212
213 void set(T v) {
214 assert (v >= 0, "sanity");
215 assert (v < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
216 Atomic::release_store_fence(&value, (ShenandoahSharedValue)v);
217 }
218
219 T get() const {
220 return (T)Atomic::load_acquire(&value);
221 }
222
223 T cmpxchg(T new_value, T expected) {
224 assert (new_value >= 0, "sanity");
225 assert (new_value < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
226 return (T)Atomic::cmpxchg(&value, (ShenandoahSharedValue)expected, (ShenandoahSharedValue)new_value);
227 }
228
229 volatile ShenandoahSharedValue* addr_of() {
230 return &value;
231 }
232
233 private:
234 volatile T* operator&() {
235 fatal("Use addr_of() instead");
236 return nullptr;
237 }
238
239 bool operator==(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
240 bool operator!=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
241 bool operator> (ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
242 bool operator>=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
243 bool operator< (ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
244 bool operator<=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
245
246 };
247
248 typedef struct ShenandoahSharedSemaphore {
249 shenandoah_padding(0);
250 volatile ShenandoahSharedValue value;
251 shenandoah_padding(1);
252
253 static uint max_tokens() {
254 return sizeof(ShenandoahSharedValue) * CHAR_MAX;
255 }
256
257 ShenandoahSharedSemaphore(uint tokens) {
258 assert(tokens <= max_tokens(), "sanity");
259 Atomic::release_store_fence(&value, (ShenandoahSharedValue)tokens);
260 }
261
262 bool try_acquire() {
263 while (true) {
264 ShenandoahSharedValue ov = Atomic::load_acquire(&value);
265 if (ov == 0) {
266 return false;
267 }
268 ShenandoahSharedValue nv = ov - 1;
269 if (Atomic::cmpxchg(&value, ov, nv) == ov) {
270 // successfully set
271 return true;
272 }
273 }
274 }
275
276 void claim_all() {
277 Atomic::release_store_fence(&value, (ShenandoahSharedValue)0);
278 }
279
280 } ShenandoahSharedSemaphore;
281
282 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHSHAREDVARIABLES_HPP