DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT <http://nagoya.apache.org/bugzilla/show_bug.cgi?id=8510>. ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND INSERTED IN THE BUG DATABASE.
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=8510 shutdown hook does not fire in forked java task under JDK1.4 ------- Additional Comments From [EMAIL PROTECTED] 2002-10-24 10:16 ------- I make some experiments and make a "guess". Maybe the guess is wrong, but hope the other information will help to solve the problem. == Experiment 1: use JDK to invoke MyProg == "MyProg" is a program with shutdown hook installed. Press "Ctrl+C" to stop it. "Yes" means the showdown hook of "MyProg" is invoked. java.exe MyProg JDK 1.3.1 Yes (1.3.1_03-b03) JDK 1.4.0 Yes (1.4.0-b92) == Experiment 2: use Ant 1.5.1 to invoke MyProg == Run "MyProg" with Ant. Press "Ctrl+C" to stop it. Ant 1.5.1 has its own shotdown hook (added by ProcessDestroyer.java) which call java.lang.Process.destroy() on the process of "MyProg". "Yes" means the showdown hook of "MyProg" is invoked. Ant 1.5.1 -> MyProg JDK 1.3.1 *Yes* JDK 1.4.0 No == Experiment 3: use "Invoker" to invoke MyProg == "Invoker" is a program which launches "MyProg" with System.exec(). "Invoker" has its own shotdown hook which call java.lang.Process.destroy() on the process of "MyProg". "Yes" means the showdown hook of "MyProg" been invoked. java.exe Invoker -> MyProg JDK 1.3.1 JDK 1.4.0 0 No 0 No 1 No 1 No 2 *Yes* 2 No case 0: Invoker call proc.destroy() directly (not in its shutdown hook) case 1: Invoker call proc.destroy() in its own shutdown hook triggered when the "main" thread completed. case 2: Invoker call proc.destroy() in its own shutdown hook triggered by Ctrl+C. == Code and Document == On Win32 systems java.lang.Process.destroy() make system call TerminateProcess() in both JDK 1.3.1 and 1.4.0 which unconditionally cause a process to exit. (src\win32\native\java\lang\Win32Process_md.c) In the JavaDoc of java.lang.Runtime, "In rare circumstances the virtual machine may abort, that is, stop running without shutting down cleanly. This occurs when the virtual machine is terminated externally, for example with the SIGKILL signal on Unix or the TerminateProcess call on Win32.". == My guess == Process.destroy() which calls TerminateProcess() should give "MyProg" no chance to run its shutdown hook. There are two exceptions: (marked with '*') JDK 1.3.1 + Ant 1.5.1 + MyProg (with Ctrl+C) JDK 1.3.1 + Invoker + MyProg (with Ctrl+C) I "guess" that JDK 1.3.1 also send "Ctrl+C" to MyProg which cause it to run the shutdown hook before killed by TerminateProcess() from Ant and Invoker. But I have no evidence. == Code: MyProg.java == import java.io.FileWriter; import java.io.IOException; public class MyProg { public static void log(String s) { try { FileWriter fw = new FileWriter("MyProg.txt", true); fw.write(s + "\n"); fw.flush(); fw.close(); } catch (IOException e) { } } public static void main(String[] args) throws Exception { log("MyProg: main() : " + System.getProperty("java.runtime.version")); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { log("MyProg: hook invoked"); }}); log("MyProg: hook installed"); while (true) ; } } == Code: Invoker.java == public class Invoker { public static Process exec() { try { System.out.println("before exec"); Process proc = Runtime.getRuntime().exec("java MyProg"); System.out.println("after exec, sleep 5 sec"); Thread.currentThread().sleep(5 * 1000); System.out.println("ready"); return proc; } catch (Exception e) { e.printStackTrace(); return null; } } public static void addHook(final Process proc) { System.out.println("enter addHook"); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { System.out.println("Invoker: hook invoked"); System.out.println("before destory"); proc.destroy(); System.out.println("after destory"); }}); System.out.println("leave addHook"); } public static void destroyDirectly() { Process proc = exec(); System.out.println("before destroy"); proc.destroy(); System.out.println("after destroy"); } public static void destroyFromHook1() { Process proc = exec(); addHook(proc); } public static void destroyFromHook2() { Process proc = exec(); addHook(proc); System.out.println("waiting for ctrl+c"); while (true) ; } public static void main(String[] args) throws Exception { switch (Integer.parseInt(args[0])) { case 0 : destroyDirectly(); break; case 1 : destroyFromHook1(); break; case 2 : destroyFromHook2(); break; } } } == build.xml == <project name="A" default="A" basedir="."> <target name="A"> <java classname="MyProg" fork="yes"> <classpath> <pathelement location="."/> </classpath> </java> </target> </project> -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
