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 }