/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.utils;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Map;
/**
* This is a self-destructor class to kill a long running process automatically
* after a pre-defined time. The class reads the number of minutes from the
* system property 'h2.selfDestruct' and starts a countdown thread to kill the
* virtual machine if it still runs then.
*/
public class SelfDestructor extends Thread {
private static final String PROPERTY_NAME = "h2.selfDestruct";
/**
* Start the countdown. If the self-destruct system property is set, this
* value is used, otherwise the given default value is used.
*
* @param defaultMinutes the default number of minutes after which the
* current process is killed.
*/
public static void startCountdown(int defaultMinutes) {
final int minutes = Integer.parseInt(System.getProperty(PROPERTY_NAME, "" + defaultMinutes));
if (minutes != 0) {
Thread thread = new Thread() {
public void run() {
for (int i = minutes; i >= 0; i--) {
while (true) {
try {
String name = "SelfDestructor " + i + " min";
setName(name);
break;
} catch (OutOfMemoryError e) {
// ignore
}
}
try {
Thread.sleep(60 * 1000);
} catch (InterruptedException e) {
// ignore
}
}
String time = new Timestamp(System.currentTimeMillis()).toString();
System.out.println(time + " Killing the process after " + minutes + " minute(s)");
try {
Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
for (Map.Entry<Thread, StackTraceElement[]> en : map.entrySet()) {
System.out.println(en.getKey());
for (StackTraceElement el : en.getValue()) {
System.out.println(" " + el);
}
}
System.out.println();
System.out.flush();
try {
Thread.sleep(1000);
} catch (Exception e) {
// ignore
}
int activeCount = Thread.activeCount();
Thread[] threads = new Thread[activeCount + 100];
int len = Thread.enumerate(threads);
Method stop = Thread.class.getMethod("stop", Throwable.class);
for (int i = 0; i < len; i++) {
Thread t = threads[i];
String threadName = "Thread #" + i + ": " + t.getName();
Error e = new Error(threadName);
if (t != Thread.currentThread()) {
stop.invoke(t, e);
t.interrupt();
}
}
} catch (Throwable t) {
t.printStackTrace();
// ignore
}
try {
Thread.sleep(1000);
} catch (Exception e) {
// ignore
}
System.out.println("Killing the process now");
Runtime.getRuntime().halt(1);
}
};
thread.setDaemon(true);
thread.start();
}
}
/**
* Get the string to be added when starting the Java process.
*
* @param minutes the countdown time in minutes
* @return the setting
*/
public static String getPropertyString(int minutes) {
return "-D" + PROPERTY_NAME + "=" + minutes;
}
}