Skip to content

Commit f0a3e01

Browse files
Merge pull request #5 from qibergames/development
Rework future completion and add atomic variable support
2 parents a137af5 + 7d72e7f commit f0a3e01

19 files changed

+573
-25
lines changed
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
package com.qibergames.futura.concurrent.atomic;
2+
3+
import lombok.Getter;
4+
import org.jetbrains.annotations.NotNull;
5+
6+
import java.lang.reflect.Field;
7+
import sun.misc.Unsafe;
8+
9+
/**
10+
* Represents an implementation of {@link VarHandle} for legacy java runtimes, that utilise the {@link Unsafe} API.
11+
*
12+
* @param <T> the type of the variable
13+
*/
14+
@Getter
15+
class LegacyVarHandle<T> implements VarHandle<T> {
16+
/**
17+
* The object that owns the field (either a class or an instance).
18+
*/
19+
private final @NotNull Object handle;
20+
21+
/**
22+
* The field to create a handle for.
23+
*/
24+
private final @NotNull Field field;
25+
26+
/**
27+
* The internal offset of the field.
28+
*/
29+
private final long offset;
30+
31+
/**
32+
* Create a new {@link LegacyVarHandle} for the specified field.
33+
*
34+
* @param handle the object that owns the field (either a class or an instance)
35+
* @param field the field to create a handle for
36+
* @param isStatic whether the field is static or not
37+
*/
38+
public LegacyVarHandle(@NotNull Object handle, @NotNull Field field, boolean isStatic) {
39+
this.handle = handle;
40+
this.field = field;
41+
this.offset = isStatic ? VarHandleSupport.UNSAFE.staticFieldOffset(field) : VarHandleSupport.UNSAFE.objectFieldOffset(field);
42+
}
43+
44+
/**
45+
* Retrieve the value of the variable, with memory semantics of reading as if the variable was declared
46+
* non-{@code volatile}. Commonly referred to as plain read access.
47+
*
48+
* @return the held value of the variable
49+
*/
50+
@Override
51+
@SuppressWarnings("unchecked")
52+
public T get() {
53+
verifyHandle();
54+
return (T) VarHandleSupport.UNSAFE.getObject(handle, offset);
55+
}
56+
57+
/**
58+
* Retrieve the value of the variable, with memory semantics of reading as if the variable was declared
59+
* non-{@code volatile}. Commonly referred to as plain read access.
60+
*
61+
* @param handle the holder of the field (either a class or an instance)
62+
* @return the held value of the variable
63+
*/
64+
@Override
65+
@SuppressWarnings("unchecked")
66+
public T get(@NotNull Object handle) {
67+
return (T) VarHandleSupport.UNSAFE.getObject(handle, offset);
68+
}
69+
70+
/**
71+
* Retrieve the value of the variable, with memory semantics of reading as if the variable was declared
72+
* {@code volatile}.
73+
*
74+
* @return the held value of the variable
75+
*/
76+
@Override
77+
@SuppressWarnings("unchecked")
78+
public T getVolatile() {
79+
verifyHandle();
80+
return (T) VarHandleSupport.UNSAFE.getObjectVolatile(handle, offset);
81+
}
82+
83+
/**
84+
* Retrieve the value of the variable, with memory semantics of reading as if the variable was declared
85+
* {@code volatile}.
86+
*
87+
* @param handle the holder of the field (either a class or an instance)
88+
* @return the held value of the variable
89+
*/
90+
@Override
91+
@SuppressWarnings("unchecked")
92+
public T getVolatile(@NotNull Object handle) {
93+
return (T) VarHandleSupport.UNSAFE.getObjectVolatile(handle, offset);
94+
}
95+
96+
/**
97+
* Update the value of the variable to {@code newValue}, with memory semantics of setting as if the variable
98+
* was declared non-{@code volatile} and non-{@code final}. Commonly referred to as plain write access.
99+
*
100+
* @param value the new value of the variable
101+
*/
102+
public void set(T value) {
103+
verifyHandle();
104+
VarHandleSupport.UNSAFE.putObject(handle, offset, value);
105+
}
106+
107+
/**
108+
* Update the value of the variable to {@code newValue}, with memory semantics of setting as if the variable was
109+
* declared non-{@code volatile} and non-{@code final}. Commonly referred to as plain write access.
110+
*
111+
* @param handle the holder of the field (either a class or an instance)
112+
* @param value the new value of the variable
113+
*/
114+
@Override
115+
public void set(@NotNull Object handle, T value) {
116+
VarHandleSupport.UNSAFE.putObject(handle, offset, value);
117+
}
118+
119+
/**
120+
* Update the value of the variable to {@code newValue}, with memory semantics of setting as if the variable
121+
* was declared {@code volatile}.
122+
*
123+
* @param value the new value of the variable
124+
*/
125+
public void setVolatile(T value) {
126+
verifyHandle();
127+
VarHandleSupport.UNSAFE.putObjectVolatile(handle, offset, value);
128+
}
129+
130+
/**
131+
* Update the value of the variable to {@code newValue}, with memory semantics of setting as if the variable was
132+
* declared {@code volatile}.
133+
*
134+
* @param handle the holder of the field (either a class or an instance)
135+
* @param value the new value of the variable
136+
*/
137+
@Override
138+
public void setVolatile(@NotNull Object handle, T value) {
139+
VarHandleSupport.UNSAFE.putObjectVolatile(handle, offset, value);
140+
}
141+
142+
/**
143+
* Update the value of the variable to {@code newValue}.
144+
* <p>
145+
* This method acts like {@link #setVolatile(Object)}, except it does not guarantee immediate visibility of the
146+
* store to other threads. This method is generally only useful if the underlying field is a Java volatile (or if
147+
* an array cell, one that is otherwise only accessed using volatile accesses).
148+
*
149+
* @param value the new value of the variable
150+
*/
151+
@Override
152+
public void setLazy(T value) {
153+
verifyHandle();
154+
VarHandleSupport.UNSAFE.putOrderedObject(handle, offset, value);
155+
}
156+
157+
/**
158+
* Update the value of the variable to {@code newValue}.
159+
* <p>
160+
* This method acts like {@link #setVolatile(Object)}, except it does not guarantee immediate visibility of the
161+
* store to other threads. This method is generally only useful if the underlying field is a Java volatile (or if
162+
* an array cell, one that is otherwise only accessed using volatile accesses).
163+
*
164+
* @param handle the holder of the field (either a class or an instance)
165+
* @param value the new value of the variable
166+
*/
167+
@Override
168+
public void setLazy(@NotNull Object handle, T value) {
169+
VarHandleSupport.UNSAFE.putOrderedObject(handle, offset, value);
170+
}
171+
172+
/**
173+
* Atomically set the value of the variable to {@code update} with the memory semantics of {@link #setVolatile}
174+
* if the variable's current value, referred to as the <em>witness value</em>, {@code ==} the {@code expected},
175+
* as accessed with the memory semantics of {@link #getVolatile}.
176+
*
177+
* @param expected the condition of the update
178+
* @param update the new value of the variable
179+
*
180+
* @return {@code true} if the value of the variable was changed, {@code false} otherwise
181+
*/
182+
public boolean compareAndSet(T expected, T update) {
183+
verifyHandle();
184+
return VarHandleSupport.UNSAFE.compareAndSwapObject(handle, offset, expected, update);
185+
}
186+
187+
/**
188+
* Atomically set the value of the variable to {@code update} with the memory semantics of {@link #setVolatile} if
189+
* the variable's current value, referred to as the <em>witness value</em>, {@code ==} the {@code expected}, as
190+
* accessed with the memory semantics of {@link #getVolatile}.
191+
*
192+
* @param handle the holder of the field (either a class or an instance)
193+
* @param expected the condition of the update
194+
* @param update the new value of the variable
195+
* @return {@code true} if the value of the variable was changed, {@code false} otherwise
196+
*/
197+
@Override
198+
public boolean compareAndSet(@NotNull Object handle, T expected, T update) {
199+
return VarHandleSupport.UNSAFE.compareAndSwapObject(handle, offset, expected, update);
200+
}
201+
202+
/**
203+
* Atomically set the value of the variable to {@code newValue} with the memory semantics of {@link #setVolatile}
204+
* and return the variable's previous value, as accessed with the memory semantics of {@link #getVolatile}.
205+
*
206+
* @param newValue the new value of the variable
207+
* @return the previous value of the variable
208+
*/
209+
public T getAndSet(T newValue) {
210+
verifyHandle();
211+
T prev;
212+
do {
213+
prev = get();
214+
} while (!compareAndSet(prev, newValue));
215+
return prev;
216+
}
217+
218+
/**
219+
* Atomically set the value of the variable to {@code newValue} with the memory semantics of {@link #setVolatile}
220+
* and return the variable's previous value, as accessed with the memory semantics of {@link #getVolatile}.
221+
*
222+
* @param handle the holder of the field (either a class or an instance)
223+
* @param newValue the new value of the variable
224+
* @return the previous value of the variable
225+
*/
226+
@Override
227+
public T getAndSet(@NotNull Object handle, T newValue) {
228+
T prev;
229+
do {
230+
prev = get(handle);
231+
} while (!compareAndSet(handle, prev, newValue));
232+
return prev;
233+
}
234+
235+
/**
236+
* Check if the user is trying to invoke a function that requires an implicit handle.
237+
*/
238+
private void verifyHandle() {
239+
if (handle == VarHandleSupport.DUMMY_HANDLE)
240+
throw new IllegalStateException("You must explicitly pass in a handle to use this function");
241+
}
242+
}

0 commit comments

Comments
 (0)