1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 /* 26 * This file is available under and governed by the GNU General Public 27 * License version 2 only, as published by the Free Software Foundation. 28 * However, the following notice accompanied the original version of this 29 * file: 30 * 31 * Written by Doug Lea with assistance from members of JCP JSR-166 32 * Expert Group and released to the public domain, as explained at 33 * http://creativecommons.org/publicdomain/zero/1.0/ 34 */ 35 36 package java.util.concurrent.atomic; 37 import sun.misc.Unsafe; 38 import java.lang.reflect.Field; 39 import java.lang.reflect.Modifier; 40 import java.security.AccessController; 41 import java.security.PrivilegedExceptionAction; 42 import java.security.PrivilegedActionException; 43 44 /** 45 * A reflection-based utility that enables atomic updates to 46 * designated {@code volatile long} fields of designated classes. 47 * This class is designed for use in atomic data structures in which 48 * several fields of the same node are independently subject to atomic 49 * updates. 50 * 51 * <p>Note that the guarantees of the {@code compareAndSet} 52 * method in this class are weaker than in other atomic classes. 53 * Because this class cannot ensure that all uses of the field 54 * are appropriate for purposes of atomic access, it can 55 * guarantee atomicity only with respect to other invocations of 56 * {@code compareAndSet} and {@code set} on the same updater. 57 * 58 * @since 1.5 59 * @author Doug Lea 60 * @param <T> The type of the object holding the updatable field 61 */ 62 public abstract class AtomicLongFieldUpdater<T> { 63 /** 64 * Creates and returns an updater for objects with the given field. 65 * The Class argument is needed to check that reflective types and 66 * generic types match. 67 * 68 * @param tclass the class of the objects holding the field 69 * @param fieldName the name of the field to be updated. 70 * @return the updater 71 * @throws IllegalArgumentException if the field is not a 72 * volatile long type. 73 * @throws RuntimeException with a nested reflection-based 74 * exception if the class does not hold field or is the wrong type, 75 * or the field is inaccessible to the caller according to Java language 76 * access control 77 */ 78 public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { 79 if (AtomicLong.VM_SUPPORTS_LONG_CAS) 80 return new CASUpdater<U>(tclass, fieldName); 81 else 82 return new LockedUpdater<U>(tclass, fieldName); 83 } 84 85 /** 86 * Protected do-nothing constructor for use by subclasses. 87 */ 88 protected AtomicLongFieldUpdater() { 89 } 90 91 /** 92 * Atomically sets the field of the given object managed by this updater 93 * to the given updated value if the current value {@code ==} the 94 * expected value. This method is guaranteed to be atomic with respect to 95 * other calls to {@code compareAndSet} and {@code set}, but not 96 * necessarily with respect to other changes in the field. 97 * 98 * @param obj An object whose field to conditionally set 99 * @param expect the expected value 100 * @param update the new value 101 * @return true if successful 102 * @throws ClassCastException if {@code obj} is not an instance 103 * of the class possessing the field established in the constructor. 104 */ 105 public abstract boolean compareAndSet(T obj, long expect, long update); 106 107 /** 108 * Atomically sets the field of the given object managed by this updater 109 * to the given updated value if the current value {@code ==} the 110 * expected value. This method is guaranteed to be atomic with respect to 111 * other calls to {@code compareAndSet} and {@code set}, but not 112 * necessarily with respect to other changes in the field. 113 * 114 * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> 115 * and does not provide ordering guarantees, so is only rarely an 116 * appropriate alternative to {@code compareAndSet}. 117 * 118 * @param obj An object whose field to conditionally set 119 * @param expect the expected value 120 * @param update the new value 121 * @return true if successful 122 * @throws ClassCastException if {@code obj} is not an instance 123 * of the class possessing the field established in the constructor. 124 */ 125 public abstract boolean weakCompareAndSet(T obj, long expect, long update); 126 127 /** 128 * Sets the field of the given object managed by this updater to the 129 * given updated value. This operation is guaranteed to act as a volatile 130 * store with respect to subsequent invocations of {@code compareAndSet}. 131 * 132 * @param obj An object whose field to set 133 * @param newValue the new value 134 */ 135 public abstract void set(T obj, long newValue); 136 137 /** 138 * Eventually sets the field of the given object managed by this 139 * updater to the given updated value. 140 * 141 * @param obj An object whose field to set 142 * @param newValue the new value 143 * @since 1.6 144 */ 145 public abstract void lazySet(T obj, long newValue); 146 147 /** 148 * Gets the current value held in the field of the given object managed 149 * by this updater. 150 * 151 * @param obj An object whose field to get 152 * @return the current value 153 */ 154 public abstract long get(T obj); 155 156 /** 157 * Atomically sets the field of the given object managed by this updater 158 * to the given value and returns the old value. 159 * 160 * @param obj An object whose field to get and set 161 * @param newValue the new value 162 * @return the previous value 163 */ 164 public long getAndSet(T obj, long newValue) { 165 long prev; 166 do { 167 prev = get(obj); 168 } while (!compareAndSet(obj, prev, newValue)); 169 return prev; 170 } 171 172 /** 173 * Atomically increments by one the current value of the field of the 174 * given object managed by this updater. 175 * 176 * @param obj An object whose field to get and set 177 * @return the previous value 178 */ 179 public long getAndIncrement(T obj) { 180 long prev, next; 181 do { 182 prev = get(obj); 183 next = prev + 1; 184 } while (!compareAndSet(obj, prev, next)); 185 return prev; 186 } 187 188 /** 189 * Atomically decrements 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 previous value 194 */ 195 public long getAndDecrement(T obj) { 196 long prev, next; 197 do { 198 prev = get(obj); 199 next = prev - 1; 200 } while (!compareAndSet(obj, prev, next)); 201 return prev; 202 } 203 204 /** 205 * Atomically adds the given value to the current value of the field of 206 * the given object managed by this updater. 207 * 208 * @param obj An object whose field to get and set 209 * @param delta the value to add 210 * @return the previous value 211 */ 212 public long getAndAdd(T obj, long delta) { 213 long prev, next; 214 do { 215 prev = get(obj); 216 next = prev + delta; 217 } while (!compareAndSet(obj, prev, next)); 218 return prev; 219 } 220 221 /** 222 * Atomically increments by one the current value of the field of the 223 * given object managed by this updater. 224 * 225 * @param obj An object whose field to get and set 226 * @return the updated value 227 */ 228 public long incrementAndGet(T obj) { 229 long prev, next; 230 do { 231 prev = get(obj); 232 next = prev + 1; 233 } while (!compareAndSet(obj, prev, next)); 234 return next; 235 } 236 237 /** 238 * Atomically decrements by one the current value of the field of the 239 * given object managed by this updater. 240 * 241 * @param obj An object whose field to get and set 242 * @return the updated value 243 */ 244 public long decrementAndGet(T obj) { 245 long prev, next; 246 do { 247 prev = get(obj); 248 next = prev - 1; 249 } while (!compareAndSet(obj, prev, next)); 250 return next; 251 } 252 253 /** 254 * Atomically adds the given value to the current value of the field of 255 * the given object managed by this updater. 256 * 257 * @param obj An object whose field to get and set 258 * @param delta the value to add 259 * @return the updated value 260 */ 261 public long addAndGet(T obj, long delta) { 262 long prev, next; 263 do { 264 prev = get(obj); 265 next = prev + delta; 266 } while (!compareAndSet(obj, prev, next)); 267 return next; 268 } 269 270 private static class CASUpdater<T> extends AtomicLongFieldUpdater<T> { 271 private static final Unsafe unsafe = Unsafe.getUnsafe(); 272 private final long offset; 273 private final Class<T> tclass; 274 private final Class<?> cclass; 275 276 CASUpdater(final Class<T> tclass, final String fieldName) { 277 final Field field; 278 final Class<?> caller; 279 final int modifiers; 280 try { 281 field = AccessController.doPrivileged( 282 new PrivilegedExceptionAction<Field>() { 283 public Field run() throws NoSuchFieldException { 284 return tclass.getDeclaredField(fieldName); 285 } 286 }); 287 caller = sun.reflect.Reflection.getCallerClass(3); 288 modifiers = field.getModifiers(); 289 sun.reflect.misc.ReflectUtil.ensureMemberAccess( 290 caller, tclass, null, modifiers); 291 ClassLoader cl = tclass.getClassLoader(); 292 ClassLoader ccl = caller.getClassLoader(); 293 if ((ccl != null) && (ccl != cl) && 294 ((cl == null) || !isAncestor(cl, ccl))) { 295 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); 296 } 297 } catch (PrivilegedActionException pae) { 298 throw new RuntimeException(pae.getException()); 299 } catch (Exception ex) { 300 throw new RuntimeException(ex); 301 } 302 303 Class<?> fieldt = field.getType(); 304 if (fieldt != long.class) 305 throw new IllegalArgumentException("Must be long type"); 306 307 if (!Modifier.isVolatile(modifiers)) 308 throw new IllegalArgumentException("Must be volatile type"); 309 310 this.cclass = (Modifier.isProtected(modifiers) && 311 caller != tclass) ? caller : null; 312 this.tclass = tclass; 313 offset = unsafe.objectFieldOffset(field); 314 } 315 316 private void fullCheck(T obj) { 317 if (!tclass.isInstance(obj)) 318 throw new ClassCastException(); 319 if (cclass != null) 320 ensureProtectedAccess(obj); 321 } 322 323 public boolean compareAndSet(T obj, long expect, long update) { 324 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 325 return unsafe.compareAndSwapLong(obj, offset, expect, update); 326 } 327 328 public boolean weakCompareAndSet(T obj, long expect, long update) { 329 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 330 return unsafe.compareAndSwapLong(obj, offset, expect, update); 331 } 332 333 public void set(T obj, long newValue) { 334 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 335 unsafe.putLongVolatile(obj, offset, newValue); 336 } 337 338 public void lazySet(T obj, long newValue) { 339 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 340 unsafe.putOrderedLong(obj, offset, newValue); 341 } 342 343 public long get(T obj) { 344 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 345 return unsafe.getLongVolatile(obj, offset); 346 } 347 348 public long getAndSet(T obj, long newValue) { 349 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 350 return unsafe.getAndSetLong(obj, offset, newValue); 351 } 352 353 public long getAndIncrement(T obj) { 354 return getAndAdd(obj, 1); 355 } 356 357 public long getAndDecrement(T obj) { 358 return getAndAdd(obj, -1); 359 } 360 361 public long getAndAdd(T obj, long delta) { 362 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 363 return unsafe.getAndAddLong(obj, offset, delta); 364 } 365 366 public long incrementAndGet(T obj) { 367 return getAndAdd(obj, 1) + 1; 368 } 369 370 public long decrementAndGet(T obj) { 371 return getAndAdd(obj, -1) - 1; 372 } 373 374 public long addAndGet(T obj, long delta) { 375 return getAndAdd(obj, delta) + delta; 376 } 377 378 private void ensureProtectedAccess(T obj) { 379 if (cclass.isInstance(obj)) { 380 return; 381 } 382 throw new RuntimeException( 383 new IllegalAccessException("Class " + 384 cclass.getName() + 385 " can not access a protected member of class " + 386 tclass.getName() + 387 " using an instance of " + 388 obj.getClass().getName() 389 ) 390 ); 391 } 392 } 393 394 395 private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> { 396 private static final Unsafe unsafe = Unsafe.getUnsafe(); 397 private final long offset; 398 private final Class<T> tclass; 399 private final Class<?> cclass; 400 401 LockedUpdater(final Class<T> tclass, final String fieldName) { 402 Field field = null; 403 Class<?> caller = null; 404 int modifiers = 0; 405 try { 406 field = AccessController.doPrivileged( 407 new PrivilegedExceptionAction<Field>() { 408 public Field run() throws NoSuchFieldException { 409 return tclass.getDeclaredField(fieldName); 410 } 411 }); 412 caller = sun.reflect.Reflection.getCallerClass(3); 413 modifiers = field.getModifiers(); 414 sun.reflect.misc.ReflectUtil.ensureMemberAccess( 415 caller, tclass, null, modifiers); 416 ClassLoader cl = tclass.getClassLoader(); 417 ClassLoader ccl = caller.getClassLoader(); 418 if ((ccl != null) && (ccl != cl) && 419 ((cl == null) || !isAncestor(cl, ccl))) { 420 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); 421 } 422 } catch (PrivilegedActionException pae) { 423 throw new RuntimeException(pae.getException()); 424 } catch (Exception ex) { 425 throw new RuntimeException(ex); 426 } 427 428 Class<?> fieldt = field.getType(); 429 if (fieldt != long.class) 430 throw new IllegalArgumentException("Must be long type"); 431 432 if (!Modifier.isVolatile(modifiers)) 433 throw new IllegalArgumentException("Must be volatile type"); 434 435 this.cclass = (Modifier.isProtected(modifiers) && 436 caller != tclass) ? caller : null; 437 this.tclass = tclass; 438 offset = unsafe.objectFieldOffset(field); 439 } 440 441 private void fullCheck(T obj) { 442 if (!tclass.isInstance(obj)) 443 throw new ClassCastException(); 444 if (cclass != null) 445 ensureProtectedAccess(obj); 446 } 447 448 public boolean compareAndSet(T obj, long expect, long update) { 449 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 450 synchronized (this) { 451 long v = unsafe.getLong(obj, offset); 452 if (v != expect) 453 return false; 454 unsafe.putLong(obj, offset, update); 455 return true; 456 } 457 } 458 459 public boolean weakCompareAndSet(T obj, long expect, long update) { 460 return compareAndSet(obj, expect, update); 461 } 462 463 public void set(T obj, long newValue) { 464 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 465 synchronized (this) { 466 unsafe.putLong(obj, offset, newValue); 467 } 468 } 469 470 public void lazySet(T obj, long newValue) { 471 set(obj, newValue); 472 } 473 474 public long get(T obj) { 475 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 476 synchronized (this) { 477 return unsafe.getLong(obj, offset); 478 } 479 } 480 481 private void ensureProtectedAccess(T obj) { 482 if (cclass.isInstance(obj)) { 483 return; 484 } 485 throw new RuntimeException( 486 new IllegalAccessException("Class " + 487 cclass.getName() + 488 " can not access a protected member of class " + 489 tclass.getName() + 490 " using an instance of " + 491 obj.getClass().getName() 492 ) 493 ); 494 } 495 } 496 497 /** 498 * Returns true if the second classloader can be found in the first 499 * classloader's delegation chain. 500 * Equivalent to the inaccessible: first.isAncestor(second). 501 */ 502 private static boolean isAncestor(ClassLoader first, ClassLoader second) { 503 ClassLoader acl = first; 504 do { 505 acl = acl.getParent(); 506 if (second == acl) { 507 return true; 508 } 509 } while (acl != null); 510 return false; 511 } 512 }