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