OSDN Git Service

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