1 import java.util.Map;
2 
3 public class Main {
main(String[] args)4     static public void main(String[] args) throws Exception {
5         checkManager();
6 
7         // Warm up the reaper so that there are no issues with scheduling because of static
8         // initialization.
9         {
10             ProcessBuilder pb = new ProcessBuilder("sleep", "0");
11             Process proc = pb.start();
12             proc.waitFor();
13             waitForReaperTimedWaiting(true /* reaperMustExist */);
14         }
15 
16         for (int i = 1; i <= 2; i++) {
17             System.out.println("\nspawning child #" + i);
18             child();
19             Thread.sleep(2000);
20             checkManager();
21         }
22         System.out.println("\ndone!");
23     }
24 
child()25     static private void child() throws Exception {
26         System.out.println("spawning child");
27         ProcessBuilder pb = new ProcessBuilder("sleep", "5");
28         Process proc = pb.start();
29         Thread.sleep(250);
30         checkManager();
31         proc.waitFor();
32         System.out.println("child died");
33     }
34 
isReaperThread(Thread t)35     private static boolean isReaperThread(Thread t) {
36         String name = t.getName();
37         return name.indexOf("process reaper") >= 0;
38     }
39 
checkManager()40     static private void checkManager() {
41         Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
42         boolean found = false;
43 
44         for (Map.Entry<Thread, StackTraceElement[]> entry :
45                  traces.entrySet()) {
46             Thread t = entry.getKey();
47             if (isReaperThread(t)) {
48                 Thread.State state = t.getState();
49                 System.out.println("process manager: " + state);
50                 if (state != Thread.State.RUNNABLE && state != Thread.State.TIMED_WAITING) {
51                     for (StackTraceElement e : entry.getValue()) {
52                         System.out.println("  " + e);
53                     }
54                 }
55                 found = true;
56             }
57         }
58 
59         if (! found) {
60             System.out.println("process manager: nonexistent");
61         }
62     }
63 
waitForReaperTimedWaiting(boolean reaperMustExist)64     private static void waitForReaperTimedWaiting(boolean reaperMustExist) {
65         for (;;) {
66             Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
67 
68             boolean ok = true;
69             boolean found = false;
70 
71             for (Thread t : traces.keySet()) {
72                 if (isReaperThread(t)) {
73                     found = true;
74                     Thread.State state = t.getState();
75                     if (state != Thread.State.TIMED_WAITING) {
76                         ok = false;
77                         break;
78                     }
79                 }
80             }
81 
82             if (ok && (!reaperMustExist || found)) {
83                 return;
84             }
85 
86             try {
87                 Thread.sleep(100);
88             } catch (Exception e) {
89                 // Ignore.
90             }
91         }
92     }
93 }
94