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 }