/lib/classpath/external/jsr166/java/util/concurrent/atomic/AtomicLongFieldUpdater.java

https://github.com/rhuitl/uClinux · Java · 406 lines · 221 code · 40 blank · 145 comment · 81 complexity · a9cf46668f352fc49de890b36ad8dd04 MD5 · raw file

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