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