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 long} 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  AtomicLongFieldUpdater<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 long 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> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
  73         if (AtomicLong.VM_SUPPORTS_LONG_CAS)
  74             return new CASUpdater<U>(tclass, fieldName);
  75         else
  76             return new LockedUpdater<U>(tclass, fieldName);
  77     }
  78 
  79     /**
  80      * Protected do-nothing constructor for use by subclasses.
  81      */
  82     protected AtomicLongFieldUpdater() {
  83     }
  84 
  85     /**
  86      * Atomically sets the field of the given object managed by this updater
  87      * to the given updated value if the current value {@code ==} the
  88      * expected value. This method is guaranteed to be atomic with respect to
  89      * other calls to {@code compareAndSet} and {@code set}, but not
  90      * necessarily with respect to other changes in the field.
  91      *
  92      * @param obj An object whose field to conditionally set
  93      * @param expect the expected value
  94      * @param update the new value
  95      * @return true if successful.
  96      * @throws ClassCastException if {@code obj} is not an instance
  97      * of the class possessing the field established in the constructor.
  98      */
  99     public abstract boolean compareAndSet(T obj, long expect, long update);
 100 
 101     /**
 102      * Atomically sets the field of the given object managed by this updater
 103      * to the given updated value if the current value {@code ==} the
 104      * expected value. This method is guaranteed to be atomic with respect to
 105      * other calls to {@code compareAndSet} and {@code set}, but not
 106      * necessarily with respect to other changes in the field.
 107      *
 108      * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 109      * and does not provide ordering guarantees, so is only rarely an
 110      * appropriate alternative to {@code compareAndSet}.
 111      *
 112      * @param obj An object whose field to conditionally set
 113      * @param expect the expected value
 114      * @param update the new value
 115      * @return true if successful.
 116      * @throws ClassCastException if {@code obj} is not an instance
 117      * of the class possessing the field established in the constructor.
 118      */
 119     public abstract boolean weakCompareAndSet(T obj, long expect, long update);
 120 
 121     /**
 122      * Sets the field of the given object managed by this updater to the
 123      * given updated value. This operation is guaranteed to act as a volatile
 124      * store with respect to subsequent invocations of {@code compareAndSet}.
 125      *
 126      * @param obj An object whose field to set
 127      * @param newValue the new value
 128      */
 129     public abstract void set(T obj, long newValue);
 130 
 131     /**
 132      * Eventually sets the field of the given object managed by this
 133      * updater to the given updated value.
 134      *
 135      * @param obj An object whose field to set
 136      * @param newValue the new value
 137      * @since 1.6
 138      */
 139     public abstract void lazySet(T obj, long newValue);
 140 
 141     /**
 142      * Gets the current value held in the field of the given object managed
 143      * by this updater.
 144      *
 145      * @param obj An object whose field to get
 146      * @return the current value
 147      */
 148     public abstract long get(T obj);
 149 
 150     /**
 151      * Atomically sets the field of the given object managed by this updater
 152      * to the given value and returns the old value.
 153      *
 154      * @param obj An object whose field to get and set
 155      * @param newValue the new value
 156      * @return the previous value
 157      */
 158     public long getAndSet(T obj, long newValue) {
 159         for (;;) {
 160             long current = get(obj);
 161             if (compareAndSet(obj, current, newValue))
 162                 return current;
 163         }
 164     }
 165 
 166     /**
 167      * Atomically increments by one the current value of the field of the
 168      * given object managed by this updater.
 169      *
 170      * @param obj An object whose field to get and set
 171      * @return the previous value
 172      */
 173     public long getAndIncrement(T obj) {
 174         for (;;) {
 175             long current = get(obj);
 176             long next = current + 1;
 177             if (compareAndSet(obj, current, next))
 178                 return current;
 179         }
 180     }
 181 
 182     /**
 183      * Atomically decrements by one the current value of the field of the
 184      * given object managed by this updater.
 185      *
 186      * @param obj An object whose field to get and set
 187      * @return the previous value
 188      */
 189     public long getAndDecrement(T obj) {
 190         for (;;) {
 191             long current = get(obj);
 192             long next = current - 1;
 193             if (compareAndSet(obj, current, next))
 194                 return current;
 195         }
 196     }
 197 
 198     /**
 199      * Atomically adds the given value to the current value of the field of
 200      * the given object managed by this updater.
 201      *
 202      * @param obj An object whose field to get and set
 203      * @param delta the value to add
 204      * @return the previous value
 205      */
 206     public long getAndAdd(T obj, long delta) {
 207         for (;;) {
 208             long current = get(obj);
 209             long next = current + delta;
 210             if (compareAndSet(obj, current, next))
 211                 return current;
 212         }
 213     }
 214 
 215     /**
 216      * Atomically increments by one the current value of the field of the
 217      * given object managed by this updater.
 218      *
 219      * @param obj An object whose field to get and set
 220      * @return the updated value
 221      */
 222     public long incrementAndGet(T obj) {
 223         for (;;) {
 224             long current = get(obj);
 225             long next = current + 1;
 226             if (compareAndSet(obj, current, next))
 227                 return next;
 228         }
 229     }
 230 
 231     /**
 232      * Atomically decrements by one the current value of the field of the
 233      * given object managed by this updater.
 234      *
 235      * @param obj An object whose field to get and set
 236      * @return the updated value
 237      */
 238     public long decrementAndGet(T obj) {
 239         for (;;) {
 240             long current = get(obj);
 241             long next = current - 1;
 242             if (compareAndSet(obj, current, next))
 243                 return next;
 244         }
 245     }
 246 
 247     /**
 248      * Atomically adds the given value to the current value of the field of
 249      * the given object managed by this updater.
 250      *
 251      * @param obj An object whose field to get and set
 252      * @param delta the value to add
 253      * @return the updated value
 254      */
 255     public long addAndGet(T obj, long delta) {
 256         for (;;) {
 257             long current = get(obj);
 258             long next = current + delta;
 259             if (compareAndSet(obj, current, next))
 260                 return next;
 261         }
 262     }
 263 
 264     private static class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
 265         private static final Unsafe unsafe = Unsafe.getUnsafe();
 266         private final long offset;
 267         private final Class<T> tclass;
 268         private final Class cclass;
 269 
 270         CASUpdater(Class<T> tclass, String fieldName) {
 271             Field field = null;
 272             Class caller = null;
 273             int modifiers = 0;
 274             try {
 275                 field = tclass.getDeclaredField(fieldName);
 276                 caller = sun.reflect.Reflection.getCallerClass(3);
 277                 modifiers = field.getModifiers();
 278                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
 279                     caller, tclass, null, modifiers);
 280                 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
 281             } catch (Exception ex) {
 282                 throw new RuntimeException(ex);
 283             }
 284 
 285             Class fieldt = field.getType();
 286             if (fieldt != long.class)
 287                 throw new IllegalArgumentException("Must be long type");
 288 
 289             if (!Modifier.isVolatile(modifiers))
 290                 throw new IllegalArgumentException("Must be volatile type");
 291 
 292             this.cclass = (Modifier.isProtected(modifiers) &&
 293                            caller != tclass) ? caller : null;
 294             this.tclass = tclass;
 295             offset = unsafe.objectFieldOffset(field);
 296         }
 297 
 298         private void fullCheck(T obj) {
 299             if (!tclass.isInstance(obj))
 300                 throw new ClassCastException();
 301             if (cclass != null)
 302                 ensureProtectedAccess(obj);
 303         }
 304 
 305         public boolean compareAndSet(T obj, long expect, long update) {
 306             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 307             return unsafe.compareAndSwapLong(obj, offset, expect, update);
 308         }
 309 
 310         public boolean weakCompareAndSet(T obj, long expect, long update) {
 311             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 312             return unsafe.compareAndSwapLong(obj, offset, expect, update);
 313         }
 314 
 315         public void set(T obj, long newValue) {
 316             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 317             unsafe.putLongVolatile(obj, offset, newValue);
 318         }
 319 
 320         public void lazySet(T obj, long newValue) {
 321             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 322             unsafe.putOrderedLong(obj, offset, newValue);
 323         }
 324 
 325         public long get(T obj) {
 326             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 327             return unsafe.getLongVolatile(obj, offset);
 328         }
 329 
 330         private void ensureProtectedAccess(T obj) {
 331             if (cclass.isInstance(obj)) {
 332                 return;
 333             }
 334             throw new RuntimeException(
 335                 new IllegalAccessException("Class " +
 336                     cclass.getName() +
 337                     " can not access a protected member of class " +
 338                     tclass.getName() +
 339                     " using an instance of " +
 340                     obj.getClass().getName()
 341                 )
 342             );
 343         }
 344     }
 345 
 346 
 347     private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
 348         private static final Unsafe unsafe = Unsafe.getUnsafe();
 349         private final long offset;
 350         private final Class<T> tclass;
 351         private final Class cclass;
 352 
 353         LockedUpdater(Class<T> tclass, String fieldName) {
 354             Field field = null;
 355             Class caller = null;
 356             int modifiers = 0;
 357             try {
 358                 field = tclass.getDeclaredField(fieldName);
 359                 caller = sun.reflect.Reflection.getCallerClass(3);
 360                 modifiers = field.getModifiers();
 361                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
 362                     caller, tclass, null, modifiers);
 363                 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
 364             } catch (Exception ex) {
 365                 throw new RuntimeException(ex);
 366             }
 367 
 368             Class fieldt = field.getType();
 369             if (fieldt != long.class)
 370                 throw new IllegalArgumentException("Must be long type");
 371 
 372             if (!Modifier.isVolatile(modifiers))
 373                 throw new IllegalArgumentException("Must be volatile type");
 374 
 375             this.cclass = (Modifier.isProtected(modifiers) &&
 376                            caller != tclass) ? caller : null;
 377             this.tclass = tclass;
 378             offset = unsafe.objectFieldOffset(field);
 379         }
 380 
 381         private void fullCheck(T obj) {
 382             if (!tclass.isInstance(obj))
 383                 throw new ClassCastException();
 384             if (cclass != null)
 385                 ensureProtectedAccess(obj);
 386         }
 387 
 388         public boolean compareAndSet(T obj, long expect, long update) {
 389             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 390             synchronized (this) {
 391                 long v = unsafe.getLong(obj, offset);
 392                 if (v != expect)
 393                     return false;
 394                 unsafe.putLong(obj, offset, update);
 395                 return true;
 396             }
 397         }
 398 
 399         public boolean weakCompareAndSet(T obj, long expect, long update) {
 400             return compareAndSet(obj, expect, update);
 401         }
 402 
 403         public void set(T obj, long newValue) {
 404             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 405             synchronized (this) {
 406                 unsafe.putLong(obj, offset, newValue);
 407             }
 408         }
 409 
 410         public void lazySet(T obj, long newValue) {
 411             set(obj, newValue);
 412         }
 413 
 414         public long get(T obj) {
 415             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
 416             synchronized (this) {
 417                 return unsafe.getLong(obj, offset);
 418             }
 419         }
 420 
 421         private void ensureProtectedAccess(T obj) {
 422             if (cclass.isInstance(obj)) {
 423                 return;
 424             }
 425             throw new RuntimeException(
 426                 new IllegalAccessException("Class " +
 427                     cclass.getName() +
 428                     " can not access a protected member of class " +
 429                     tclass.getName() +
 430                     " using an instance of " +
 431                     obj.getClass().getName()
 432                 )
 433             );
 434         }
 435     }
 436 }