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} reference fields of designated
  47  * classes.  This class is designed for use in atomic data structures
  48  * in which several reference fields of the same node are
  49  * independently subject to atomic updates. For example, a tree node
  50  * might be declared as
  51  *
  52  *  <pre> {@code
  53  * class Node {
  54  *   private volatile Node left, right;
  55  *
  56  *   private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
  57  *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
  58  *   private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
  59  *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
  60  *
  61  *   Node getLeft() { return left;  }
  62  *   boolean compareAndSetLeft(Node expect, Node update) {
  63  *     return leftUpdater.compareAndSet(this, expect, update);
  64  *   }
  65  *   // ... and so on
  66  * }}</pre>
  67  *
  68  * <p>Note that the guarantees of the {@code compareAndSet}
  69  * method in this class are weaker than in other atomic classes.
  70  * Because this class cannot ensure that all uses of the field
  71  * are appropriate for purposes of atomic access, it can
  72  * guarantee atomicity only with respect to other invocations of
  73  * {@code compareAndSet} and {@code set} on the same updater.
  74  *
  75  * @since 1.5
  76  * @author Doug Lea
  77  * @param <T> The type of the object holding the updatable field
  78  * @param <V> The type of the field
  79  */
  80 public abstract class AtomicReferenceFieldUpdater<T, V> {
  81 
  82     /**
  83      * Creates and returns an updater for objects with the given field.
  84      * The Class arguments are needed to check that reflective types and
  85      * generic types match.
  86      *
  87      * @param tclass the class of the objects holding the field.
  88      * @param vclass the class of the field
  89      * @param fieldName the name of the field to be updated.
  90      * @return the updater
  91      * @throws IllegalArgumentException if the field is not a volatile reference type.
  92      * @throws RuntimeException with a nested reflection-based
  93      * exception if the class does not hold field or is the wrong type,
  94      * or the field is inaccessible to the caller according to Java language
  95      * access control
  96      */
  97     public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) {
  98         return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass,
  99                                                         vclass,
 100                                                         fieldName);
 101     }
 102 
 103     /**
 104      * Protected do-nothing constructor for use by subclasses.
 105      */
 106     protected AtomicReferenceFieldUpdater() {
 107     }
 108 
 109     /**
 110      * Atomically sets the field of the given object managed by this updater
 111      * to the given updated value if the current value {@code ==} the
 112      * expected value. This method is guaranteed to be atomic with respect to
 113      * other calls to {@code compareAndSet} and {@code set}, but not
 114      * necessarily with respect to other changes in the field.
 115      *
 116      * @param obj An object whose field to conditionally set
 117      * @param expect the expected value
 118      * @param update the new value
 119      * @return true if successful.
 120      */
 121     public abstract boolean compareAndSet(T obj, V expect, V update);
 122 
 123     /**
 124      * Atomically sets the field of the given object managed by this updater
 125      * to the given updated value if the current value {@code ==} the
 126      * expected value. This method is guaranteed to be atomic with respect to
 127      * other calls to {@code compareAndSet} and {@code set}, but not
 128      * necessarily with respect to other changes in the field.
 129      *
 130      * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 131      * and does not provide ordering guarantees, so is only rarely an
 132      * appropriate alternative to {@code compareAndSet}.
 133      *
 134      * @param obj An object whose field to conditionally set
 135      * @param expect the expected value
 136      * @param update the new value
 137      * @return true if successful.
 138      */
 139     public abstract boolean weakCompareAndSet(T obj, V expect, V update);
 140 
 141     /**
 142      * Sets the field of the given object managed by this updater to the
 143      * given updated value. This operation is guaranteed to act as a volatile
 144      * store with respect to subsequent invocations of {@code compareAndSet}.
 145      *
 146      * @param obj An object whose field to set
 147      * @param newValue the new value
 148      */
 149     public abstract void set(T obj, V newValue);
 150 
 151     /**
 152      * Eventually sets the field of the given object managed by this
 153      * updater to the given updated value.
 154      *
 155      * @param obj An object whose field to set
 156      * @param newValue the new value
 157      * @since 1.6
 158      */
 159     public abstract void lazySet(T obj, V newValue);
 160 
 161     /**
 162      * Gets the current value held in the field of the given object managed
 163      * by this updater.
 164      *
 165      * @param obj An object whose field to get
 166      * @return the current value
 167      */
 168     public abstract V get(T obj);
 169 
 170     /**
 171      * Atomically sets the field of the given object managed by this updater
 172      * to the given value and returns the old value.
 173      *
 174      * @param obj An object whose field to get and set
 175      * @param newValue the new value
 176      * @return the previous value
 177      */
 178     public V getAndSet(T obj, V newValue) {
 179         for (;;) {
 180             V current = get(obj);
 181             if (compareAndSet(obj, current, newValue))
 182                 return current;

 183         }
 184     }
 185 
 186     private static final class AtomicReferenceFieldUpdaterImpl<T,V>
 187         extends AtomicReferenceFieldUpdater<T,V> {
 188         private static final Unsafe unsafe = Unsafe.getUnsafe();
 189         private final long offset;
 190         private final Class<T> tclass;
 191         private final Class<V> vclass;
 192         private final Class<?> cclass;
 193 
 194         /*
 195          * Internal type checks within all update methods contain
 196          * internal inlined optimizations checking for the common
 197          * cases where the class is final (in which case a simple
 198          * getClass comparison suffices) or is of type Object (in
 199          * which case no check is needed because all objects are
 200          * instances of Object). The Object case is handled simply by
 201          * setting vclass to null in constructor.  The targetCheck and
 202          * updateCheck methods are invoked when these faster
 203          * screenings fail.
 204          */
 205 
 206         AtomicReferenceFieldUpdaterImpl(final Class<T> tclass,
 207                                         Class<V> vclass,
 208                                         final String fieldName) {
 209             final Field field;
 210             final Class<?> fieldClass;
 211             final Class<?> caller;
 212             final int modifiers;
 213             try {
 214                 field = AccessController.doPrivileged(
 215                     new PrivilegedExceptionAction<Field>() {
 216                         public Field run() throws NoSuchFieldException {
 217                             return tclass.getDeclaredField(fieldName);
 218                         }
 219                     });
 220                 caller = sun.reflect.Reflection.getCallerClass(3);
 221                 modifiers = field.getModifiers();
 222                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
 223                     caller, tclass, null, modifiers);
 224                 ClassLoader cl = tclass.getClassLoader();
 225                 ClassLoader ccl = caller.getClassLoader();
 226                 if ((ccl != null) && (ccl != cl) &&
 227                     ((cl == null) || !isAncestor(cl, ccl))) {
 228                   sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
 229                 }
 230                 fieldClass = field.getType();
 231             } catch (PrivilegedActionException pae) {
 232                 throw new RuntimeException(pae.getException());
 233             } catch (Exception ex) {
 234                 throw new RuntimeException(ex);
 235             }
 236 
 237             if (vclass != fieldClass)
 238                 throw new ClassCastException();
 239 
 240             if (!Modifier.isVolatile(modifiers))
 241                 throw new IllegalArgumentException("Must be volatile type");
 242 
 243             this.cclass = (Modifier.isProtected(modifiers) &&
 244                            caller != tclass) ? caller : null;
 245             this.tclass = tclass;
 246             if (vclass == Object.class)
 247                 this.vclass = null;
 248             else
 249                 this.vclass = vclass;
 250             offset = unsafe.objectFieldOffset(field);
 251         }
 252 
 253         /**
 254          * Returns true if the second classloader can be found in the first
 255          * classloader's delegation chain.
 256          * Equivalent to the inaccessible: first.isAncestor(second).
 257          */
 258         private static boolean isAncestor(ClassLoader first, ClassLoader second) {
 259             ClassLoader acl = first;
 260             do {
 261                 acl = acl.getParent();
 262                 if (second == acl) {
 263                     return true;
 264                 }
 265             } while (acl != null);
 266             return false;
 267         }
 268 
 269         void targetCheck(T obj) {
 270             if (!tclass.isInstance(obj))
 271                 throw new ClassCastException();
 272             if (cclass != null)
 273                 ensureProtectedAccess(obj);
 274         }
 275 
 276         void updateCheck(T obj, V update) {
 277             if (!tclass.isInstance(obj) ||
 278                 (update != null && vclass != null && !vclass.isInstance(update)))
 279                 throw new ClassCastException();
 280             if (cclass != null)
 281                 ensureProtectedAccess(obj);
 282         }
 283 
 284         public boolean compareAndSet(T obj, V expect, V update) {
 285             if (obj == null || obj.getClass() != tclass || cclass != null ||
 286                 (update != null && vclass != null &&
 287                  vclass != update.getClass()))
 288                 updateCheck(obj, update);
 289             return unsafe.compareAndSwapObject(obj, offset, expect, update);
 290         }
 291 
 292         public boolean weakCompareAndSet(T obj, V expect, V update) {
 293             // same implementation as strong form for now
 294             if (obj == null || obj.getClass() != tclass || cclass != null ||
 295                 (update != null && vclass != null &&
 296                  vclass != update.getClass()))
 297                 updateCheck(obj, update);
 298             return unsafe.compareAndSwapObject(obj, offset, expect, update);
 299         }
 300 
 301         public void set(T obj, V newValue) {
 302             if (obj == null || obj.getClass() != tclass || cclass != null ||
 303                 (newValue != null && vclass != null &&
 304                  vclass != newValue.getClass()))
 305                 updateCheck(obj, newValue);
 306             unsafe.putObjectVolatile(obj, offset, newValue);
 307         }
 308 
 309         public void lazySet(T obj, V newValue) {
 310             if (obj == null || obj.getClass() != tclass || cclass != null ||
 311                 (newValue != null && vclass != null &&
 312                  vclass != newValue.getClass()))
 313                 updateCheck(obj, newValue);
 314             unsafe.putOrderedObject(obj, offset, newValue);
 315         }
 316 
 317         @SuppressWarnings("unchecked")
 318         public V get(T obj) {
 319             if (obj == null || obj.getClass() != tclass || cclass != null)
 320                 targetCheck(obj);
 321             return (V)unsafe.getObjectVolatile(obj, offset);
 322         }
 323 









 324         private void ensureProtectedAccess(T obj) {
 325             if (cclass.isInstance(obj)) {
 326                 return;
 327             }
 328             throw new RuntimeException(
 329                 new IllegalAccessException("Class " +
 330                     cclass.getName() +
 331                     " can not access a protected member of class " +
 332                     tclass.getName() +
 333                     " using an instance of " +
 334                     obj.getClass().getName()
 335                 )
 336             );
 337         }
 338     }
 339 }
--- EOF ---