Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/lang/Thread/ThreadStateController.java
41149 views
1
/*
2
* Copyright (c) 2013, 2020, 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.concurrent.Phaser;
25
import java.util.concurrent.TimeUnit;
26
import java.util.concurrent.TimeoutException;
27
import java.util.concurrent.atomic.AtomicInteger;
28
import java.util.concurrent.locks.LockSupport;
29
30
import jdk.test.lib.LockFreeLogger;
31
import jdk.test.lib.Utils;
32
33
/**
34
* ThreadStateController allows a thread to request this thread to transition
35
* to a specific thread state. The {@linkplain #transitionTo request} is
36
* a blocking call that the calling thread will wait until this thread is about
37
* going to the new state. Only one request of state transition at a time
38
* is supported (the Phaser expects only parties of 2 to arrive and advance
39
* to next phase).
40
*/
41
public class ThreadStateController extends Thread {
42
// used to achieve waiting states
43
private final Object lock;
44
public ThreadStateController(String name, Object lock) {
45
super(name);
46
this.lock = lock;
47
}
48
49
public void checkThreadState(Thread.State expected) {
50
// maximum number of retries when checking for thread state.
51
final int MAX_RETRY = 500;
52
53
// wait for the thread to transition to the expected state.
54
// There is a small window between the thread checking the state
55
// and the thread actual entering that state.
56
Thread.State state;
57
int retryCount=0;
58
while ((state = getState()) != expected && retryCount < MAX_RETRY) {
59
pause(10);
60
retryCount++;
61
}
62
63
if (state == null) {
64
throw new RuntimeException(getName() + " expected to have " +
65
expected + " but got null.");
66
}
67
68
if (state != expected) {
69
throw new RuntimeException(String.format("%s expected in %s state but got %s " +
70
"(iterations %d interrupted %d)%n",
71
getName(), expected, state, iterations.get(), interrupted.get()));
72
}
73
}
74
75
public static void pause(long ms) {
76
try {
77
Thread.sleep(Utils.adjustTimeout(ms));
78
} catch (InterruptedException e) {
79
throw new RuntimeException(e);
80
}
81
}
82
83
// Phaser to sync between the main thread putting
84
// this thread into various states
85
private final Phaser phaser = new Phaser(2);
86
private volatile int newState = S_RUNNABLE;
87
private volatile int state = 0;
88
private boolean done = false;
89
90
private static final int S_RUNNABLE = 1;
91
private static final int S_BLOCKED = 2;
92
private static final int S_WAITING = 3;
93
private static final int S_TIMED_WAITING = 4;
94
private static final int S_PARKED = 5;
95
private static final int S_TIMED_PARKED = 6;
96
private static final int S_SLEEPING = 7;
97
private static final int S_TERMINATE = 8;
98
99
// for debugging
100
private final AtomicInteger iterations = new AtomicInteger();
101
private final AtomicInteger interrupted = new AtomicInteger();
102
103
private final LockFreeLogger logger = new LockFreeLogger();
104
105
@Override
106
public void run() {
107
// this thread has started
108
while (!done) {
109
// state transition
110
int nextState = state;
111
if (newState != state) {
112
nextState = newState;
113
iterations.set(0);
114
interrupted.set(0);
115
}
116
iterations.incrementAndGet();
117
switch (nextState) {
118
case S_RUNNABLE: {
119
stateChange(nextState);
120
double sum = 0;
121
for (int i = 0; i < 1000; i++) {
122
double r = Math.random();
123
double x = Math.pow(3, r);
124
sum += x - r;
125
}
126
break;
127
}
128
case S_BLOCKED: {
129
log("%d: %s is going to block (iterations %d)%n",
130
getId(), getName(), iterations.get());
131
stateChange(nextState);
132
// going to block on lock
133
synchronized (lock) {
134
log("%d: %s acquired the lock (iterations %d)%n",
135
getId(), getName(), iterations.get());
136
try {
137
// this thread has escaped the BLOCKED state
138
// release the lock and a short wait before continue
139
lock.wait(Utils.adjustTimeout(10));
140
} catch (InterruptedException e) {
141
// ignore
142
interrupted.incrementAndGet();
143
}
144
}
145
break;
146
}
147
case S_WAITING: {
148
synchronized (lock) {
149
log("%d: %s is going to waiting (iterations %d interrupted %d)%n",
150
getId(), getName(), iterations.get(), interrupted.get());
151
try {
152
stateChange(nextState);
153
lock.wait();
154
log("%d: %s wakes up from waiting (iterations %d interrupted %d)%n",
155
getId(), getName(), iterations.get(), interrupted.get());
156
} catch (InterruptedException e) {
157
// ignore
158
interrupted.incrementAndGet();
159
}
160
}
161
break;
162
}
163
case S_TIMED_WAITING: {
164
synchronized (lock) {
165
log("%d: %s is going to timed waiting (iterations %d interrupted %d)%n",
166
getId(), getName(), iterations.get(), interrupted.get());
167
try {
168
stateChange(nextState);
169
lock.wait(Integer.MAX_VALUE);
170
log("%d: %s wakes up from timed waiting (iterations %d interrupted %d)%n",
171
getId(), getName(), iterations.get(), interrupted.get());
172
} catch (InterruptedException e) {
173
// ignore
174
interrupted.incrementAndGet();
175
}
176
}
177
break;
178
}
179
case S_PARKED: {
180
log("%d: %s is going to park (iterations %d)%n",
181
getId(), getName(), iterations.get());
182
stateChange(nextState);
183
LockSupport.park();
184
break;
185
}
186
case S_TIMED_PARKED: {
187
log("%d: %s is going to timed park (iterations %d)%n",
188
getId(), getName(), iterations.get());
189
long deadline = System.currentTimeMillis() +
190
Utils.adjustTimeout(10000*1000);
191
stateChange(nextState);
192
LockSupport.parkUntil(deadline);
193
break;
194
}
195
case S_SLEEPING: {
196
log("%d: %s is going to sleep (iterations %d interrupted %d)%n",
197
getId(), getName(), iterations.get(), interrupted.get());
198
try {
199
stateChange(nextState);
200
Thread.sleep(Utils.adjustTimeout(1000000));
201
} catch (InterruptedException e) {
202
// finish sleeping
203
interrupted.incrementAndGet();
204
}
205
break;
206
}
207
case S_TERMINATE: {
208
done = true;
209
stateChange(nextState);
210
break;
211
}
212
default:
213
break;
214
}
215
}
216
}
217
218
/**
219
* Change the state if it matches newState.
220
*/
221
private void stateChange(int nextState) {
222
// no state change
223
if (state == nextState)
224
return;
225
226
// transition to the new state
227
if (newState == nextState) {
228
state = nextState;
229
phaser.arrive();
230
log("%d: state change: %s %s%n",
231
getId(), toStateName(nextState), phaserToString(phaser));
232
return;
233
}
234
235
// should never reach here
236
throw new RuntimeException("current " + state + " next " + nextState +
237
" new state " + newState);
238
}
239
240
/**
241
* Blocks until this thread transitions to the given state
242
*/
243
public void transitionTo(Thread.State tstate) throws InterruptedException {
244
switch (tstate) {
245
case RUNNABLE:
246
nextState(S_RUNNABLE);
247
break;
248
case BLOCKED:
249
nextState(S_BLOCKED);
250
break;
251
case WAITING:
252
nextState(S_WAITING);
253
break;
254
case TIMED_WAITING:
255
nextState(S_TIMED_WAITING);
256
break;
257
case TERMINATED:
258
nextState(S_TERMINATE);
259
break;
260
default:
261
break;
262
}
263
}
264
265
/**
266
* Blocks until this thread transitions to sleeping
267
*/
268
public void transitionToSleep() throws InterruptedException {
269
nextState(S_SLEEPING);
270
}
271
272
/**
273
* Blocks until this thread transitions to park or timed park
274
*/
275
public void transitionToPark(boolean timed) throws InterruptedException {
276
nextState(timed ? S_TIMED_PARKED : S_PARKED);
277
}
278
279
private void nextState(int s) throws InterruptedException {
280
final long id = Thread.currentThread().getId();
281
log("%d: wait until the thread transitions to %s %s%n",
282
id, toStateName(s), phaserToString(phaser));
283
this.newState = s;
284
int phase = phaser.arrive();
285
log("%d: awaiting party arrive %s %s%n",
286
id, toStateName(s), phaserToString(phaser));
287
for (;;) {
288
// when this thread has changed its state before it waits or parks
289
// on a lock, a potential race might happen if it misses the notify
290
// or unpark. Hence await for the phaser to advance with timeout
291
// to cope with this race condition.
292
switch (state) {
293
case S_WAITING:
294
case S_TIMED_WAITING:
295
synchronized (lock) {
296
lock.notify();
297
}
298
break;
299
case S_PARKED:
300
case S_TIMED_PARKED:
301
LockSupport.unpark(this);
302
break;
303
case S_SLEEPING:
304
this.interrupt();
305
break;
306
case S_BLOCKED:
307
default:
308
break;
309
}
310
try {
311
phaser.awaitAdvanceInterruptibly(phase, 100, TimeUnit.MILLISECONDS);
312
log("%d: arrived at %s %s%n",
313
id, toStateName(s), phaserToString(phaser));
314
return;
315
} catch (TimeoutException ex) {
316
// this thread hasn't arrived at this phase
317
log("%d: Timeout: %s%n", id, phaser);
318
}
319
}
320
}
321
322
private String phaserToString(Phaser p) {
323
return "[phase = " + p.getPhase() +
324
" parties = " + p.getRegisteredParties() +
325
" arrived = " + p.getArrivedParties() + "]";
326
}
327
328
private String toStateName(int state) {
329
switch (state) {
330
case S_RUNNABLE:
331
return "runnable";
332
case S_WAITING:
333
return "waiting";
334
case S_TIMED_WAITING:
335
return "timed waiting";
336
case S_PARKED:
337
return "parked";
338
case S_TIMED_PARKED:
339
return "timed parked";
340
case S_SLEEPING:
341
return "sleeping";
342
case S_BLOCKED:
343
return "blocked";
344
case S_TERMINATE:
345
return "terminated";
346
default:
347
return "unknown " + state;
348
}
349
}
350
351
private void log(String msg, Object ... params) {
352
logger.log(msg, params);
353
}
354
355
/**
356
* Waits for the controller to complete the test run and returns the
357
* generated log
358
* @return The controller log
359
* @throws InterruptedException
360
*/
361
public String getLog() throws InterruptedException {
362
return getLog(0);
363
}
364
365
/**
366
* Waits at most {@code millis} milliseconds for the controller
367
* to complete the test run and returns the generated log.
368
* A timeout of {@code 0} means to wait forever.
369
*/
370
public String getLog(long millis) throws InterruptedException {
371
this.join(millis);
372
373
return logger.toString();
374
}
375
}
376
377