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/licenses/publicdomain
  34  */
  35 
  36 package java.util.concurrent.atomic;
  37 import sun.misc.Unsafe;
  38 import java.lang.reflect.*;
  39 
  40 /**
  41  * A reflection-based utility that enables atomic updates to
  42  * designated {@code volatile} reference fields of designated
  43  * classes.  This class is designed for use in atomic data structures
  44  * in which several reference fields of the same node are
  45  * independently subject to atomic updates. For example, a tree node
  46  * might be declared as
  47  *
  48  * <pre>
  49  * class Node {
  50  *   private volatile Node left, right;
  51  *
  52  *   private static final AtomicReferenceFieldUpdater&lt;Node, Node&gt; leftUpdater =
  53  *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
  54  *   private static AtomicReferenceFieldUpdater&lt;Node, Node&gt; rightUpdater =
  55  *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
  56  *
  57  *   Node getLeft() { return left;  }
  58  *   boolean compareAndSetLeft(Node expect, Node update) {
  59  *     return leftUpdater.compareAndSet(this, expect, update);
  60  *   }
  61  *   // ... and so on
  62  * }
  63  * </pre>
  64  *
  65  * <p>Note that the guarantees of the {@code compareAndSet}
  66  * method in this class are weaker than in other atomic classes.
  67  * Because this class cannot ensure that all uses of the field
  68  * are appropriate for purposes of atomic access, it can
  69  * guarantee atomicity only with respect to other invocations of
  70  * {@code compareAndSet} and {@code set} on the same updater.
  71  *
  72  * @since 1.5
  73  * @author Doug Lea
  74  * @param <T> The type of the object holding the updatable field
  75  * @param <V> The type of the field
  76  */
  77 public abstract class AtomicReferenceFieldUpdater<T, V>  {
  78 
  79     /**
  80      * Creates and returns an updater for objects with the given field.
  81      * The Class arguments are needed to check that reflective types and
  82      * generic types match.
  83      *
  84      * @param tclass the class of the objects holding the field.
  85      * @param vclass the class of the field
  86      * @param fieldName the name of the field to be updated.
  87      * @return the updater
  88      * @throws IllegalArgumentException if the field is not a volatile reference type.
  89      * @throws RuntimeException with a nested reflection-based
  90      * exception if the class does not hold field or is the wrong type.
  91      */
  92     public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) {
  93         return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass,
  94                                                         vclass,
  95                                                         fieldName);
  96     }
  97 
  98     /**
  99      * Protected do-nothing constructor for use by subclasses.
 100      */
 101     protected AtomicReferenceFieldUpdater() {
 102     }
 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      * @param obj An object whose field to conditionally set
 112      * @param expect the expected value
 113      * @param update the new value
 114      * @return true if successful.
 115      */
 116     public abstract boolean compareAndSet(T obj, V expect, V update);
 117 
 118     /**
 119      * Atomically sets the field of the given object managed by this updater
 120      * to the given updated value if the current value {@code ==} the
 121      * expected value. This method is guaranteed to be atomic with respect to
 122      * other calls to {@code compareAndSet} and {@code set}, but not
 123      * necessarily with respect to other changes in the field.
 124      *
 125      * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 126      * and does not provide ordering guarantees, so is only rarely an
 127      * appropriate alternative to {@code compareAndSet}.
 128      *
 129      * @param obj An object whose field to conditionally set
 130      * @param expect the expected value
 131      * @param update the new value
 132      * @return true if successful.
 133      */
 134     public abstract boolean weakCompareAndSet(T obj, V expect, V update);
 135 
 136     /**
 137      * Sets the field of the given object managed by this updater to the
 138      * given updated value. This operation is guaranteed to act as a volatile
 139      * store with respect to subsequent invocations of {@code compareAndSet}.
 140      *
 141      * @param obj An object whose field to set
 142      * @param newValue the new value
 143      */
 144     public abstract void set(T obj, V newValue);
 145 
 146     /**
 147      * Eventually sets the field of the given object managed by this
 148      * updater to the given updated value.
 149      *
 150      * @param obj An object whose field to set
 151      * @param newValue the new value
 152      * @since 1.6
 153      */
 154     public abstract void lazySet(T obj, V newValue);
 155 
 156     /**
 157      * Gets the current value held in the field of the given object managed
 158      * by this updater.
 159      *
 160      * @param obj An object whose field to get
 161      * @return the current value
 162      */
 163     public abstract V get(T obj);
 164 
 165     /**
 166      * Atomically sets the field of the given object managed by this updater
 167      * to the given value and returns the old value.
 168      *
 169      * @param obj An object whose field to get and set
 170      * @param newValue the new value
 171      * @return the previous value
 172      */
 173     public V getAndSet(T obj, V newValue) {
 174         for (;;) {
 175             V current = get(obj);
 176             if (compareAndSet(obj, current, newValue))
 177                 return current;
 178         }
 179     }
 180 
 181     private static final class AtomicReferenceFieldUpdaterImpl<T,V>
 182         extends AtomicReferenceFieldUpdater<T,V> {
 183         private static final Unsafe unsafe = Unsafe.getUnsafe();
 184         private final long offset;
 185         private final Class<T> tclass;
 186         private final Class<V> vclass;
 187         private final Class cclass;
 188 
 189         /*
 190          * Internal type checks within all update methods contain
 191          * internal inlined optimizations checking for the common
 192          * cases where the class is final (in which case a simple
 193          * getClass comparison suffices) or is of type Object (in
 194          * which case no check is needed because all objects are
 195          * instances of Object). The Object case is handled simply by
 196          * setting vclass to null in constructor.  The targetCheck and
 197          * updateCheck methods are invoked when these faster
 198          * screenings fail.
 199          */
 200 
 201         AtomicReferenceFieldUpdaterImpl(Class<T> tclass,
 202                                         Class<V> vclass,
 203                                         String fieldName) {
 204             Field field = null;
 205             Class fieldClass = null;
 206             Class caller = null;
 207             int modifiers = 0;
 208             try {
 209                 field = tclass.getDeclaredField(fieldName);
 210                 caller = sun.reflect.Reflection.getCallerClass(3);
 211                 modifiers = field.getModifiers();
 212                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
 213                     caller, tclass, null, modifiers);
 214                 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
 215                 fieldClass = field.getType();
 216             } catch (Exception ex) {
 217                 throw new RuntimeException(ex);
 218             }
 219 
 220             if (vclass != fieldClass)
 221                 throw new ClassCastException();
 222 
 223             if (!Modifier.isVolatile(modifiers))
 224                 throw new IllegalArgumentException("Must be volatile type");
 225 
 226             this.cclass = (Modifier.isProtected(modifiers) &&
 227                            caller != tclass) ? caller : null;
 228             this.tclass = tclass;
 229             if (vclass == Object.class)
 230                 this.vclass = null;
 231             else
 232                 this.vclass = vclass;
 233             offset = unsafe.objectFieldOffset(field);
 234         }
 235 
 236         void targetCheck(T obj) {
 237             if (!tclass.isInstance(obj))
 238                 throw new ClassCastException();
 239             if (cclass != null)
 240                 ensureProtectedAccess(obj);
 241         }
 242 
 243         void updateCheck(T obj, V update) {
 244             if (!tclass.isInstance(obj) ||
 245                 (update != null && vclass != null && !vclass.isInstance(update)))
 246                 throw new ClassCastException();
 247             if (cclass != null)
 248                 ensureProtectedAccess(obj);
 249         }
 250 
 251         public boolean compareAndSet(T obj, V expect, V update) {
 252             if (obj == null || obj.getClass() != tclass || cclass != null ||
 253                 (update != null && vclass != null &&
 254                  vclass != update.getClass()))
 255                 updateCheck(obj, update);
 256             return unsafe.compareAndSwapObject(obj, offset, expect, update);
 257         }
 258 
 259         public boolean weakCompareAndSet(T obj, V expect, V update) {
 260             // same implementation as strong form for now
 261             if (obj == null || obj.getClass() != tclass || cclass != null ||
 262                 (update != null && vclass != null &&
 263                  vclass != update.getClass()))
 264                 updateCheck(obj, update);
 265             return unsafe.compareAndSwapObject(obj, offset, expect, update);
 266         }
 267 
 268         public void set(T obj, V newValue) {
 269             if (obj == null || obj.getClass() != tclass || cclass != null ||
 270                 (newValue != null && vclass != null &&
 271                  vclass != newValue.getClass()))
 272                 updateCheck(obj, newValue);
 273             unsafe.putObjectVolatile(obj, offset, newValue);
 274         }
 275 
 276         public void lazySet(T obj, V newValue) {
 277             if (obj == null || obj.getClass() != tclass || cclass != null ||
 278                 (newValue != null && vclass != null &&
 279                  vclass != newValue.getClass()))
 280                 updateCheck(obj, newValue);
 281             unsafe.putOrderedObject(obj, offset, newValue);
 282         }
 283 
 284         public V get(T obj) {
 285             if (obj == null || obj.getClass() != tclass || cclass != null)
 286                 targetCheck(obj);
 287             return (V)unsafe.getObjectVolatile(obj, offset);
 288         }
 289 
 290         private void ensureProtectedAccess(T obj) {
 291             if (cclass.isInstance(obj)) {
 292                 return;
 293             }
 294             throw new RuntimeException (
 295                 new IllegalAccessException("Class " +
 296                     cclass.getName() +
 297                     " can not access a protected member of class " +
 298                     tclass.getName() +
 299                     " using an instance of " +
 300                     obj.getClass().getName()
 301                 )
 302             );
 303         }
 304     }
 305 }
--- EOF ---