View Javadoc
1   package org.argeo.cms.internal.kernel;
2   
3   /**
4    * Workaround for killing Gogo shell by system shutdown.
5    * 
6    * @see https://issues.apache.org/jira/browse/FELIX-4208
7    */
8   class GogoShellKiller extends Thread {
9   
10  	public GogoShellKiller() {
11  		super("Gogo Shell Killer");
12  		setDaemon(true);
13  	}
14  
15  	@Override
16  	public void run() {
17  		ThreadGroup rootTg = getRootThreadGroup(null);
18  		Thread gogoShellThread = findGogoShellThread(rootTg);
19  		if (gogoShellThread == null)
20  			return;
21  		while (getNonDaemonCount(rootTg) > 2) {
22  			try {
23  				Thread.sleep(100);
24  			} catch (InterruptedException e) {
25  				// silent
26  			}
27  		}
28  		gogoShellThread = findGogoShellThread(rootTg);
29  		if (gogoShellThread == null)
30  			return;
31  		// No non-deamon threads left, forcibly halting the VM
32  		Runtime.getRuntime().halt(0);
33  	}
34  
35  	private ThreadGroup getRootThreadGroup(ThreadGroup tg) {
36  		if (tg == null)
37  			tg = Thread.currentThread().getThreadGroup();
38  		if (tg.getParent() == null)
39  			return tg;
40  		else
41  			return getRootThreadGroup(tg.getParent());
42  	}
43  
44  	private int getNonDaemonCount(ThreadGroup rootThreadGroup) {
45  		Thread[] threads = new Thread[rootThreadGroup.activeCount()];
46  		rootThreadGroup.enumerate(threads);
47  		int nonDameonCount = 0;
48  		for (Thread t : threads)
49  			if (t != null && !t.isDaemon())
50  				nonDameonCount++;
51  		return nonDameonCount;
52  	}
53  
54  	private Thread findGogoShellThread(ThreadGroup rootThreadGroup) {
55  		Thread[] threads = new Thread[rootThreadGroup.activeCount()];
56  		rootThreadGroup.enumerate(threads, true);
57  		for (Thread thread : threads) {
58  			if (thread.getName().equals("pipe-gosh --login --noshutdown"))
59  				return thread;
60  		}
61  		return null;
62  	}
63  
64  }