Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ThreadController.java
40948 views
1
/*
2
* Copyright (c) 2003, 2018, 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
package nsk.monitoring.share;
25
26
import java.lang.management.*;
27
import java.util.*;
28
29
import nsk.share.*;
30
31
/**
32
* The <code>ThreadController</code> class allows to operate with threads.
33
*/
34
public class ThreadController extends StateController {
35
36
/**
37
* Type of threads: pure java.
38
*/
39
static public final int JAVA_TYPE = 0;
40
41
/**
42
* Type of threads: native.
43
*/
44
static public final int NATIVE_TYPE = 1;
45
46
/**
47
* Type of threads: both java and native.
48
*/
49
static public final int MIXED_TYPE = 2;
50
51
/**
52
* Result code: no errors.
53
*/
54
static public final int NO_ERROR = 0;
55
56
/**
57
* Result code: wrong state of the thread.
58
*/
59
static public final int ERR_STATE = 1;
60
61
/**
62
* Result code: error in stack trace.
63
*/
64
static public final int ERR_STACKTRACE = 2;
65
66
/**
67
* Result code: thread not found.
68
*/
69
static public final int ERR_THREAD_NOTFOUND = 3;
70
71
72
// Prefix to print while logging
73
static final String LOG_PREFIX = "ThreadController> ";
74
75
// Internal trace levels
76
static final int THREAD_TRACE_LEVEL = 50;
77
78
/**
79
* Suffix of all started threads.
80
*/
81
static final String THREAD_SUFFIX = "_ThreadMM";
82
83
// Number of tested kinds of threads
84
public static final int THREAD_KIND_COUNT = 4;
85
86
/**
87
* Index of blocked threads.
88
*/
89
static public final int BLOCKED_IDX = 0;
90
91
/**
92
* Index of waiting threads.
93
*/
94
static public final int WAITING_IDX = 1;
95
96
/**
97
* Index of sleeping threads.
98
*/
99
static public final int SLEEPING_IDX = 2;
100
101
/**
102
* Index of running threads.
103
*/
104
static public final int RUNNING_IDX = 3;
105
106
public static final String[] THREAD_KIND_NAMES = {"BLOCKED","WAITING","SLEEPING","RUNNABLE"};
107
public static final Thread.State[] THREAD_KINDS = {Thread.State.BLOCKED, Thread.State.WAITING, Thread.State.TIMED_WAITING, Thread.State.RUNNABLE};
108
109
private Map<Thread.State, Integer> threadsCount = new HashMap<Thread.State, Integer>();
110
private Map<Thread.State, List<BaseThread>> threadsClusters = new HashMap<Thread.State, List<BaseThread>>();
111
112
private ThreadsGroupLocks threadsGroupLocks;
113
114
115
int maxDepth;
116
static int invocationType;
117
118
static {
119
try {
120
System.loadLibrary("ThreadController");
121
} catch (UnsatisfiedLinkError e) {
122
System.err.println("Could not load \"ThreadController\" "
123
+ "library");
124
System.err.println("java.library.path:"
125
+ System.getProperty("java.library.path"));
126
throw e;
127
}
128
}
129
130
/**
131
* Creates a new <code>ThreadController</code> object with defined
132
* arguments..
133
*
134
* @param log <code>Log</code> object to print info to.
135
* @param threadCount number of threads to start.
136
* @param maxDepth depth of recursion.
137
* @param invocationType type of threads to start (java, native, or mixed).
138
*/
139
public ThreadController(Log log, int threadCount, int maxDepth,
140
String invocationType) {
141
logPrefix = LOG_PREFIX;
142
setLog(log);
143
setThreadCount(threadCount);
144
setDepth(maxDepth);
145
setInvocationType(invocationType);
146
}
147
148
149
// Calculate how many threads of each kind to start
150
private void setThreadCount(int threadCount) {
151
int total = 0;
152
int kinds = THREAD_KIND_COUNT;
153
int tmp = threadCount / kinds;
154
int rest = threadCount % kinds;
155
int increased = kinds - rest;
156
for (int i = 0; i < kinds; i++) {
157
if (i >= increased) {
158
threadsCount.put(THREAD_KINDS[i], tmp + 1);
159
} else {
160
threadsCount.put(THREAD_KINDS[i], tmp);
161
}
162
}
163
display("number of created threads:\t" + threadCount);
164
}
165
166
// Print thread count
167
private void printThreadCount() {
168
for (Thread.State state : THREAD_KINDS) {
169
display("\t" + state + " threads ("
170
+ threadsCount.get(state) + ")");
171
}
172
}
173
174
// Set recursion depth
175
private void setDepth(int depth) {
176
maxDepth = depth;
177
display("depth for all threads:\t" + maxDepth);
178
}
179
180
// Set invocation type
181
private void setInvocationType(String value) {
182
display("invocation type:\t" + value);
183
if (value.equals(ArgumentHandler.JAVA_TYPE)) {
184
invocationType = JAVA_TYPE;
185
} else if (value.equals(ArgumentHandler.NATIVE_TYPE)) {
186
invocationType = NATIVE_TYPE;
187
} else if (value.equals(ArgumentHandler.MIXED_TYPE)) {
188
invocationType = MIXED_TYPE;
189
} else {
190
throw new Failure("UNKNOWN invocation type");
191
}
192
}
193
194
/**
195
* Returns invocation type.
196
*
197
* @return invocation type.
198
*/
199
public int getInvocationType() {
200
return invocationType;
201
}
202
203
/**
204
* Returns thread count.
205
*
206
* @param state kind of thread state
207
* @return thread count.
208
*/
209
public int getThreadCount(Thread.State state) {
210
return threadsCount.get(state);
211
}
212
213
/**
214
* Returns thread count.
215
*
216
* @param kindIndex of thread state
217
* @return thread count.
218
*/
219
public int getThreadCount(int kindIndex) {
220
return threadsCount.get(THREAD_KINDS[kindIndex]);
221
}
222
223
public int getThreadKindCount() {
224
return THREAD_KINDS.length;
225
}
226
227
228
/**
229
* Brings out VM into defined state.
230
* <p/>
231
* The method starts all threads.
232
*/
233
public void run() {
234
long startTime = System.currentTimeMillis() / 1000;
235
startThreads();
236
display("locking threads");
237
waitForThreads();
238
}
239
240
/**
241
* Tries to return VM into initial state
242
* <p/>
243
* The method interrupts all threads.
244
*/
245
public void reset() {
246
for (Thread.State state : THREAD_KINDS) {
247
threadsGroupLocks.releaseGroup(state);
248
}
249
}
250
251
// Get thread state via JVMTI
252
private native Thread.State getThreadState(Thread thread);
253
254
// Start all threads
255
private void startThreads() throws Failure {
256
257
String tmp_name;
258
BaseThread thread = null;
259
260
threadsGroupLocks = new ThreadsGroupLocks(threadsCount, logger);
261
for (Thread.State state : THREAD_KINDS) {
262
threadsClusters.put(state, new ArrayList<BaseThread>());
263
for (int j = 0; j < threadsCount.get(state); j++) {
264
tmp_name = state + THREAD_SUFFIX + int2Str(j);
265
switch (state) {
266
case BLOCKED:
267
thread = new BlockedThread(this, tmp_name, logger.getLog(), threadsGroupLocks);
268
break;
269
case WAITING:
270
thread = new WaitingThread(this, tmp_name, logger.getLog(), threadsGroupLocks);
271
break;
272
case TIMED_WAITING:
273
thread = new SleepingThread(this, tmp_name, logger.getLog(), threadsGroupLocks);
274
break;
275
case RUNNABLE:
276
thread = new RunningThread(this, tmp_name, logger.getLog(), threadsGroupLocks);
277
break;
278
default:
279
throw new TestBug("Unknow thread kind");
280
}
281
threadsClusters.get(state).add(thread);
282
thread.start();
283
}
284
}
285
waitForThreads();
286
}
287
288
private boolean checkState(Thread.State expectedState) {
289
for (Thread thread : threadsClusters.get(expectedState)) {
290
if (getThreadState(thread) != expectedState) {
291
292
return false;
293
}
294
}
295
return true;
296
}
297
298
private void waitForThreads() {
299
for (Thread.State state : THREAD_KINDS) {
300
threadsGroupLocks.waitForGroup(state);
301
while (!checkState(state)) {
302
Thread.yield();
303
}
304
}
305
}
306
307
308
/**
309
* Finds a thread with defined id.
310
*
311
* @param id ID of the thread.
312
* @return a thread with defined id.
313
*/
314
public BaseThread findThread(long id) {
315
for(Thread.State state:THREAD_KINDS){
316
for(BaseThread thread:threadsClusters.get(state)){
317
if (id==thread.getId()) {
318
return thread;
319
}
320
}
321
}
322
return null;
323
}
324
325
/**
326
* Finds a thread by name.
327
*
328
* @param name name of the thread.
329
* @return a thread with defined name.
330
*/
331
public BaseThread findThread(String name) {
332
for(Thread.State state:THREAD_KINDS){
333
for(BaseThread thread:threadsClusters.get(state)){
334
if (name.equals(thread.getName())) {
335
return thread;
336
}
337
}
338
}
339
return null;
340
}
341
342
/**
343
* Checks the thread's <code>ThreadInfo</code>.
344
*
345
* @param info <code>ThreadInfo</code> object to test.
346
* @return result code.
347
* @see #NO_ERROR
348
* @see #ERR_THREAD_NOTFOUND
349
* @see #ERR_STATE
350
* @see #ERR_STACKTRACE
351
*/
352
public int checkThreadInfo(ThreadInfo info) {
353
String name = info.getThreadName();
354
355
if (name.indexOf(THREAD_SUFFIX) == -1) {
356
return NO_ERROR;
357
}
358
359
long id = info.getThreadId();
360
Thread.State state = info.getThreadState();
361
StackTraceElement[] stackTrace = info.getStackTrace();
362
363
BaseThread thrd = findThread(id);
364
if (thrd == null) {
365
return ERR_THREAD_NOTFOUND;
366
}
367
368
if (!thrd.checkState(state))
369
return ERR_STATE;
370
371
if (!thrd.checkStackTrace(stackTrace))
372
return ERR_STACKTRACE;
373
374
return NO_ERROR;
375
}
376
}
377
378
abstract class BaseThread extends Thread {
379
380
private int currentDepth = 0;
381
private String logPrefix;
382
protected Log.Logger logger;
383
384
protected ThreadController controller;
385
386
protected List<String> expectedMethods = new ArrayList<String>();
387
protected int expectedLength;
388
389
protected ThreadsGroupLocks threadsGroupLocks;
390
391
static {
392
if (ThreadController.invocationType == ThreadController.NATIVE_TYPE ||
393
ThreadController.invocationType == ThreadController.MIXED_TYPE) {
394
try {
395
System.loadLibrary("ThreadController");
396
} catch (UnsatisfiedLinkError e) {
397
System.err.println("Could not load \"ThreadController\" "
398
+ "library");
399
System.err.println("java.library.path:"
400
+ System.getProperty("java.library.path"));
401
throw e;
402
}
403
}
404
}
405
406
public BaseThread(ThreadController controller, String name, Log log, ThreadsGroupLocks threadsGroupLocks) {
407
super(name);
408
this.controller = controller;
409
int pos = controller.LOG_PREFIX.indexOf('>');
410
logPrefix = controller.LOG_PREFIX.substring(0, pos) + "::"
411
+ name + "> ";
412
setLog(log);
413
this.threadsGroupLocks = threadsGroupLocks;
414
415
expectedLength = 1 + controller.maxDepth + 1;
416
if(controller.invocationType == ThreadController.MIXED_TYPE) {
417
//nativeRecursiveMethod
418
expectedLength ++;
419
}
420
421
expectedMethods.add(BaseThread.class.getName() + ".run");
422
423
switch (controller.invocationType) {
424
case ThreadController.JAVA_TYPE:
425
expectedMethods.add(BaseThread.class.getName() + ".recursiveMethod");
426
break;
427
case ThreadController.NATIVE_TYPE:
428
expectedMethods.add(BaseThread.class.getName() + ".nativeRecursiveMethod");
429
break;
430
case ThreadController.MIXED_TYPE:
431
expectedMethods.add(BaseThread.class.getName() + ".recursiveMethod");
432
expectedMethods.add(BaseThread.class.getName() + ".nativeRecursiveMethod");
433
}
434
435
expectedMethods.add(ThreadsGroupLocks.PlainCountDownLatch.class.getName() + ".countDown");
436
}
437
438
public void run() {
439
try {
440
switch (controller.invocationType) {
441
case ThreadController.JAVA_TYPE:
442
case ThreadController.MIXED_TYPE:
443
recursiveMethod();
444
break;
445
case ThreadController.NATIVE_TYPE:
446
nativeRecursiveMethod();
447
break;
448
default:
449
throw new Failure("unknown invocationType:"
450
+ controller.invocationType);
451
}
452
} catch (StackOverflowError e) {
453
logger.complain(e.toString());
454
throw new RuntimeException(e);
455
}
456
logger.trace(controller.THREAD_TRACE_LEVEL, "thread finished");
457
}
458
459
protected abstract void bringState();
460
461
public abstract State getState();
462
463
protected abstract void nativeBringState();
464
465
public abstract boolean checkState(Thread.State state);
466
467
public boolean checkStackTrace(StackTraceElement[] elements) {
468
boolean res = true;
469
470
logger.trace(controller.THREAD_TRACE_LEVEL, "trace elements: "
471
+ elements.length);
472
473
if (elements.length > expectedLength) {
474
res = false;
475
logger.complain("Contains " + elements.length + ", more then "
476
+ expectedLength + " elements");
477
}
478
479
for (int j = 0; j < elements.length; j++) {
480
if (!checkElement(elements[j])) {
481
logger.complain("Unexpected method name: "
482
+ elements[j].getMethodName()
483
+ " at " + j + " position");
484
if (elements[j].isNativeMethod()) {
485
logger.complain("\tline number: (native method)");
486
logger.complain("\tclass name: " + elements[j].getClassName());
487
} else {
488
logger.complain("\tline number: " + elements[j].getLineNumber());
489
logger.complain("\tclass name: " + elements[j].getClassName());
490
logger.complain("\tfile name: " + elements[j].getFileName());
491
}
492
res = false;
493
}
494
}
495
return res;
496
}
497
498
protected boolean checkElement(StackTraceElement element) {
499
String name = element.getClassName() + "." + element.getMethodName();
500
if (expectedMethods.contains(name)) {
501
return true;
502
}
503
504
logger.trace(controller.THREAD_TRACE_LEVEL, "\"" + name + "\""
505
+ " is not expected method name");
506
return false;
507
}
508
509
protected void recursiveMethod() {
510
currentDepth++;
511
512
if (controller.maxDepth - currentDepth > 0) {
513
514
Thread.yield();
515
try {
516
if (ThreadController.invocationType
517
== ThreadController.MIXED_TYPE) {
518
nativeRecursiveMethod();
519
} else {
520
recursiveMethod();
521
}
522
523
} catch (StackOverflowError e) {
524
logger.display(getName() + "> " + e);
525
}
526
527
} else if (controller.maxDepth == currentDepth) {
528
logger.trace(controller.THREAD_TRACE_LEVEL, "state has been "
529
+ "reached");
530
bringState();
531
}
532
currentDepth--;
533
}
534
535
protected native void nativeRecursiveMethod();
536
537
/**
538
* Defines <code>Log.Logger</code> object
539
*/
540
public void setLog(Log log) {
541
logger = new Log.Logger(log, logPrefix);
542
}
543
}
544
545
class BlockedThread extends BaseThread {
546
547
private static final Thread.State STATE = Thread.State.BLOCKED;
548
549
public State getState() {
550
return STATE;
551
}
552
553
public BlockedThread(ThreadController controller, String name, Log log, ThreadsGroupLocks threadsGroupLocks) {
554
super(controller, name, log, threadsGroupLocks);
555
556
this.threadsGroupLocks = threadsGroupLocks;
557
558
expectedLength += 2;
559
560
expectedMethods.add(ThreadsGroupLocks.Blocker.class.getName() + ".block");
561
562
switch (controller.invocationType) {
563
case ThreadController.JAVA_TYPE:
564
expectedMethods.add(BlockedThread.class.getName() + ".bringState");
565
break;
566
case ThreadController.NATIVE_TYPE:
567
expectedMethods.add(BlockedThread.class.getName() + ".nativeBringState");
568
break;
569
case ThreadController.MIXED_TYPE:
570
expectedMethods.add(BlockedThread.class.getName() + ".bringState");
571
572
}
573
}
574
575
protected void bringState() {
576
logger.trace(controller.THREAD_TRACE_LEVEL, "entering to monitor");
577
threadsGroupLocks.getBarrier(getState()).countDown();
578
threadsGroupLocks.blocker.block();
579
logger.trace(controller.THREAD_TRACE_LEVEL, "exiting from monitor");
580
}
581
582
protected native void nativeBringState();
583
584
public boolean checkState(Thread.State state) {
585
return state == Thread.State.BLOCKED;
586
}
587
}
588
589
class WaitingThread extends BaseThread {
590
591
private static final Thread.State STATE = Thread.State.WAITING;
592
public State getState() {
593
return STATE;
594
}
595
596
private ThreadsGroupLocks threadsGroupLocks;
597
598
public WaitingThread(ThreadController controller, String name, Log log, ThreadsGroupLocks threadsGroupLocks) {
599
super(controller, name, log, threadsGroupLocks);
600
601
this.threadsGroupLocks = threadsGroupLocks;
602
603
expectedLength += 4;
604
605
expectedMethods.add(ThreadsGroupLocks.PlainCountDownLatch.class.getName() + ".await");
606
expectedMethods.add(Object.class.getName() + ".wait");
607
608
switch (controller.invocationType) {
609
case ThreadController.JAVA_TYPE:
610
expectedMethods.add(WaitingThread.class.getName() + ".bringState");
611
break;
612
case ThreadController.NATIVE_TYPE:
613
expectedMethods.add(WaitingThread.class.getName() + ".nativeBringState");
614
break;
615
case ThreadController.MIXED_TYPE:
616
expectedMethods.add(WaitingThread.class.getName() + ".bringState");
617
618
}
619
}
620
621
622
protected void bringState() {
623
ThreadsGroupLocks.PlainCountDownLatch barrier = threadsGroupLocks.getBarrier(STATE);
624
try {
625
logger.trace(controller.THREAD_TRACE_LEVEL, "waiting on a monitor");
626
threadsGroupLocks.getBarrier(getState()).countDown();
627
barrier.await();
628
} catch (InterruptedException e) {
629
logger.display(e.toString());
630
}
631
}
632
633
protected native void nativeBringState();
634
635
public boolean checkState(Thread.State state) {
636
return state == STATE;
637
}
638
639
}
640
641
class SleepingThread extends BaseThread {
642
private static final Thread.State STATE = State.TIMED_WAITING;
643
644
public State getState() {
645
return STATE;
646
}
647
648
private ThreadsGroupLocks threadsGroupLocks;
649
650
public SleepingThread(ThreadController controller, String name, Log log, ThreadsGroupLocks threadsGroupLocks) {
651
super(controller, name, log, threadsGroupLocks);
652
653
this.threadsGroupLocks = threadsGroupLocks;
654
655
expectedLength += 3;
656
657
expectedMethods.add(Thread.class.getName() + ".sleep");
658
expectedMethods.add(SleepingThread.class.getName() + ".run");
659
660
switch (controller.invocationType) {
661
case ThreadController.JAVA_TYPE:
662
expectedMethods.add(SleepingThread.class.getName() + ".bringState");
663
break;
664
case ThreadController.NATIVE_TYPE:
665
expectedMethods.add(SleepingThread.class.getName() + ".nativeBringState");
666
break;
667
case ThreadController.MIXED_TYPE:
668
expectedMethods.add(SleepingThread.class.getName() + ".bringState");
669
}
670
671
}
672
673
protected void bringState() {
674
try {
675
threadsGroupLocks.getBarrier(getState()).countDown();
676
Thread.sleep(3600 * 1000);
677
} catch (InterruptedException e) {
678
logger.display(e.toString());
679
}
680
}
681
682
protected native void nativeBringState();
683
684
public boolean checkState(Thread.State state) {
685
return state == Thread.State.TIMED_WAITING;
686
}
687
688
public void run() {
689
try {
690
switch (controller.invocationType) {
691
case ThreadController.JAVA_TYPE:
692
case ThreadController.MIXED_TYPE:
693
recursiveMethod();
694
break;
695
case ThreadController.NATIVE_TYPE:
696
nativeRecursiveMethod();
697
break;
698
default:
699
throw new Failure("unknown invocationType:"
700
+ controller.invocationType);
701
}
702
logger.trace(controller.THREAD_TRACE_LEVEL, "thread finished");
703
} catch (StackOverflowError e) {
704
logger.complain(e.toString());
705
throw new RuntimeException(e);
706
}
707
}
708
}
709
710
class RunningThread extends BaseThread {
711
public State getState() {
712
return STATE;
713
}
714
715
private static final Thread.State STATE = Thread.State.RUNNABLE;
716
private ThreadsGroupLocks threadsGroupLocks;
717
718
public RunningThread(ThreadController controller, String name, Log log, ThreadsGroupLocks threadsGroupLocks) {
719
super(controller, name, log, threadsGroupLocks);
720
this.threadsGroupLocks = threadsGroupLocks;
721
722
expectedLength += 2;
723
724
expectedMethods.add(Thread.class.getName() + ".yield");
725
726
switch (controller.invocationType) {
727
case ThreadController.JAVA_TYPE:
728
expectedMethods.add(RunningThread.class.getName() + ".bringState");
729
break;
730
case ThreadController.NATIVE_TYPE:
731
expectedMethods.add(RunningThread.class.getName() + ".nativeBringState");
732
break;
733
case ThreadController.MIXED_TYPE:
734
expectedMethods.add(RunningThread.class.getName() + ".bringState");
735
}
736
}
737
738
protected void bringState() {
739
logger.trace(controller.THREAD_TRACE_LEVEL, "running loop");
740
threadsGroupLocks.getBarrier(getState()).countDown();
741
while (!threadsGroupLocks.runnableCanExit) {
742
Thread.yield();
743
}
744
}
745
746
protected native void nativeBringState();
747
748
public boolean checkState(Thread.State state) {
749
return state == Thread.State.RUNNABLE;
750
}
751
}
752
753
754
class ThreadsGroupLocks {
755
756
private Log.Logger logger;
757
758
//for all
759
private Map<Thread.State, PlainCountDownLatch> barriers = new HashMap<Thread.State, PlainCountDownLatch>();
760
761
//for Blocked
762
public final Blocker blocker = new Blocker();
763
764
//for Runnable
765
public volatile boolean runnableCanExit = false;
766
767
public ThreadsGroupLocks(Map<Thread.State, Integer> threadsCount, Log.Logger logger) {
768
this.logger = logger;
769
for (Thread.State state : threadsCount.keySet()) {
770
if (state == Thread.State.WAITING) {
771
barriers.put(state, new PlainCountDownLatch(threadsCount.get(state) + 1));
772
} else {
773
barriers.put(state, new PlainCountDownLatch(threadsCount.get(state)));
774
}
775
}
776
blocker.startBlocker();
777
}
778
779
public PlainCountDownLatch getBarrier(Thread.State state) {
780
return barriers.get(state);
781
}
782
783
public void waitForGroup(Thread.State stateGroup) {
784
switch (stateGroup) {
785
case BLOCKED:
786
case RUNNABLE:
787
case TIMED_WAITING:
788
try {
789
barriers.get(stateGroup).await();
790
} catch (InterruptedException e) {
791
logger.display(e.toString());
792
}
793
break;
794
795
case WAITING:
796
while (barriers.get(stateGroup).getCount() != 1) {
797
Thread.yield();
798
}
799
break;
800
}
801
}
802
803
public void releaseGroup(Thread.State stateGroup) {
804
switch (stateGroup) {
805
case BLOCKED:
806
blocker.unBlock();
807
break;
808
case RUNNABLE:
809
runnableCanExit = true;
810
break;
811
case TIMED_WAITING:
812
case WAITING:
813
barriers.get(stateGroup).countDown();
814
break;
815
}
816
}
817
818
public class Blocker {
819
820
private Object monitor = new Object();
821
private PlainCountDownLatch blockerCanExit = new PlainCountDownLatch(1);
822
private PlainCountDownLatch blockerStart = new PlainCountDownLatch(1);
823
824
private Runnable blockerThread = new Runnable() {
825
public void run() {
826
synchronized (monitor) {
827
blockerStart.countDown();
828
try {
829
blockerCanExit.await();
830
} catch (InterruptedException e) {
831
logger.display(e.toString());
832
}
833
834
}
835
}
836
};
837
838
public void startBlocker() {
839
new Thread(blockerThread, "Blocker").start();
840
}
841
842
public void block() {
843
try {
844
blockerStart.await();
845
} catch (InterruptedException e) {
846
logger.complain(e.toString());
847
}
848
synchronized (monitor) {
849
}
850
}
851
852
public void unBlock() {
853
blockerCanExit.countDown();
854
}
855
}
856
857
public static class PlainCountDownLatch {
858
private volatile int counter;
859
private Object counterMonitor = new Object();
860
861
public PlainCountDownLatch(int counter){
862
this.counter = counter;
863
}
864
865
public void countDown(){
866
synchronized (counterMonitor) {
867
counter--;
868
if(counter==0) {
869
counterMonitor.notifyAll();
870
}
871
}
872
}
873
874
public void await() throws InterruptedException{
875
synchronized (counterMonitor){
876
while(counter != 0){
877
counterMonitor.wait();
878
}
879
}
880
}
881
882
public int getCount(){
883
synchronized (counterMonitor) {
884
return counter;
885
}
886
}
887
}
888
889
}
890
891