1 /*
2  * Copyright (c) 2011, 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.atomic.AtomicInteger;
25 import java.util.concurrent.BrokenBarrierException;
26 import java.util.concurrent.CyclicBarrier;
27 
28 
29 /**
30  * RacingThreadsTest is a support class for creating a test
31  * where multiple threads are needed to exercise a code path.
32  * The RacingThreadsTest class is typically used as follows:
33  * <ul>
34  * <li>
35  *     Extend RacingThreadsTest class in order to provide the test
36  *     specific variables and/or code, e.g., <br>
37  *     public class MyRacingThreadsTest extends RacingThreadsTest
38  * <li>
39  *     Use
40  *     "new MyRacingThreadsTest(name, n_threads, n_loops, n_secs)"
41  *     to create your test with the specified name and the specified
42  *     number of WorkerThreads that execute the test code in parallel
43  *     up to n_loops iterations or n_secs seconds.
44  * <li>
45  *     Use
46  *     "new DriverThread(test)"
47  *     to create the test DriverThread that manages all the
48  *     WorkerThreads. The DriverThread class can be extended to
49  *     provide test specific code and/or variables. However, that
50  *     is typically done in your test's subclass.
51  * <li>
52  *     Use
53  *     "new WorkerThread(workerNum, test)"
54  *     to create WorkerThread-workerNum that executes the test code.
55  *     The WorkerThread class can be extended to provide test thread
56  *     specific code and/or variables.
57  * <li>
58  *     Use
59  *     "RacingThreadsTest.runTest(driver, workers)"
60  *     to run the test. If the test fails, then a RuntimeException
61  *     is thrown.
62  * </ul>
63  *
64  * The RacingThreadsTest class provides many methods that can be
65  * overridden in order to provide test specific semantics at each
66  * identified test execution point. At a minimum, your test's
67  * subclass needs to override the
68  * "void executeRace(WorkerThread)"
69  * method in order to exercise your race condition and it needs to
70  * override the
71  * "void checkRaceResults(DriverThread)"
72  * method in order to check the results of the race. Your
73  * checkRaceResults() method should call the
74  * "int incAndGetFailCnt()"
75  * method when it detects a failure. It can also call the
76  * "void unexpectedException(Thread, Exception)"
77  * method if it detects an unexpected exception; this will cause
78  * an error message to be output and the failure count to be
79  * incremented. When the RacingThreadsTest.runTest() method is
80  * done running the races, if there is a non-zero failure count,
81  * then a RuntimeException will be thrown.
82  * <p>
83  * The RacingThreadsTest class uses three internal barriers to
84  * coordinate actions between the DriverThread and the WorkerThreads.
85  * These barriers should not be managed or used by your test's
86  * subclass and are only mentioned here to provide clarity about
87  * interactions between the DriverThread and the WorkerThreads.
88  * The following transaction diagram shows when the different
89  * RacingThreadsTest methods are called relative to the different
90  * barriers:
91  *
92  * <pre>
93  * DriverThread           WorkerThread-0         WorkerThread-N-1
94  * ---------------------  ---------------------  ---------------------
95  * run(workers)
96  * oneTimeDriverInit()
97  * &lt;start WorkerThreads&gt;  run()                  run()
98  * &lt;top of race loop&gt;     :                      :
99  * perRaceDriverInit()    oneTimeWorkerInit()    oneTimeWorkerInit()
100  * :                      &lt;top of race loop&gt;     &lt;top of race loop&gt;
101  * :                      perRaceWorkerInit()    perRaceWorkerInit()
102  * startBarrier           startBarrier           startBarrier
103  * :                      executeRace()          executeRace()
104  * finishBarrier          finishBarrier          finishBarrier
105  * checkRaceResults()     :                      :
106  * resetBarrier           resetBarrier           resetBarrier
107  * perRaceDriverEpilog()  perRaceWorkerEpilog()  perRaceWorkerEpilog()
108  * &lt;repeat race or done&gt;  &lt;repeat race or done&gt;  &lt;repeat race or done&gt;
109  * :                      oneTimeWorkerEpilog()  oneTimeWorkerEpilog()
110  * &lt;join WorkerThreads&gt;   &lt;WorkerThread ends&gt;    &lt;WorkerThread ends&gt;
111  * oneTimeDriverEpilog()
112  * &lt;DriverThread ends&gt;
113  * </pre>
114  *
115  * Just to be clear about the parallel parts of this infrastructure:
116  * <ul>
117  * <li>
118  *     After the DriverThread starts the WorkerThreads, the DriverThread
119  *     and the WorkerThreads are running in parallel until the startBarrier
120  *     is reached.
121  * <li>
122  *     After the WorkerThreads leave the startBarrier, they are running
123  *     the code in executeRace() in parallel which is the whole point
124  *     of this class.
125  * <li>
126  *     The DriverThread heads straight to the finishBarrier and waits for
127  *     the WorkerThreads to get there.
128  * <li>
129  *     After the DriverThread leaves the finishBarrier, it checks the
130  *     results of the race.
131  * <li>
132  *     The WorkerThreads head straight to the resetBarrier and wait for
133  *     the DriverThread to get there.
134  * <li>
135  *     If this is not the last race, then after the DriverThread and
136  *     WorkerThreads leave the resetBarrier, the DriverThread and the
137  *     WorkerThreads are running in parallel until the startBarrier
138  *     is reached.
139  * <li>
140  *     If this is the last race, then after the DriverThread and
141  *     WorkerThreads leave the resetBarrier, the DriverThread and the
142  *     WorkerThreads are running in parallel as each WorkerThread ends.
143  * <li>
144  *     The DriverThread waits for the WorkerThreads to end and
145  *     then it ends
146  * </ul>
147  *
148  * Once the DriverThread has ended, the RacingThreadsTest.runTest()
149  * method checks the failure count. If there were no failures, then
150  * a "Test PASSed" message is printed. Otherwise, the failure count
151  * is printed, a "Test FAILed" message is printed and a RuntimeException
152  * is thrown.
153  */
154 public class RacingThreadsTest {
155     /**
156      * name of the test
157      */
158     public final String TEST_NAME;
159     /**
160      * maximum number of test iterations (race loops)
161      */
162     public final int N_LOOPS;
163     /**
164      * the maximum number of seconds to execute the test loop
165      */
166     public final int N_SECS;
167     /**
168      * number of WorkerThreads
169      */
170     public final int N_THREADS;
171 
172     /**
173      * Creates a test with the specified name and the specified number
174      * of WorkerThreads that execute the test code in parallel up to
175      * n_loops iterations or n_secs seconds. The RacingThreadsTest
176      * class is extended in order to provide the test specific variables
177      * and/or code.
178      * @param name the name of the test
179      * @param n_threads the number of WorkerThreads
180      * @param n_loops the maximum number of test iterations
181      * @param n_secs the maximum number of seconds to execute the test loop
182      */
RacingThreadsTest(String name, int n_threads, int n_loops, int n_secs)183     RacingThreadsTest(String name, int n_threads, int n_loops, int n_secs) {
184         TEST_NAME = name;
185         N_THREADS = n_threads;
186         N_LOOPS = n_loops;
187         N_SECS = n_secs;
188 
189         finishBarrier = new CyclicBarrier(N_THREADS + 1);
190         resetBarrier = new CyclicBarrier(N_THREADS + 1);
191         startBarrier = new CyclicBarrier(N_THREADS + 1);
192     }
193 
194 
195     /**
196      * Entry point for exercising the RacingThreadsTest class.
197      */
main(String[] args)198     public static void main(String[] args) {
199         // a dummy test:
200         // - 2 threads
201         // - 3 loops
202         // - 2 seconds
203         // - standard DriverThread
204         // - standard WorkerThread
205         RacingThreadsTest test = new RacingThreadsTest("dummy", 2, 3, 2);
206         DriverThread driver = new DriverThread(test);
207         WorkerThread[] workers = new WorkerThread[2];
208         for (int i = 0; i < workers.length; i++) {
209             workers[i] = new WorkerThread(i, test);
210         }
211         test.runTest(driver, workers);
212     }
213 
214     private static volatile boolean done = false;  // test done flag
215 
216     // # of fails; AtomicInteger since any WorkerThread can increment
217     private static final AtomicInteger failCnt = new AtomicInteger();
218     // # of loops; volatile is OK since only DriverThread increments
219     // but using AtomicInteger for consistency
220     private static final AtomicInteger loopCnt = new AtomicInteger();
221     private static boolean verbose
222         = Boolean.getBoolean("RacingThreadsTest.verbose");
223 
224     // barriers for starting, finishing and resetting the race
225     private final CyclicBarrier finishBarrier;
226     private final CyclicBarrier resetBarrier;
227     private final CyclicBarrier startBarrier;
228 
229 
230     /**
231      * Get current done flag value.
232      * @return the current done flag value
233      */
getDone()234     public boolean getDone() {
235         return done;
236     }
237 
238     /**
239      * Set done flag to specified value.
240      * @param v the new done flag value
241      */
setDone(boolean v)242     public void setDone(boolean v) {
243         done = v;
244     }
245 
246     /**
247      * Get current failure counter value.
248      * @return the current failure count
249      */
getFailCnt()250     public int getFailCnt() {
251         return failCnt.get();
252     }
253 
254     /**
255      * Increment and get current failure counter value.
256      * @return the current failure count after incrementing
257      */
incAndGetFailCnt()258     public int incAndGetFailCnt() {
259         return failCnt.incrementAndGet();
260     }
261 
262     /**
263      * Get current loop counter value.
264      * @return the current loop count
265      */
getLoopCnt()266     public int getLoopCnt() {
267         return loopCnt.get();
268     }
269 
270     /**
271      * Increment and get current loop counter value.
272      * @return the current loop count after incrementing
273      */
incAndGetLoopCnt()274     public int incAndGetLoopCnt() {
275         return loopCnt.incrementAndGet();
276     }
277 
278     /**
279      * Get current verbose flag value.
280      * @return the current verbose flag value
281      */
getVerbose()282     public boolean getVerbose() {
283         return verbose;
284     }
285 
286     /**
287      * Set verbose flag to specified value.
288      * @param v the new verbose flag value
289      */
setVerbose(boolean v)290     public void setVerbose(boolean v) {
291         verbose = v;
292     }
293 
294     /**
295      * Run the test with the specified DriverThread and the
296      * specified WorkerThreads.
297      * @param driver the DriverThread for running the test
298      * @param workers the WorkerThreads for executing the race
299      * @exception RuntimeException the test has failed
300      */
runTest(DriverThread driver, WorkerThread[] workers)301     public void runTest(DriverThread driver, WorkerThread[] workers) {
302         driver.run(workers);
303 
304         try {
305             driver.join();
306         } catch (InterruptedException ie) {
307             unexpectedException(Thread.currentThread(), ie);
308             // fall through to test failed below
309         }
310 
311         if (failCnt.get() == 0) {
312             System.out.println(TEST_NAME + ": Test PASSed.");
313         } else {
314             System.out.println(TEST_NAME + ": failCnt=" + failCnt.get());
315             System.out.println(TEST_NAME + ": Test FAILed.");
316             throw new RuntimeException("Test Failed");
317         }
318     }
319 
320     /**
321      * Helper method for reporting an unexpected Exception and
322      * calling incAndGetFailCnt();
323      * @param t the Thread that caught the exception
324      * @param e the Exception that was caught
325      */
unexpectedException(Thread t, Exception e)326     public void unexpectedException(Thread t, Exception e) {
327         System.err.println(t.getName() + ": ERROR: unexpected exception: " + e);
328         incAndGetFailCnt();  // ignore return
329     }
330 
331 
332     // The following methods are typically overridden by the subclass
333     // of RacingThreadsTest to provide test specific semantics at each
334     // identified test execution point:
335 
336     /**
337      * Initialize 1-time items for the DriverThread.
338      * Called by the DriverThread before WorkerThreads are started.
339      * @param dt the DriverThread
340      */
oneTimeDriverInit(DriverThread dt)341     public void oneTimeDriverInit(DriverThread dt) {
342         if (verbose)
343             System.out.println(dt.getName() + ": oneTimeDriverInit() called");
344     }
345 
346     /**
347      * Initialize 1-time items for a WorkerThread. Called by a
348      * WorkerThread after oneTimeDriverInit() and before the
349      * WorkerThread checks in with startBarrier. May execute in
350      * parallel with perRaceDriverInit() or with another
351      * WorkerThread's oneTimeWorkerInit() call or another
352      * WorkerThread's perRaceWorkerInit() call.
353      * @param wt the WorkerThread
354      */
oneTimeWorkerInit(WorkerThread wt)355     public void oneTimeWorkerInit(WorkerThread wt) {
356         if (verbose)
357             System.out.println(wt.getName() + ": oneTimeWorkerInit() called");
358     }
359 
360     /**
361      * Initialize per-race items for the DriverThread. Called by the
362      * DriverThread before it checks in with startBarrier. May execute
363      * in parallel with oneTimeWorkerInit() and perRaceWorkerInit()
364      * calls. After any race except for the last race, this method may
365      * execute in parallel with perRaceWorkerEpilog().
366      * @param dt the DriverThread
367      */
perRaceDriverInit(DriverThread dt)368     public void perRaceDriverInit(DriverThread dt) {
369         if (verbose)
370             System.out.println(dt.getName() + ": perRaceDriverInit() called");
371     }
372 
373     /**
374      * Initialize per-race items for a WorkerThread. Called by each
375      * WorkerThread before it checks in with startBarrier. On the first
376      * call, this method may execute in parallel with another
377      * WorkerThread's oneTimeWorkerInit() call. On any call, this method
378      * may execute in parallel with perRaceDriverInit() or another
379      * WorkerThread's perRaceWorkerInit() call. After any race except
380      * for the last race, this method may execute in parallel with
381      * perRaceDriverEpilog() or another WorkerThread's
382      * perRaceWorkerEpilog() call.
383      * @param wt the WorkerThread
384      */
perRaceWorkerInit(WorkerThread wt)385     public void perRaceWorkerInit(WorkerThread wt) {
386         if (verbose)
387             System.out.println(wt.getName() + ": perRaceWorkerInit() called");
388     }
389 
390     /**
391      * Execute the race in a WorkerThread. Called by each WorkerThread
392      * after it has been released from startBarrier.
393      * @param wt the WorkerThread
394      */
executeRace(WorkerThread wt)395     public void executeRace(WorkerThread wt) {
396         if (verbose)
397             System.out.println(wt.getName() + ": executeRace() called");
398     }
399 
400     /**
401      * Check race results in the DriverThread. Called by the DriverThread
402      * after it has been released from finishBarrier and before the
403      * DriverThread checks in with resetBarrier.
404      * @param dt the DriverThread
405      */
checkRaceResults(DriverThread dt)406     public void checkRaceResults(DriverThread dt) {
407         if (verbose)
408             System.out.println(dt.getName() + ": checkRaceResults() called");
409     }
410 
411     /**
412      * Handle end-of-race items for the DriverThread. Called by the
413      * DriverThread after it has been released from resetBarrier and
414      * before the DriverThread checks in again with startBarrier. Can
415      * execute in parallel with perRaceWorkerEpilog(). If this is not
416      * the last race, can execute in parallel with perRaceWorkerInit().
417      * If this is the last race, can execute in parallel with
418      * oneTimeWorkerEpilog().
419      * @param dt the DriverThread
420      */
perRaceDriverEpilog(DriverThread dt)421     public void perRaceDriverEpilog(DriverThread dt) {
422         if (verbose)
423             System.out.println(dt.getName() + ": perRaceDriverEpilog() called");
424     }
425 
426     /**
427      * Handle end-of-race items for a WorkerThread. Called by each
428      * WorkerThread after it has been released from resetBarrier and
429      * before the WorkerThread checks in again with startBarrier.
430      * Can execute in parallel with perRaceDriverEpilog() or another
431      * WorkerThread's perRaceWorkerEpilog() call. If this is not the
432      * last race, can execute in parallel with perRaceDriverInit(),
433      * or another WorkerThread's perRaceWorkerInit() call. If this
434      * is the last race, can execute in parallel with another
435      * WorkerThread's oneTimeWorkerEpilog() call.
436      * @param wt the WorkerThread
437      */
perRaceWorkerEpilog(WorkerThread wt)438     public void perRaceWorkerEpilog(WorkerThread wt) {
439         if (verbose)
440             System.out.println(wt.getName() + ": perRaceWorkerEpilog() called");
441     }
442 
443     /**
444      * Handle end-of-test items for a WorkerThread. Called by each
445      * WorkerThread after it has detected that all races are done and
446      * before oneTimeDriverEpilog() is called. Can execute in parallel
447      * with perRaceDriverEpilog(), with another WorkerThread's
448      * perRaceWorkerEpilog() call or with another WorkerThread's
449      * oneTimeWorkerEpilog() call.
450      * @param wt the WorkerThread
451      */
oneTimeWorkerEpilog(WorkerThread wt)452     public void oneTimeWorkerEpilog(WorkerThread wt) {
453         if (verbose)
454             System.out.println(wt.getName() + ": oneTimeWorkerEpilog() called");
455     }
456 
457     /**
458      * Handle end-of-test items for the DriverThread. Called by the
459      * DriverThread after all the WorkerThreads have called
460      * oneTimeWorkerEpilog().
461      * @param dt the DriverThread
462      */
oneTimeDriverEpilog(DriverThread dt)463     public void oneTimeDriverEpilog(DriverThread dt) {
464         if (verbose)
465             System.out.println(dt.getName() + ": oneTimeDriverEpilog() called");
466     }
467 
468 
469     /**
470      * DriverThread for executing the test.
471      */
472     public static class DriverThread extends Thread {
473         private final RacingThreadsTest test;
474 
475         /**
476          * Create the test DriverThread that manages all the WorkerThreads.
477          * The DriverThread class can be extended to provide test specific
478          * variables and/or code. However, that is typically done in the
479          * subclass of RacingThreadsTest.
480          * @parameter test the RacingThreadsTest being run
481          */
DriverThread(RacingThreadsTest test)482         DriverThread(RacingThreadsTest test) {
483             super("DriverThread");
484             this.test = test;
485         }
486 
run(WorkerThread[] workers)487         private void run(WorkerThread[] workers) {
488             System.out.println(getName() + ": is starting.");
489             System.out.println(getName() + ": # WorkerThreads: " + test.N_THREADS);
490             System.out.println(getName() + ": max # loops: " + test.N_LOOPS);
491             System.out.println(getName() + ": max # secs: " + test.N_SECS);
492 
493             // initialize 1-time items for the DriverThread
494             test.oneTimeDriverInit(this);
495 
496             // start all the threads
497             for (int i = 0; i < workers.length; i++) {
498                 workers[i].start();
499             }
500 
501             // All WorkerThreads call oneTimeWorkerInit() and
502             // perRaceWorkerInit() on the way to startBarrier.
503 
504             long endTime = System.currentTimeMillis() + test.N_SECS * 1000;
505 
506             for (; !test.getDone() && test.getLoopCnt() < test.N_LOOPS;
507                 test.incAndGetLoopCnt()) {
508 
509                 if (test.getVerbose() && (test.N_LOOPS < 10 ||
510                     (test.getLoopCnt() % (test.N_LOOPS / 10)) == 0)) {
511                     System.out.println(getName() + ": race loop #"
512                         + test.getLoopCnt());
513                 }
514 
515                 // initialize per-race items for the DriverThread
516                 test.perRaceDriverInit(this);
517 
518                 try {
519                     // we've setup the race so start it when all
520                     // WorkerThreads get to the startBarrier
521                     test.startBarrier.await();
522                 } catch (BrokenBarrierException bbe) {
523                     test.unexpectedException(this, bbe);
524                     return;
525                 } catch (InterruptedException ie) {
526                     test.unexpectedException(this, ie);
527                     return;
528                 }
529 
530                 // All WorkerThreads are racing via executeRace()
531                 // at this point
532 
533                 // wait for all threads to finish the race
534                 try {
535                     test.finishBarrier.await();
536                 } catch (BrokenBarrierException bbe) {
537                     test.unexpectedException(this, bbe);
538                     return;
539                 } catch (InterruptedException ie) {
540                     test.unexpectedException(this, ie);
541                     return;
542                 }
543                 // All WorkerThreads are heading to resetBarrier at this
544                 // point so we can check the race results before we reset
545                 // for another race (or bail because we are done).
546 
547                 test.checkRaceResults(this);
548 
549                 if (test.getLoopCnt() + 1 >= test.N_LOOPS ||
550                     System.currentTimeMillis() >= endTime) {
551                     // This is the last loop or we're out of time.
552                     // Let test threads know we are done before we release
553                     // them from resetBarrier
554                     test.setDone(true);
555                 }
556 
557                 // release the WorkerThreads from resetBarrier
558                 try {
559                     test.resetBarrier.await();
560                 } catch (BrokenBarrierException bbe) {
561                     test.unexpectedException(this, bbe);
562                     return;
563                 } catch (InterruptedException ie) {
564                     test.unexpectedException(this, ie);
565                     return;
566                 }
567 
568                 // All WorkerThreads call perRaceWorkerEpilog(). If
569                 // this is not the last loop, then all WorkerThreads
570                 // will also call perRaceWorkerInit() on the way to
571                 // startBarrier. If this is the last loop, then all
572                 // WorkerThreads will call oneTimeWorkerEpilog() on
573                 // their way to ending.
574 
575                 // handle end-of-race items for the DriverThread
576                 test.perRaceDriverEpilog(this);
577             }
578 
579             System.out.println(getName() + ": completed " + test.getLoopCnt()
580                 + " race loops.");
581             if (test.getLoopCnt() < test.N_LOOPS) {
582                 System.out.println(getName() + ": race stopped @ " + test.N_SECS
583                     + " seconds.");
584             }
585 
586             for (int i = 0; i < workers.length; i++) {
587                 try {
588                     workers[i].join();
589                 } catch (InterruptedException ie) {
590                     test.unexpectedException(this, ie);
591                     return;
592                 }
593             }
594 
595             // handle end-of-test items for the DriverThread
596             test.oneTimeDriverEpilog(this);
597 
598             System.out.println(getName() + ": is done.");
599         }
600     }
601 
602 
603     /**
604      * WorkerThread for executing the race.
605      */
606     public static class WorkerThread extends Thread {
607         private final RacingThreadsTest test;
608         private final int workerNum;
609 
610         /**
611          * Creates WorkerThread-N that executes the test code. The
612          * WorkerThread class can be extended to provide test thread
613          * specific variables and/or code.
614          * @param workerNum the number for the new WorkerThread
615          * @parameter test the RacingThreadsTest being run
616          */
WorkerThread(int workerNum, RacingThreadsTest test)617         WorkerThread(int workerNum, RacingThreadsTest test) {
618             super("WorkerThread-" + workerNum);
619             this.test = test;
620             this.workerNum = workerNum;
621         }
622 
623         /**
624          * get the WorkerThread's number
625          * @return the WorkerThread's number
626          */
getWorkerNum()627         public int getWorkerNum() {
628             return workerNum;
629         }
630 
631         /**
632          * Run the race in a WorkerThread.
633          */
run()634         public void run() {
635             System.out.println(getName() + ": is running.");
636 
637             // initialize 1-time items for the WorkerThread
638             test.oneTimeWorkerInit(this);
639 
640             while (!test.getDone()) {
641                 // initialize per-race items for the WorkerThread
642                 test.perRaceWorkerInit(this);
643 
644                 try {
645                     test.startBarrier.await();  // wait for race to start
646                 } catch (BrokenBarrierException bbe) {
647                     test.unexpectedException(this, bbe);
648                     return;
649                 } catch (InterruptedException ie) {
650                     test.unexpectedException(this, ie);
651                     return;
652                 }
653 
654                 // execute the race for the WorkerThread
655                 test.executeRace(this);
656 
657                 try {
658                     test.finishBarrier.await();  // this thread is done
659                 } catch (BrokenBarrierException bbe) {
660                     test.unexpectedException(this, bbe);
661                     return;
662                 } catch (InterruptedException ie) {
663                     test.unexpectedException(this, ie);
664                     return;
665                 }
666 
667                 try {
668                     test.resetBarrier.await();  // wait for race to reset
669                 } catch (BrokenBarrierException bbe) {
670                     test.unexpectedException(this, bbe);
671                     return;
672                 } catch (InterruptedException ie) {
673                     test.unexpectedException(this, ie);
674                     return;
675                 }
676 
677                // handle end-of-race items for the WorkerThread
678                 test.perRaceWorkerEpilog(this);
679             }
680 
681             // handle end-of-test items for the WorkerThread
682             test.oneTimeWorkerEpilog(this);
683 
684             System.out.println(getName() + ": is ending.");
685         }
686     }
687 }
688