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