1 /* 2 * Written by Doug Lea with assistance from members of JCP JSR-166 3 * Expert Group and released to the public domain, as explained at 4 * http://creativecommons.org/publicdomain/zero/1.0/ 5 */ 6 7 package java.util.concurrent.atomic; 8 9 import dalvik.system.VMStack; // android-added 10 import sun.misc.Unsafe; 11 import java.lang.reflect.*; 12 13 /** 14 * A reflection-based utility that enables atomic updates to 15 * designated {@code volatile long} fields of designated classes. 16 * This class is designed for use in atomic data structures in which 17 * several fields of the same node are independently subject to atomic 18 * updates. 19 * 20 * <p>Note that the guarantees of the {@code compareAndSet} 21 * method in this class are weaker than in other atomic classes. 22 * Because this class cannot ensure that all uses of the field 23 * are appropriate for purposes of atomic access, it can 24 * guarantee atomicity only with respect to other invocations of 25 * {@code compareAndSet} and {@code set} on the same updater. 26 * 27 * @since 1.5 28 * @author Doug Lea 29 * @param <T> The type of the object holding the updatable field 30 */ 31 public abstract class AtomicLongFieldUpdater<T> { 32 /** 33 * Creates and returns an updater for objects with the given field. 34 * The Class argument is needed to check that reflective types and 35 * generic types match. 36 * 37 * @param tclass the class of the objects holding the field 38 * @param fieldName the name of the field to be updated. 39 * @return the updater 40 * @throws IllegalArgumentException if the field is not a 41 * volatile long type. 42 * @throws RuntimeException with a nested reflection-based 43 * exception if the class does not hold field or is the wrong type. 44 */ 45 public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { 46 if (AtomicLong.VM_SUPPORTS_LONG_CAS) 47 return new CASUpdater<U>(tclass, fieldName); 48 else 49 return new LockedUpdater<U>(tclass, fieldName); 50 } 51 52 /** 53 * Protected do-nothing constructor for use by subclasses. 54 */ 55 protected AtomicLongFieldUpdater() { 56 } 57 58 /** 59 * Atomically sets the field of the given object managed by this updater 60 * to the given updated value if the current value {@code ==} the 61 * expected value. This method is guaranteed to be atomic with respect to 62 * other calls to {@code compareAndSet} and {@code set}, but not 63 * necessarily with respect to other changes in the field. 64 * 65 * @param obj An object whose field to conditionally set 66 * @param expect the expected value 67 * @param update the new value 68 * @return true if successful. 69 * @throws ClassCastException if {@code obj} is not an instance 70 * of the class possessing the field established in the constructor. 71 */ 72 public abstract boolean compareAndSet(T obj, long expect, long update); 73 74 /** 75 * Atomically sets the field of the given object managed by this updater 76 * to the given updated value if the current value {@code ==} the 77 * expected value. This method is guaranteed to be atomic with respect to 78 * other calls to {@code compareAndSet} and {@code set}, but not 79 * necessarily with respect to other changes in the field. 80 * 81 * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> 82 * and does not provide ordering guarantees, so is only rarely an 83 * appropriate alternative to {@code compareAndSet}. 84 * 85 * @param obj An object whose field to conditionally set 86 * @param expect the expected value 87 * @param update the new value 88 * @return true if successful. 89 * @throws ClassCastException if {@code obj} is not an instance 90 * of the class possessing the field established in the constructor. 91 */ 92 public abstract boolean weakCompareAndSet(T obj, long expect, long update); 93 94 /** 95 * Sets the field of the given object managed by this updater to the 96 * given updated value. This operation is guaranteed to act as a volatile 97 * store with respect to subsequent invocations of {@code compareAndSet}. 98 * 99 * @param obj An object whose field to set 100 * @param newValue the new value 101 */ 102 public abstract void set(T obj, long newValue); 103 104 /** 105 * Eventually sets the field of the given object managed by this 106 * updater to the given updated value. 107 * 108 * @param obj An object whose field to set 109 * @param newValue the new value 110 * @since 1.6 111 */ 112 public abstract void lazySet(T obj, long newValue); 113 114 /** 115 * Gets the current value held in the field of the given object managed 116 * by this updater. 117 * 118 * @param obj An object whose field to get 119 * @return the current value 120 */ 121 public abstract long get(T obj); 122 123 /** 124 * Atomically sets the field of the given object managed by this updater 125 * to the given value and returns the old value. 126 * 127 * @param obj An object whose field to get and set 128 * @param newValue the new value 129 * @return the previous value 130 */ 131 public long getAndSet(T obj, long newValue) { 132 for (;;) { 133 long current = get(obj); 134 if (compareAndSet(obj, current, newValue)) 135 return current; 136 } 137 } 138 139 /** 140 * Atomically increments by one the current value of the field of the 141 * given object managed by this updater. 142 * 143 * @param obj An object whose field to get and set 144 * @return the previous value 145 */ 146 public long getAndIncrement(T obj) { 147 for (;;) { 148 long current = get(obj); 149 long next = current + 1; 150 if (compareAndSet(obj, current, next)) 151 return current; 152 } 153 } 154 155 /** 156 * Atomically decrements by one the current value of the field of the 157 * given object managed by this updater. 158 * 159 * @param obj An object whose field to get and set 160 * @return the previous value 161 */ 162 public long getAndDecrement(T obj) { 163 for (;;) { 164 long current = get(obj); 165 long next = current - 1; 166 if (compareAndSet(obj, current, next)) 167 return current; 168 } 169 } 170 171 /** 172 * Atomically adds the given value to the current value of the field of 173 * the given object managed by this updater. 174 * 175 * @param obj An object whose field to get and set 176 * @param delta the value to add 177 * @return the previous value 178 */ 179 public long getAndAdd(T obj, long delta) { 180 for (;;) { 181 long current = get(obj); 182 long next = current + delta; 183 if (compareAndSet(obj, current, next)) 184 return current; 185 } 186 } 187 188 /** 189 * Atomically increments by one the current value of the field of the 190 * given object managed by this updater. 191 * 192 * @param obj An object whose field to get and set 193 * @return the updated value 194 */ 195 public long incrementAndGet(T obj) { 196 for (;;) { 197 long current = get(obj); 198 long next = current + 1; 199 if (compareAndSet(obj, current, next)) 200 return next; 201 } 202 } 203 204 /** 205 * Atomically decrements by one the current value of the field of the 206 * given object managed by this updater. 207 * 208 * @param obj An object whose field to get and set 209 * @return the updated value 210 */ 211 public long decrementAndGet(T obj) { 212 for (;;) { 213 long current = get(obj); 214 long next = current - 1; 215 if (compareAndSet(obj, current, next)) 216 return next; 217 } 218 } 219 220 /** 221 * Atomically adds the given value to the current value of the field of 222 * the given object managed by this updater. 223 * 224 * @param obj An object whose field to get and set 225 * @param delta the value to add 226 * @return the updated value 227 */ 228 public long addAndGet(T obj, long delta) { 229 for (;;) { 230 long current = get(obj); 231 long next = current + delta; 232 if (compareAndSet(obj, current, next)) 233 return next; 234 } 235 } 236 237 private static class CASUpdater<T> extends AtomicLongFieldUpdater<T> { 238 private static final Unsafe unsafe = Unsafe.getUnsafe(); 239 private final long offset; 240 private final Class<T> tclass; 241 private final Class<?> cclass; 242 243 CASUpdater(Class<T> tclass, String fieldName) { 244 Field field = null; 245 Class<?> caller = null; 246 int modifiers = 0; 247 try { 248 field = tclass.getDeclaredField(fieldName); 249 caller = VMStack.getStackClass2(); // android-changed 250 modifiers = field.getModifiers(); 251 // BEGIN android-removed 252 // sun.reflect.misc.ReflectUtil.ensureMemberAccess( 253 // caller, tclass, null, modifiers); 254 // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); 255 // END android-removed 256 } catch (Exception ex) { 257 throw new RuntimeException(ex); 258 } 259 260 Class<?> fieldt = field.getType(); 261 if (fieldt != long.class) 262 throw new IllegalArgumentException("Must be long type"); 263 264 if (!Modifier.isVolatile(modifiers)) 265 throw new IllegalArgumentException("Must be volatile type"); 266 267 this.cclass = (Modifier.isProtected(modifiers) && 268 caller != tclass) ? caller : null; 269 this.tclass = tclass; 270 offset = unsafe.objectFieldOffset(field); 271 } 272 273 private void fullCheck(T obj) { 274 if (!tclass.isInstance(obj)) 275 throw new ClassCastException(); 276 if (cclass != null) 277 ensureProtectedAccess(obj); 278 } 279 280 public boolean compareAndSet(T obj, long expect, long update) { 281 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 282 return unsafe.compareAndSwapLong(obj, offset, expect, update); 283 } 284 285 public boolean weakCompareAndSet(T obj, long expect, long update) { 286 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 287 return unsafe.compareAndSwapLong(obj, offset, expect, update); 288 } 289 290 public void set(T obj, long newValue) { 291 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 292 unsafe.putLongVolatile(obj, offset, newValue); 293 } 294 295 public void lazySet(T obj, long newValue) { 296 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 297 unsafe.putOrderedLong(obj, offset, newValue); 298 } 299 300 public long get(T obj) { 301 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 302 return unsafe.getLongVolatile(obj, offset); 303 } 304 305 private void ensureProtectedAccess(T obj) { 306 if (cclass.isInstance(obj)) { 307 return; 308 } 309 throw new RuntimeException( 310 new IllegalAccessException("Class " + 311 cclass.getName() + 312 " can not access a protected member of class " + 313 tclass.getName() + 314 " using an instance of " + 315 obj.getClass().getName() 316 ) 317 ); 318 } 319 } 320 321 322 private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> { 323 private static final Unsafe unsafe = Unsafe.getUnsafe(); 324 private final long offset; 325 private final Class<T> tclass; 326 private final Class<?> cclass; 327 328 LockedUpdater(Class<T> tclass, String fieldName) { 329 Field field = null; 330 Class<?> caller = null; 331 int modifiers = 0; 332 try { 333 field = tclass.getDeclaredField(fieldName); 334 caller = VMStack.getStackClass2(); // android-changed 335 modifiers = field.getModifiers(); 336 // BEGIN android-removed 337 // sun.reflect.misc.ReflectUtil.ensureMemberAccess( 338 // caller, tclass, null, modifiers); 339 // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); 340 // END android-removed 341 } catch (Exception ex) { 342 throw new RuntimeException(ex); 343 } 344 345 Class<?> fieldt = field.getType(); 346 if (fieldt != long.class) 347 throw new IllegalArgumentException("Must be long type"); 348 349 if (!Modifier.isVolatile(modifiers)) 350 throw new IllegalArgumentException("Must be volatile type"); 351 352 this.cclass = (Modifier.isProtected(modifiers) && 353 caller != tclass) ? caller : null; 354 this.tclass = tclass; 355 offset = unsafe.objectFieldOffset(field); 356 } 357 358 private void fullCheck(T obj) { 359 if (!tclass.isInstance(obj)) 360 throw new ClassCastException(); 361 if (cclass != null) 362 ensureProtectedAccess(obj); 363 } 364 365 public boolean compareAndSet(T obj, long expect, long update) { 366 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 367 synchronized (this) { 368 long v = unsafe.getLong(obj, offset); 369 if (v != expect) 370 return false; 371 unsafe.putLong(obj, offset, update); 372 return true; 373 } 374 } 375 376 public boolean weakCompareAndSet(T obj, long expect, long update) { 377 return compareAndSet(obj, expect, update); 378 } 379 380 public void set(T obj, long newValue) { 381 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 382 synchronized (this) { 383 unsafe.putLong(obj, offset, newValue); 384 } 385 } 386 387 public void lazySet(T obj, long newValue) { 388 set(obj, newValue); 389 } 390 391 public long get(T obj) { 392 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 393 synchronized (this) { 394 return unsafe.getLong(obj, offset); 395 } 396 } 397 398 private void ensureProtectedAccess(T obj) { 399 if (cclass.isInstance(obj)) { 400 return; 401 } 402 throw new RuntimeException( 403 new IllegalAccessException("Class " + 404 cclass.getName() + 405 " can not access a protected member of class " + 406 tclass.getName() + 407 " using an instance of " + 408 obj.getClass().getName() 409 ) 410 ); 411 } 412 } 413 } 414