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 int} fields of designated classes.
  43  * This class is designed for use in atomic data structures in which
  44  * several fields of the same node are independently subject to atomic
  45  * updates.
  46  *
  47  * <p>Note that the guarantees of the {@code compareAndSet}
  48  * method in this class are weaker than in other atomic classes.
  49  * Because this class cannot ensure that all uses of the field
  50  * are appropriate for purposes of atomic access, it can
  51  * guarantee atomicity only with respect to other invocations of
  52  * {@code compareAndSet} and {@code set} on the same updater.
  53  *
  54  * @since 1.5
  55  * @author Doug Lea
  56  * @param <T> The type of the object holding the updatable field
  57  */
  58 public abstract class  AtomicIntegerFieldUpdater<T> {
  59     /**
  60      * Creates and returns an updater for objects with the given field.
  61      * The Class argument is needed to check that reflective types and
  62      * generic types match.
  63      *
  64      * @param tclass the class of the objects holding the field
  65      * @param fieldName the name of the field to be updated
  66      * @return the updater
  67      * @throws IllegalArgumentException if the field is not a
  68      * volatile integer type
  69      * @throws RuntimeException with a nested reflection-based
  70      * exception if the class does not hold field or is the wrong type
  71      */
  72     public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
  73         return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName);
  74     }
  75 
  76     /**
  77      * Protected do-nothing constructor for use by subclasses.
  78      */
  79     protected AtomicIntegerFieldUpdater() {
  80     }
  81 
  82     /**
  83      * Atomically sets the field of the given object managed by this updater
  84      * to the given updated value if the current value {@code ==} the
  85      * expected value. This method is guaranteed to be atomic with respect to
  86      * other calls to {@code compareAndSet} and {@code set}, but not
  87      * necessarily with respect to other changes in the field.
  88      *
  89      * @param obj An object whose field to conditionally set
  90      * @param expect the expected value
  91      * @param update the new value
  92      * @return true if successful
  93      * @throws ClassCastException if {@code obj} is not an instance
  94      * of the class possessing the field established in the constructor
  95      */
  96     public abstract boolean compareAndSet(T obj, int expect, int update);
  97 
  98     /**
  99      * Atomically sets the field of the given object managed by this updater
 100      * to the given updated value if the current value {@code ==} the
 101      * expected value. This method is guaranteed to be atomic with respect to
 102      * other calls to {@code compareAndSet} and {@code set}, but not
 103      * necessarily with respect to other changes in the field.
 104      *
 105      * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 106      * and does not provide ordering guarantees, so is only rarely an
 107      * appropriate alternative to {@code compareAndSet}.
 108      *
 109      * @param obj An object whose field to conditionally set
 110      * @param expect the expected value
 111      * @param update the new value
 112      * @return true if successful
 113      * @throws ClassCastException if {@code obj} is not an instance
 114      * of the class possessing the field established in the constructor
 115      */
 116     public abstract boolean weakCompareAndSet(T obj, int expect, int update);
 117 
 118     /**
 119      * Sets the field of the given object managed by this updater to the
 120      * given updated value. This operation is guaranteed to act as a volatile
 121      * store with respect to subsequent invocations of {@code compareAndSet}.
 122      *
 123      * @param obj An object whose field to set
 124      * @param newValue the new value
 125      */
 126     public abstract void set(T obj, int newValue);
 127 
 128     /**
 129      * Eventually sets the field of the given object managed by this
 130      * updater to the given updated value.
 131      *
 132      * @param obj An object whose field to set
 133      * @param newValue the new value
 134      * @since 1.6
 135      */
 136     public abstract void lazySet(T obj, int newValue);
 137 
 138 
 139     /**
 140      * Gets the current value held in the field of the given object managed
 141      * by this updater.
 142      *
 143      * @param obj An object whose field to get
 144      * @return the current value
 145      */
 146     public abstract int get(T obj);
 147 
 148     /**
 149      * Atomically sets the field of the given object managed by this updater
 150      * to the given value and returns the old value.
 151      *
 152      * @param obj An object whose field to get and set
 153      * @param newValue the new value
 154      * @return the previous value
 155      */
 156     public int getAndSet(T obj, int newValue) {
 157         for (;;) {
 158             int current = get(obj);
 159             if (compareAndSet(obj, current, newValue))
 160                 return current;
 161         }
 162     }
 163 
 164     /**
 165      * Atomically increments by one the current value of the field of the
 166      * given object managed by this updater.
 167      *
 168      * @param obj An object whose field to get and set
 169      * @return the previous value
 170      */
 171     public int getAndIncrement(T obj) {
 172         for (;;) {
 173             int current = get(obj);
 174             int next = current + 1;
 175             if (compareAndSet(obj, current, next))
 176                 return current;
 177         }
 178     }
 179 
 180     /**
 181      * Atomically decrements by one the current value of the field of the
 182      * given object managed by this updater.
 183      *
 184      * @param obj An object whose field to get and set
 185      * @return the previous value
 186      */
 187     public int getAndDecrement(T obj) {
 188         for (;;) {
 189             int current = get(obj);
 190             int next = current - 1;
 191             if (compareAndSet(obj, current, next))
 192                 return current;
 193         }
 194     }
 195 
 196     /**
 197      * Atomically adds the given value to the current value of the field of
 198      * the given object managed by this updater.
 199      *
 200      * @param obj An object whose field to get and set
 201      * @param delta the value to add
 202      * @return the previous value
 203      */
 204     public int getAndAdd(T obj, int delta) {
 205         for (;;) {
 206             int current = get(obj);
 207             int next = current + delta;
 208             if (compareAndSet(obj, current, next))
 209                 return current;
 210         }
 211     }
 212 
 213     /**
 214      * Atomically increments by one the current value of the field of the
 215      * given object managed by this updater.
 216      *
 217      * @param obj An object whose field to get and set
 218      * @return the updated value
 219      */
 220     public int incrementAndGet(T obj) {
 221         for (;;) {
 222             int current = get(obj);
 223             int next = current + 1;
 224             if (compareAndSet(obj, current, next))
 225                 return next;
 226         }
 227     }
 228 
 229     /**
 230      * Atomically decrements by one the current value of the field of the
 231      * given object managed by this updater.
 232      *
 233      * @param obj An object whose field to get and set
 234      * @return the updated value
 235      */
 236     public int decrementAndGet(T obj) {
 237         for (;;) {
 238             int current = get(obj);
 239             int next = current - 1;
 240             if (compareAndSet(obj, current, next))
 241                 return next;
 242         }
 243     }
 244 
 245     /**
 246      * Atomically adds the given value to the current value of the field of
 247      * the given object managed by this updater.
 248      *
 249      * @param obj An object whose field to get and set
 250      * @param delta the value to add
 251      * @return the updated value
 252      */
 253     public int addAndGet(T obj, int delta) {
 254         for (;;) {
 255             int current = get(obj);
 256             int next = current + delta;
 257             if (compareAndSet(obj, current, next))
 258                 return next;
 259         }
 260     }
 261 
 262     /**
 263      * Standard hotspot implementation using intrinsics
 264      */
 265     private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T> {
 266         private static final Unsafe unsafe = Unsafe.getUnsafe();
 267         private final long offset;
 268         private final Class<T> tclass;
 269         private final Class cclass;
 270 
 271         AtomicIntegerFieldUpdaterImpl(Class<T> tclass, String fieldName) {
 272             Field field = null;
 273             Class caller = null;
 274             int modifiers = 0;
 275             try {
 276                 field = tclass.getDeclaredField(fieldName);
 277                 caller = sun.reflect.Reflection.getCallerClass(3);
 278                 modifiers = field.getModifiers();
 279                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
 280                     caller, tclass, null, modifiers);
 281                 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
 282             } catch (Exception ex) {
 283                 throw new RuntimeException(ex);
 284             }
 285 
 286             Class fieldt = field.getType();
 287             if (fieldt != int.class)
 288                 throw new IllegalArgumentException("Must be integer type");
 289 
 290             if (!Modifier.isVolatile(modifiers))
 291                 throw new IllegalArgumentException("Must be volatile type");
 292 
 293             this.cclass = (Modifier.isProtected(modifiers) &&
 294                            caller != tclass) ? caller : null;
 295             this.tclass = tclass;
 296             offset = unsafe.objectFieldOffset(field);
 297         }
 298 
 299         private void fullCheck(T obj) {
 300             if (!tclass.isInstance(obj))
 301                 throw new ClassCastException();
 302             if (cclass != null)
 303                 ensureProtectedAccess(obj);
 304         }
 305 
 306         public boolean compareAndSet(T obj, int expect, int update) {
 307             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 308             return unsafe.compareAndSwapInt(obj, offset, expect, update);
 309         }
 310 
 311         public boolean weakCompareAndSet(T obj, int expect, int update) {
 312             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 313             return unsafe.compareAndSwapInt(obj, offset, expect, update);
 314         }
 315 
 316         public void set(T obj, int newValue) {
 317             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 318             unsafe.putIntVolatile(obj, offset, newValue);
 319         }
 320 
 321         public void lazySet(T obj, int newValue) {
 322             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 323             unsafe.putOrderedInt(obj, offset, newValue);
 324         }
 325 
 326         public final int get(T obj) {
 327             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 328             return unsafe.getIntVolatile(obj, offset);
 329         }
 330 
 331         private void ensureProtectedAccess(T obj) {
 332             if (cclass.isInstance(obj)) {
 333                 return;
 334             }
 335             throw new RuntimeException(
 336                 new IllegalAccessException("Class " +
 337                     cclass.getName() +
 338                     " can not access a protected member of class " +
 339                     tclass.getName() +
 340                     " using an instance of " +
 341                     obj.getClass().getName()
 342                 )
 343             );
 344         }
 345     }
 346 }
--- EOF ---