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   shenandoah_padding(0);
216   volatile ShenandoahSharedValue value;
217   shenandoah_padding(1);
218 
219   ShenandoahSharedEnumFlag() {
220     value = 0;
221   }
222 
223   void set(T v) {
224     assert (v >= 0, "sanity");
225     assert (v < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
226     Atomic::release_store_fence(&value, (ShenandoahSharedValue)v);
227   }
228 
229   T get() const {
230     return (T)Atomic::load_acquire(&value);
231   }
232 
233   T cmpxchg(T new_value, T expected) {
234     assert (new_value >= 0, "sanity");
235     assert (new_value < (sizeof(ShenandoahSharedValue) * CHAR_MAX), "sanity");
236     return (T)Atomic::cmpxchg(&value, (ShenandoahSharedValue)expected, (ShenandoahSharedValue)new_value);
237   }
238 
239   volatile ShenandoahSharedValue* addr_of() {
240     return &value;
241   }
242 
243 private:
244   volatile T* operator&() {
245     fatal("Use addr_of() instead");
246     return nullptr;
247   }
248 
249   bool operator==(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
250   bool operator!=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
251   bool operator> (ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
252   bool operator>=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
253   bool operator< (ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
254   bool operator<=(ShenandoahSharedEnumFlag& other) { fatal("Use get() instead"); return false; }
255 
256 };
257 
258 typedef struct ShenandoahSharedSemaphore {
259   shenandoah_padding(0);
260   volatile ShenandoahSharedValue value;
261   shenandoah_padding(1);
262 
263   static uint max_tokens() {
264     return sizeof(ShenandoahSharedValue) * CHAR_MAX;
265   }
266 
267   ShenandoahSharedSemaphore(uint tokens) {
268     assert(tokens <= max_tokens(), "sanity");
269     Atomic::release_store_fence(&value, (ShenandoahSharedValue)tokens);
270   }
271 
272   bool try_acquire() {
273     while (true) {
274       ShenandoahSharedValue ov = Atomic::load_acquire(&value);
275       if (ov == 0) {
276         return false;
277       }
278       ShenandoahSharedValue nv = ov - 1;
279       if (Atomic::cmpxchg(&value, ov, nv) == ov) {
280         // successfully set
281         return true;
282       }
283     }
284   }
285 
286   void claim_all() {
287     Atomic::release_store_fence(&value, (ShenandoahSharedValue)0);
288   }
289 
290 } ShenandoahSharedSemaphore;
291 
292 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHSHAREDVARIABLES_HPP