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