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