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