Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/test/jdk/java/foreign/TestResourceScope.java
66643 views
1
/*
2
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
/*
25
* @test
26
* @modules java.base/jdk.internal.ref
27
* jdk.incubator.foreign/jdk.incubator.foreign
28
* @run testng/othervm TestResourceScope
29
*/
30
31
import java.lang.ref.Cleaner;
32
33
import jdk.incubator.foreign.ResourceScope;
34
import jdk.internal.ref.CleanerFactory;
35
36
import org.testng.annotations.DataProvider;
37
import org.testng.annotations.Test;
38
import static org.testng.Assert.*;
39
40
import java.util.ArrayList;
41
import java.util.List;
42
import java.util.concurrent.atomic.AtomicInteger;
43
import java.util.concurrent.atomic.AtomicReference;
44
import java.util.function.Supplier;
45
import java.util.stream.IntStream;
46
47
public class TestResourceScope {
48
49
final static int N_THREADS = 100;
50
51
@Test(dataProvider = "cleaners")
52
public void testConfined(Supplier<Cleaner> cleanerSupplier) {
53
AtomicInteger acc = new AtomicInteger();
54
Cleaner cleaner = cleanerSupplier.get();
55
ResourceScope scope = cleaner != null ?
56
ResourceScope.newConfinedScope(cleaner) :
57
ResourceScope.newConfinedScope();
58
for (int i = 0 ; i < N_THREADS ; i++) {
59
int delta = i;
60
scope.addCloseAction(() -> acc.addAndGet(delta));
61
}
62
assertEquals(acc.get(), 0);
63
64
if (cleaner == null) {
65
scope.close();
66
assertEquals(acc.get(), IntStream.range(0, N_THREADS).sum());
67
} else {
68
scope = null;
69
int expected = IntStream.range(0, N_THREADS).sum();
70
while (acc.get() != expected) {
71
kickGC();
72
}
73
}
74
}
75
76
@Test(dataProvider = "cleaners")
77
public void testSharedSingleThread(Supplier<Cleaner> cleanerSupplier) {
78
AtomicInteger acc = new AtomicInteger();
79
Cleaner cleaner = cleanerSupplier.get();
80
ResourceScope scope = cleaner != null ?
81
ResourceScope.newSharedScope(cleaner) :
82
ResourceScope.newSharedScope();
83
for (int i = 0 ; i < N_THREADS ; i++) {
84
int delta = i;
85
scope.addCloseAction(() -> acc.addAndGet(delta));
86
}
87
assertEquals(acc.get(), 0);
88
89
if (cleaner == null) {
90
scope.close();
91
assertEquals(acc.get(), IntStream.range(0, N_THREADS).sum());
92
} else {
93
scope = null;
94
int expected = IntStream.range(0, N_THREADS).sum();
95
while (acc.get() != expected) {
96
kickGC();
97
}
98
}
99
}
100
101
@Test(dataProvider = "cleaners")
102
public void testSharedMultiThread(Supplier<Cleaner> cleanerSupplier) {
103
AtomicInteger acc = new AtomicInteger();
104
Cleaner cleaner = cleanerSupplier.get();
105
List<Thread> threads = new ArrayList<>();
106
ResourceScope scope = cleaner != null ?
107
ResourceScope.newSharedScope(cleaner) :
108
ResourceScope.newSharedScope();
109
AtomicReference<ResourceScope> scopeRef = new AtomicReference<>(scope);
110
for (int i = 0 ; i < N_THREADS ; i++) {
111
int delta = i;
112
Thread thread = new Thread(() -> {
113
try {
114
scopeRef.get().addCloseAction(() -> {
115
acc.addAndGet(delta);
116
});
117
} catch (IllegalStateException ex) {
118
// already closed - we need to call cleanup manually
119
acc.addAndGet(delta);
120
}
121
});
122
threads.add(thread);
123
}
124
assertEquals(acc.get(), 0);
125
threads.forEach(Thread::start);
126
127
// if no cleaner, close - not all segments might have been added to the scope!
128
// if cleaner, don't unset the scope - after all, the scope is kept alive by threads
129
if (cleaner == null) {
130
while (true) {
131
try {
132
scope.close();
133
break;
134
} catch (IllegalStateException ise) {
135
// scope is acquired (by add) - wait some more
136
}
137
}
138
}
139
140
threads.forEach(t -> {
141
try {
142
t.join();
143
} catch (InterruptedException ex) {
144
fail();
145
}
146
});
147
148
if (cleaner == null) {
149
assertEquals(acc.get(), IntStream.range(0, N_THREADS).sum());
150
} else {
151
scope = null;
152
scopeRef.set(null);
153
int expected = IntStream.range(0, N_THREADS).sum();
154
while (acc.get() != expected) {
155
kickGC();
156
}
157
}
158
}
159
160
@Test(dataProvider = "cleaners")
161
public void testLockSingleThread(Supplier<Cleaner> cleanerSupplier) {
162
Cleaner cleaner = cleanerSupplier.get();
163
ResourceScope scope = cleaner != null ?
164
ResourceScope.newConfinedScope(cleaner) :
165
ResourceScope.newConfinedScope();
166
List<ResourceScope.Handle> handles = new ArrayList<>();
167
for (int i = 0 ; i < N_THREADS ; i++) {
168
handles.add(scope.acquire());
169
}
170
171
while (true) {
172
try {
173
scope.close();
174
assertEquals(handles.size(), 0);
175
break;
176
} catch (IllegalStateException ex) {
177
assertTrue(handles.size() > 0);
178
ResourceScope.Handle handle = handles.remove(0);
179
scope.release(handle);
180
scope.release(handle); // make sure it's idempotent
181
scope.release(handle); // make sure it's idempotent
182
}
183
}
184
}
185
186
@Test(dataProvider = "cleaners")
187
public void testLockSharedMultiThread(Supplier<Cleaner> cleanerSupplier) {
188
Cleaner cleaner = cleanerSupplier.get();
189
ResourceScope scope = cleaner != null ?
190
ResourceScope.newSharedScope(cleaner) :
191
ResourceScope.newSharedScope();
192
AtomicInteger lockCount = new AtomicInteger();
193
for (int i = 0 ; i < N_THREADS ; i++) {
194
new Thread(() -> {
195
try {
196
ResourceScope.Handle handle = scope.acquire(); // this can throw if segment has been closed
197
lockCount.incrementAndGet();
198
waitSomeTime();
199
lockCount.decrementAndGet();
200
scope.release(handle); // cannot throw (acquired segments cannot be closed)
201
scope.release(handle); // cannot throw (idempotent)
202
scope.release(handle); // cannot throw (idempotent)
203
} catch (IllegalStateException ex) {
204
// might be already closed - do nothing
205
}
206
}).start();
207
}
208
209
while (true) {
210
try {
211
scope.close();
212
assertEquals(lockCount.get(), 0);
213
break;
214
} catch (IllegalStateException ex) {
215
waitSomeTime();
216
}
217
}
218
}
219
220
@Test
221
public void testCloseEmptyConfinedScope() {
222
ResourceScope.newConfinedScope().close();
223
}
224
225
@Test
226
public void testCloseEmptySharedScope() {
227
ResourceScope.newSharedScope().close();
228
}
229
230
@Test
231
public void testCloseConfinedLock() {
232
ResourceScope scope = ResourceScope.newConfinedScope();
233
ResourceScope.Handle handle = scope.acquire();
234
AtomicReference<Throwable> failure = new AtomicReference<>();
235
Thread t = new Thread(() -> {
236
try {
237
scope.release(handle);
238
scope.release(handle); // make sure it's idempotent
239
scope.release(handle); // make sure it's idempotent
240
} catch (Throwable ex) {
241
failure.set(ex);
242
}
243
});
244
t.start();
245
try {
246
t.join();
247
assertNotNull(failure.get());
248
assertEquals(failure.get().getClass(), IllegalStateException.class);
249
} catch (Throwable ex) {
250
throw new AssertionError(ex);
251
}
252
}
253
254
@Test(dataProvider = "scopes")
255
public void testScopeHandles(Supplier<ResourceScope> scopeFactory) {
256
ResourceScope scope = scopeFactory.get();
257
acquireRecursive(scope, 5);
258
if (!scope.isImplicit()) {
259
scope.close();
260
}
261
}
262
263
private void acquireRecursive(ResourceScope scope, int acquireCount) {
264
ResourceScope.Handle handle = scope.acquire();
265
assertEquals(handle.scope(), scope);
266
if (acquireCount > 0) {
267
// recursive acquire
268
acquireRecursive(scope, acquireCount - 1);
269
}
270
if (!scope.isImplicit()) {
271
assertThrows(IllegalStateException.class, scope::close);
272
}
273
scope.release(handle);
274
scope.release(handle); // make sure it's idempotent
275
scope.release(handle); // make sure it's idempotent
276
}
277
278
private void waitSomeTime() {
279
try {
280
Thread.sleep(10);
281
} catch (InterruptedException ex) {
282
// ignore
283
}
284
}
285
286
private void kickGC() {
287
for (int i = 0 ; i < 100 ; i++) {
288
byte[] b = new byte[100];
289
System.gc();
290
Thread.onSpinWait();
291
}
292
}
293
294
@DataProvider
295
static Object[][] cleaners() {
296
return new Object[][] {
297
{ (Supplier<Cleaner>)() -> null },
298
{ (Supplier<Cleaner>)Cleaner::create },
299
{ (Supplier<Cleaner>)CleanerFactory::cleaner }
300
};
301
}
302
303
@DataProvider
304
static Object[][] scopes() {
305
return new Object[][] {
306
{ (Supplier<ResourceScope>)ResourceScope::newConfinedScope },
307
{ (Supplier<ResourceScope>)ResourceScope::newSharedScope },
308
{ (Supplier<ResourceScope>)ResourceScope::newImplicitScope },
309
{ (Supplier<ResourceScope>)ResourceScope::globalScope }
310
};
311
}
312
}
313
314