OSDN Git Service

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