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 for (;;) { 166 long current = get(obj); 167 if (compareAndSet(obj, current, newValue)) 168 return current; 169 } 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 for (;;) { 181 long current = get(obj); 182 long next = current + 1; 183 if (compareAndSet(obj, current, next)) 184 return current; 185 } 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 for (;;) { 197 long current = get(obj); 198 long next = current - 1; 199 if (compareAndSet(obj, current, next)) 200 return current; 201 } 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 for (;;) { 214 long current = get(obj); 215 long next = current + delta; 216 if (compareAndSet(obj, current, next)) 217 return current; 218 } 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 for (;;) { 230 long current = get(obj); 231 long next = current + 1; 232 if (compareAndSet(obj, current, next)) 233 return next; 234 } 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 for (;;) { 246 long current = get(obj); 247 long next = current - 1; 248 if (compareAndSet(obj, current, next)) 249 return next; 250 } 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 for (;;) { 263 long current = get(obj); 264 long next = current + delta; 265 if (compareAndSet(obj, current, next)) 266 return next; 267 } 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 private void ensureProtectedAccess(T obj) { 349 if (cclass.isInstance(obj)) { 350 return; 351 } 352 throw new RuntimeException( 353 new IllegalAccessException("Class " + 354 cclass.getName() + 355 " can not access a protected member of class " + 356 tclass.getName() + 357 " using an instance of " + 358 obj.getClass().getName() 359 ) 360 ); 361 } 362 } 363 364 365 private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> { 366 private static final Unsafe unsafe = Unsafe.getUnsafe(); 367 private final long offset; 368 private final Class<T> tclass; 369 private final Class<?> cclass; 370 371 LockedUpdater(final Class<T> tclass, final String fieldName) { 372 Field field = null; 373 Class<?> caller = null; 374 int modifiers = 0; 375 try { 376 field = AccessController.doPrivileged( 377 new PrivilegedExceptionAction<Field>() { 378 public Field run() throws NoSuchFieldException { 379 return tclass.getDeclaredField(fieldName); 380 } 381 }); 382 caller = sun.reflect.Reflection.getCallerClass(3); 383 modifiers = field.getModifiers(); 384 sun.reflect.misc.ReflectUtil.ensureMemberAccess( 385 caller, tclass, null, modifiers); 386 ClassLoader cl = tclass.getClassLoader(); 387 ClassLoader ccl = caller.getClassLoader(); 388 if ((ccl != null) && (ccl != cl) && 389 ((cl == null) || !isAncestor(cl, ccl))) { 390 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); 391 } 392 } catch (PrivilegedActionException pae) { 393 throw new RuntimeException(pae.getException()); 394 } catch (Exception ex) { 395 throw new RuntimeException(ex); 396 } 397 398 Class<?> fieldt = field.getType(); 399 if (fieldt != long.class) 400 throw new IllegalArgumentException("Must be long type"); 401 402 if (!Modifier.isVolatile(modifiers)) 403 throw new IllegalArgumentException("Must be volatile type"); 404 405 this.cclass = (Modifier.isProtected(modifiers) && 406 caller != tclass) ? caller : null; 407 this.tclass = tclass; 408 offset = unsafe.objectFieldOffset(field); 409 } 410 411 private void fullCheck(T obj) { 412 if (!tclass.isInstance(obj)) 413 throw new ClassCastException(); 414 if (cclass != null) 415 ensureProtectedAccess(obj); 416 } 417 418 public boolean compareAndSet(T obj, long expect, long update) { 419 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 420 synchronized (this) { 421 long v = unsafe.getLong(obj, offset); 422 if (v != expect) 423 return false; 424 unsafe.putLong(obj, offset, update); 425 return true; 426 } 427 } 428 429 public boolean weakCompareAndSet(T obj, long expect, long update) { 430 return compareAndSet(obj, expect, update); 431 } 432 433 public void set(T obj, long newValue) { 434 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 435 synchronized (this) { 436 unsafe.putLong(obj, offset, newValue); 437 } 438 } 439 440 public void lazySet(T obj, long newValue) { 441 set(obj, newValue); 442 } 443 444 public long get(T obj) { 445 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 446 synchronized (this) { 447 return unsafe.getLong(obj, offset); 448 } 449 } 450 451 private void ensureProtectedAccess(T obj) { 452 if (cclass.isInstance(obj)) { 453 return; 454 } 455 throw new RuntimeException( 456 new IllegalAccessException("Class " + 457 cclass.getName() + 458 " can not access a protected member of class " + 459 tclass.getName() + 460 " using an instance of " + 461 obj.getClass().getName() 462 ) 463 ); 464 } 465 } 466 467 /** 468 * Returns true if the second classloader can be found in the first 469 * classloader's delegation chain. 470 * Equivalent to the inaccessible: first.isAncestor(second). 471 */ 472 private static boolean isAncestor(ClassLoader first, ClassLoader second) { 473 ClassLoader acl = first; 474 do { 475 acl = acl.getParent(); 476 if (second == acl) { 477 return true; 478 } 479 } while (acl != null); 480 return false; 481 } 482 } --- EOF ---