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 int} 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 AtomicIntegerFieldUpdater<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 integer 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> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
  79         return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName);
  80     }
  81 
  82     /**
  83      * Protected do-nothing constructor for use by subclasses.
  84      */
  85     protected AtomicIntegerFieldUpdater() {
  86     }
  87 
  88     /**
  89      * Atomically sets the field of the given object managed by this updater
  90      * to the given updated value if the current value {@code ==} the
  91      * expected value. This method is guaranteed to be atomic with respect to
  92      * other calls to {@code compareAndSet} and {@code set}, but not
  93      * necessarily with respect to other changes in the field.
  94      *
  95      * @param obj An object whose field to conditionally set
  96      * @param expect the expected value
  97      * @param update the new value
  98      * @return true if successful
  99      * @throws ClassCastException if {@code obj} is not an instance
 100      * of the class possessing the field established in the constructor
 101      */
 102     public abstract boolean compareAndSet(T obj, int expect, int update);
 103 
 104     /**
 105      * Atomically sets the field of the given object managed by this updater
 106      * to the given updated value if the current value {@code ==} the
 107      * expected value. This method is guaranteed to be atomic with respect to
 108      * other calls to {@code compareAndSet} and {@code set}, but not
 109      * necessarily with respect to other changes in the field.
 110      *
 111      * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 112      * and does not provide ordering guarantees, so is only rarely an
 113      * appropriate alternative to {@code compareAndSet}.
 114      *
 115      * @param obj An object whose field to conditionally set
 116      * @param expect the expected value
 117      * @param update the new value
 118      * @return true if successful
 119      * @throws ClassCastException if {@code obj} is not an instance
 120      * of the class possessing the field established in the constructor
 121      */
 122     public abstract boolean weakCompareAndSet(T obj, int expect, int update);
 123 
 124     /**
 125      * Sets the field of the given object managed by this updater to the
 126      * given updated value. This operation is guaranteed to act as a volatile
 127      * store with respect to subsequent invocations of {@code compareAndSet}.
 128      *
 129      * @param obj An object whose field to set
 130      * @param newValue the new value
 131      */
 132     public abstract void set(T obj, int newValue);
 133 
 134     /**
 135      * Eventually sets the field of the given object managed by this
 136      * updater to the given updated value.
 137      *
 138      * @param obj An object whose field to set
 139      * @param newValue the new value
 140      * @since 1.6
 141      */
 142     public abstract void lazySet(T obj, int newValue);
 143 
 144     /**
 145      * Gets the current value held in the field of the given object managed
 146      * by this updater.
 147      *
 148      * @param obj An object whose field to get
 149      * @return the current value
 150      */
 151     public abstract int get(T obj);
 152 
 153     /**
 154      * Atomically sets the field of the given object managed by this updater
 155      * to the given value and returns the old value.
 156      *
 157      * @param obj An object whose field to get and set
 158      * @param newValue the new value
 159      * @return the previous value
 160      */
 161     public int getAndSet(T obj, int newValue) {
 162         for (;;) {
 163             int current = get(obj);
 164             if (compareAndSet(obj, current, newValue))
 165                 return current;
 166         }
 167     }
 168 
 169     /**
 170      * Atomically increments by one the current value of the field of the
 171      * given object managed by this updater.
 172      *
 173      * @param obj An object whose field to get and set
 174      * @return the previous value
 175      */
 176     public int getAndIncrement(T obj) {
 177         for (;;) {
 178             int current = get(obj);
 179             int next = current + 1;
 180             if (compareAndSet(obj, current, next))
 181                 return current;
 182         }
 183     }
 184 
 185     /**
 186      * Atomically decrements by one the current value of the field of the
 187      * given object managed by this updater.
 188      *
 189      * @param obj An object whose field to get and set
 190      * @return the previous value
 191      */
 192     public int getAndDecrement(T obj) {
 193         for (;;) {
 194             int current = get(obj);
 195             int next = current - 1;
 196             if (compareAndSet(obj, current, next))
 197                 return current;
 198         }
 199     }
 200 
 201     /**
 202      * Atomically adds the given value to the current value of the field of
 203      * the given object managed by this updater.
 204      *
 205      * @param obj An object whose field to get and set
 206      * @param delta the value to add
 207      * @return the previous value
 208      */
 209     public int getAndAdd(T obj, int delta) {
 210         for (;;) {
 211             int current = get(obj);
 212             int next = current + delta;
 213             if (compareAndSet(obj, current, next))
 214                 return current;
 215         }
 216     }
 217 
 218     /**
 219      * Atomically increments by one the current value of the field of the
 220      * given object managed by this updater.
 221      *
 222      * @param obj An object whose field to get and set
 223      * @return the updated value
 224      */
 225     public int incrementAndGet(T obj) {
 226         for (;;) {
 227             int current = get(obj);
 228             int next = current + 1;
 229             if (compareAndSet(obj, current, next))
 230                 return next;
 231         }
 232     }
 233 
 234     /**
 235      * Atomically decrements by one the current value of the field of the
 236      * given object managed by this updater.
 237      *
 238      * @param obj An object whose field to get and set
 239      * @return the updated value
 240      */
 241     public int decrementAndGet(T obj) {
 242         for (;;) {
 243             int current = get(obj);
 244             int next = current - 1;
 245             if (compareAndSet(obj, current, next))
 246                 return next;
 247         }
 248     }
 249 
 250     /**
 251      * Atomically adds the given value to the current value of the field of
 252      * the given object managed by this updater.
 253      *
 254      * @param obj An object whose field to get and set
 255      * @param delta the value to add
 256      * @return the updated value
 257      */
 258     public int addAndGet(T obj, int delta) {
 259         for (;;) {
 260             int current = get(obj);
 261             int next = current + delta;
 262             if (compareAndSet(obj, current, next))
 263                 return next;
 264         }
 265     }
 266 
 267     /**
 268      * Standard hotspot implementation using intrinsics
 269      */
 270     private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<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         AtomicIntegerFieldUpdaterImpl(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 != int.class)
 305                 throw new IllegalArgumentException("Must be integer 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         /**
 317          * Returns true if the second classloader can be found in the first
 318          * classloader's delegation chain.
 319          * Equivalent to the inaccessible: first.isAncestor(second).
 320          */
 321         private static boolean isAncestor(ClassLoader first, ClassLoader second) {
 322             ClassLoader acl = first;
 323             do {
 324                 acl = acl.getParent();
 325                 if (second == acl) {
 326                     return true;
 327                 }
 328             } while (acl != null);
 329             return false;
 330         }
 331 
 332         private void fullCheck(T obj) {
 333             if (!tclass.isInstance(obj))
 334                 throw new ClassCastException();
 335             if (cclass != null)
 336                 ensureProtectedAccess(obj);
 337         }
 338 
 339         public boolean compareAndSet(T obj, int expect, int update) {
 340             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 341             return unsafe.compareAndSwapInt(obj, offset, expect, update);
 342         }
 343 
 344         public boolean weakCompareAndSet(T obj, int expect, int update) {
 345             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 346             return unsafe.compareAndSwapInt(obj, offset, expect, update);
 347         }
 348 
 349         public void set(T obj, int newValue) {
 350             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 351             unsafe.putIntVolatile(obj, offset, newValue);
 352         }
 353 
 354         public void lazySet(T obj, int newValue) {
 355             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 356             unsafe.putOrderedInt(obj, offset, newValue);
 357         }
 358 
 359         public final int get(T obj) {
 360             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 361             return unsafe.getIntVolatile(obj, offset);
 362         }
 363 
 364         private void ensureProtectedAccess(T obj) {
 365             if (cclass.isInstance(obj)) {
 366                 return;
 367             }
 368             throw new RuntimeException(
 369                 new IllegalAccessException("Class " +
 370                     cclass.getName() +
 371                     " can not access a protected member of class " +
 372                     tclass.getName() +
 373                     " using an instance of " +
 374                     obj.getClass().getName()
 375                 )
 376             );
 377         }
 378     }
 379 }