Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/lang/StackWalker/MultiThreadStackWalk.java
41149 views
1
/*
2
* Copyright (c) 2015, 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
import java.util.Arrays;
25
import java.util.Collections;
26
import java.util.List;
27
import java.util.Set;
28
import java.util.TreeSet;
29
import java.util.concurrent.atomic.AtomicBoolean;
30
import java.util.concurrent.atomic.AtomicLong;
31
import java.lang.StackWalker.StackFrame;
32
import static java.lang.StackWalker.Option.*;
33
34
35
/**
36
* @test
37
* @bug 8140450
38
* @summary This test will walk the stack using different methods, called
39
* from several threads running concurrently.
40
* Except in the case of MTSTACKSTREAM - which takes a snapshot
41
* of the stack before walking, all the methods only allow to
42
* walk the current thread stack.
43
* @run main/othervm MultiThreadStackWalk
44
* @author danielfuchs
45
*/
46
public class MultiThreadStackWalk {
47
48
static Set<String> infrastructureClasses = new TreeSet<>(Arrays.asList(
49
"jdk.internal.reflect.NativeMethodAccessorImpl",
50
"jdk.internal.reflect.DelegatingMethodAccessorImpl",
51
"java.lang.reflect.Method",
52
"com.sun.javatest.regtest.MainWrapper$MainThread",
53
"java.lang.Thread"
54
));
55
56
57
static final List<Class<?>> streamPipelines = Arrays.asList(
58
classForName("java.util.stream.AbstractPipeline"),
59
classForName("java.util.stream.TerminalOp")
60
);
61
62
static Class<?> classForName(String name) {
63
try {
64
return Class.forName(name);
65
} catch (ClassNotFoundException e){
66
throw new RuntimeException(e);
67
}
68
}
69
70
private static boolean isStreamPipeline(Class<?> clazz) {
71
for (Class<?> c : streamPipelines) {
72
if (c.isAssignableFrom(clazz)) {
73
return true;
74
}
75
}
76
return false;
77
}
78
79
/**
80
* An object that contains variables pertaining to the execution
81
* of the test within one thread.
82
* A small amount of those variable are shared with sub threads when
83
* the stack walk is executed in parallel - that is when spliterators
84
* obtained from trySplit are handed over to an instance of SplitThread
85
* in order to parallelize thread walking.
86
* @see WalkThread#handOff(MultiThreadStackWalk.Env, java.util.Spliterator, boolean, boolean)
87
* @see Env#split(MultiThreadStackWalk.Env)
88
*/
89
public static class Env {
90
final AtomicLong frameCounter; // private: the counter for the current thread.
91
final long checkMarkAt; // constant: the point at which we expect to
92
// find the marker in consume()
93
final long max; // constant: the maximum number of recursive
94
// calls to Call.
95
final AtomicBoolean debug ; // shared: whether debug is active for the
96
// instance of Test from which this instance
97
// of Env was spawned
98
final AtomicLong markerCalled; // shared: whether the marker was reached
99
final AtomicLong maxReached; // shared: whether max was reached
100
final Set<String> unexpected; // shared: list of unexpected infrastructure
101
// classes encountered after max is reached
102
103
public Env(long total, long markAt, AtomicBoolean debug) {
104
this.debug = debug;
105
frameCounter = new AtomicLong();
106
maxReached = new AtomicLong();
107
unexpected = Collections.synchronizedSet(new TreeSet<>());
108
this.max = total+2;
109
this.checkMarkAt = total - markAt + 1;
110
this.markerCalled = new AtomicLong();
111
}
112
113
// Used when delegating part of the stack walking to a sub thread
114
// see WalkThread.handOff.
115
private Env(Env orig, long start) {
116
debug = orig.debug;
117
frameCounter = new AtomicLong(start);
118
maxReached = orig.maxReached;
119
unexpected = orig.unexpected;
120
max = orig.max;
121
checkMarkAt = orig.checkMarkAt;
122
markerCalled = orig.markerCalled;
123
}
124
125
// The stack walk consumer method, where all the checks are
126
// performed.
127
public void consume(StackFrame sfi) {
128
if (frameCounter.get() == 0 && isStreamPipeline(sfi.getDeclaringClass())) {
129
return;
130
}
131
132
final long count = frameCounter.getAndIncrement();
133
final StringBuilder builder = new StringBuilder();
134
builder.append("Declaring class[")
135
.append(count)
136
.append("]: ")
137
.append(sfi.getDeclaringClass());
138
builder.append('\n');
139
builder.append("\t")
140
.append(sfi.getClassName())
141
.append(".")
142
.append(sfi.toStackTraceElement().getMethodName())
143
.append(sfi.toStackTraceElement().isNativeMethod()
144
? "(native)"
145
: "(" + sfi.toStackTraceElement().getFileName()
146
+":"+sfi.toStackTraceElement().getLineNumber()+")");
147
builder.append('\n');
148
if (debug.get()) {
149
System.out.print("[debug] " + builder.toString());
150
builder.setLength(0);
151
}
152
if (count == max) {
153
maxReached.incrementAndGet();
154
}
155
if (count == checkMarkAt) {
156
if (sfi.getDeclaringClass() != MultiThreadStackWalk.Marker.class) {
157
throw new RuntimeException("Expected Marker at " + count
158
+ ", found " + sfi.getDeclaringClass());
159
}
160
} else {
161
if (count <= 0 && sfi.getDeclaringClass() != MultiThreadStackWalk.Call.class) {
162
throw new RuntimeException("Expected Call at " + count
163
+ ", found " + sfi.getDeclaringClass());
164
} else if (count > 0 && count < max && sfi.getDeclaringClass() != MultiThreadStackWalk.Test.class) {
165
throw new RuntimeException("Expected Test at " + count
166
+ ", found " + sfi.getDeclaringClass());
167
} else if (count == max && sfi.getDeclaringClass() != MultiThreadStackWalk.class) {
168
throw new RuntimeException("Expected MultiThreadStackWalk at "
169
+ count + ", found " + sfi.getDeclaringClass());
170
} else if (count == max && !sfi.toStackTraceElement().getMethodName().equals("runTest")) {
171
throw new RuntimeException("Expected runTest method at "
172
+ count + ", found " + sfi.toStackTraceElement().getMethodName());
173
} else if (count == max+1) {
174
if (sfi.getDeclaringClass() != MultiThreadStackWalk.WalkThread.class) {
175
throw new RuntimeException("Expected MultiThreadStackWalk at "
176
+ count + ", found " + sfi.getDeclaringClass());
177
}
178
if (count == max && !sfi.toStackTraceElement().getMethodName().equals("run")) {
179
throw new RuntimeException("Expected main method at "
180
+ count + ", found " + sfi.toStackTraceElement().getMethodName());
181
}
182
} else if (count > max+1) {
183
// expect JTreg infrastructure...
184
if (!infrastructureClasses.contains(sfi.getDeclaringClass().getName())) {
185
System.err.println("**** WARNING: encountered unexpected infrastructure class at "
186
+ count +": " + sfi.getDeclaringClass().getName());
187
unexpected.add(sfi.getDeclaringClass().getName());
188
}
189
}
190
}
191
if (count == 100) {
192
// Maybe we should had some kind of checking inside that lambda
193
// too. For the moment we should be satisfied if it doesn't throw
194
// any exception and doesn't make the outer walk fail...
195
StackWalker.getInstance(RETAIN_CLASS_REFERENCE).forEach(x -> {
196
StackTraceElement st = x.toStackTraceElement();
197
StringBuilder b = new StringBuilder();
198
b.append("*** inner walk: ")
199
.append(x.getClassName())
200
.append(st == null ? "- no stack trace element -" :
201
("." + st.getMethodName()
202
+ (st.isNativeMethod() ? "(native)" :
203
"(" + st.getFileName()
204
+ ":" + st.getLineNumber() + ")")))
205
.append('\n');
206
if (debug.get()) {
207
System.out.print(b.toString());
208
b.setLength(0);
209
}
210
});
211
}
212
}
213
}
214
215
public interface Call {
216
enum WalkType {
217
WALKSTACK, // use Thread.walkStack
218
}
219
default WalkType getWalkType() { return WalkType.WALKSTACK;}
220
default void walk(Env env) {
221
WalkType walktype = getWalkType();
222
System.out.println("Thread "+ Thread.currentThread().getName()
223
+" starting walk with " + walktype);
224
switch(walktype) {
225
case WALKSTACK:
226
StackWalker.getInstance(RETAIN_CLASS_REFERENCE)
227
.forEach(env::consume);
228
break;
229
default:
230
throw new InternalError("Unknown walk type: " + walktype);
231
}
232
}
233
default void call(Env env, Call next, int total, int current, int markAt) {
234
if (current < total) {
235
next.call(env, next, total, current+1, markAt);
236
}
237
}
238
}
239
240
public static class Marker implements Call {
241
final WalkType walkType;
242
Marker(WalkType walkType) {
243
this.walkType = walkType;
244
}
245
@Override
246
public WalkType getWalkType() {
247
return walkType;
248
}
249
250
@Override
251
public void call(Env env, Call next, int total, int current, int markAt) {
252
env.markerCalled.incrementAndGet();
253
if (current < total) {
254
next.call(env, next, total, current+1, markAt);
255
} else {
256
next.walk(env);
257
}
258
}
259
}
260
261
public static class Test implements Call {
262
final Marker marker;
263
final WalkType walkType;
264
final AtomicBoolean debug;
265
Test(WalkType walkType) {
266
this.walkType = walkType;
267
this.marker = new Marker(walkType);
268
this.debug = new AtomicBoolean();
269
}
270
@Override
271
public WalkType getWalkType() {
272
return walkType;
273
}
274
@Override
275
public void call(Env env, Call next, int total, int current, int markAt) {
276
if (current < total) {
277
int nexti = current + 1;
278
Call nextObj = nexti==markAt ? marker : next;
279
nextObj.call(env, next, total, nexti, markAt);
280
} else {
281
walk(env);
282
}
283
}
284
}
285
286
public static Env runTest(Test test, int total, int markAt) {
287
Env env = new Env(total, markAt, test.debug);
288
test.call(env, test, total, 0, markAt);
289
return env;
290
}
291
292
public static void checkTest(Env env, Test test) {
293
String threadName = Thread.currentThread().getName();
294
System.out.println(threadName + ": Marker called: " + env.markerCalled.get());
295
System.out.println(threadName + ": Max reached: " + env.maxReached.get());
296
System.out.println(threadName + ": Frames consumed: " + env.frameCounter.get());
297
if (env.markerCalled.get() == 0) {
298
throw new RuntimeException(Thread.currentThread().getName() + ": Marker was not called.");
299
}
300
if (env.markerCalled.get() > 1) {
301
throw new RuntimeException(Thread.currentThread().getName()
302
+ ": Marker was called more than once: " + env.maxReached.get());
303
}
304
if (!env.unexpected.isEmpty()) {
305
System.out.flush();
306
System.err.println("Encountered some unexpected infrastructure classes below 'main': "
307
+ env.unexpected);
308
}
309
if (env.maxReached.get() == 0) {
310
throw new RuntimeException(Thread.currentThread().getName()
311
+ ": max not reached");
312
}
313
if (env.maxReached.get() > 1) {
314
throw new RuntimeException(Thread.currentThread().getName()
315
+ ": max was reached more than once: " + env.maxReached.get());
316
}
317
}
318
319
static class WalkThread extends Thread {
320
final static AtomicLong walkersCount = new AtomicLong();
321
Throwable failed = null;
322
final Test test;
323
public WalkThread(Test test) {
324
super("WalkThread[" + walkersCount.incrementAndGet() + ", type="
325
+ test.getWalkType() + "]");
326
this.test = test;
327
}
328
329
public void run() {
330
try {
331
Env env = runTest(test, 1000, 10);
332
//waitWalkers(env);
333
checkTest(env, test);
334
} catch(Throwable t) {
335
failed = t;
336
}
337
}
338
}
339
340
public static void main(String[] args) throws Throwable {
341
WalkThread[] threads = new WalkThread[Call.WalkType.values().length*3];
342
Throwable failed = null;
343
for (int i=0; i<threads.length; i++) {
344
Test test = new Test(Call.WalkType.values()[i%Call.WalkType.values().length]);
345
threads[i] = new WalkThread(test);
346
}
347
for (int i=0; i<threads.length; i++) {
348
threads[i].start();
349
}
350
for (int i=0; i<threads.length; i++) {
351
threads[i].join();
352
if (failed == null) failed = threads[i].failed;
353
else if (threads[i].failed == null) {
354
failed.addSuppressed(threads[i].failed);
355
}
356
}
357
if (failed != null) {
358
throw failed;
359
}
360
}
361
362
}
363
364