On Tuesday 08 July 2003 18:24, Timothy Stack wrote: > > Hi, > > hi, > > > This patch adds the ShutdownHook (Java 1.3) feature to kaffe. Here is > > a=20 Changelog: > > Neat, can you make a test case for it please? > > > Cheers, > > > > Guilhem. >
Ok, here it is. By the way, I have found that the previous patch breaks the normal exit. This one should be right: I had to move a intsDisable() just at the right place in jthread.c. To add to the Changelog: * test/regression/HookTest.java: new test case for java.lang.Runtime.(add|remove)ShutdownHook * libraries/java/lang/Thread.java (Thread, finish): removed calls to kaffe/lang/Application * kaffe/kaffevm/systems/unix-jthreads/jthread.c: moved intsDisable to permit the call to runOnExit in full threaded mode. > thanks, No problem, Guilhem. > > tim > > _______________________________________________ > kaffe mailing list > [EMAIL PROTECTED] > http://kaffe.org/cgi-bin/mailman/listinfo/kaffe
Index: include/Makefile.am =================================================================== RCS file: /cvs/kaffe/kaffe/include/Makefile.am,v retrieving revision 1.38 diff -u -3 -p -r1.38 Makefile.am --- include/Makefile.am 13 Jun 2003 00:32:00 -0000 1.38 +++ include/Makefile.am 8 Jul 2003 18:21:39 -0000 @@ -104,7 +104,6 @@ NOINSTALL_JNI_DERIVED_HDRS = \ kaffe_io_ByteToCharIconv.h \ kaffe_io_CharToByteDefault.h \ kaffe_io_CharToByteIconv.h \ - kaffe_lang_Application.h \ kaffe_lang_MemoryAdvice.h \ kaffe_lang_UNIXProcess.h \ kaffe_management_JIT.h \ Index: kaffe/kaffevm/thread.c =================================================================== RCS file: /cvs/kaffe/kaffe/kaffe/kaffevm/thread.c,v retrieving revision 1.49 diff -u -3 -p -r1.49 thread.c --- kaffe/kaffevm/thread.c 8 Jul 2003 07:33:49 -0000 1.49 +++ kaffe/kaffevm/thread.c 8 Jul 2003 18:21:39 -0000 @@ -570,6 +570,8 @@ static void runfinalizer(void) { + do_execute_java_method(SystemClass, "exitJavaCleanup", + "()V", NULL, true); if (runFinalizerOnExit) { invokeFinalizer(); } Index: kaffe/kaffevm/systems/unix-jthreads/jthread.c =================================================================== RCS file: /cvs/kaffe/kaffe/kaffe/kaffevm/systems/unix-jthreads/jthread.c,v retrieving revision 1.93 diff -u -3 -p -r1.93 jthread.c --- kaffe/kaffevm/systems/unix-jthreads/jthread.c 24 Jun 2003 19:26:02 -0000 1.93 +++ kaffe/kaffevm/systems/unix-jthreads/jthread.c 8 Jul 2003 18:21:39 -0000 @@ -1565,11 +1565,6 @@ DBG(JTHREAD, jmutex_unlock(&threadLock); jthread_enable_stop(); - /* we disable interrupts while we go out to prevent a reschedule - * in killThread() - */ - intsDisable(); - /* If we only have daemons left, then we should exit. */ if (talive == tdaemon) { DBG(JTHREAD, @@ -1577,6 +1572,10 @@ DBG(JTHREAD, if (runOnExit != 0) { runOnExit(); } + /* we disable interrupts while we go out to prevent a reschedule + * in killThread() + */ + intsDisable(); for (tid = liveThreads; tid != 0; tid = tid->nextlive) { /* The current thread is still on the live @@ -1588,6 +1587,10 @@ DBG(JTHREAD, } EXIT(0); } + /* we disable interrupts while we go out to prevent a reschedule + * in killThread() + */ + intsDisable(); for (;;) { killThread(currentJThread); jthread_sleep(1000); Index: libraries/clib/native/Makefile.am =================================================================== RCS file: /cvs/kaffe/kaffe/libraries/clib/native/Makefile.am,v retrieving revision 1.20 diff -u -3 -p -r1.20 Makefile.am --- libraries/clib/native/Makefile.am 26 Jun 2003 11:05:37 -0000 1.20 +++ libraries/clib/native/Makefile.am 8 Jul 2003 18:21:39 -0000 @@ -16,7 +16,6 @@ IO_SRCS = \ ObjectStreamClassImpl.c LANG_SRCS = \ - Application.c \ Class.c \ ClassLoader.c \ Compiler.c \ Index: libraries/clib/native/Runtime.c =================================================================== RCS file: /cvs/kaffe/kaffe/libraries/clib/native/Runtime.c,v retrieving revision 1.19 diff -u -3 -p -r1.19 Runtime.c --- libraries/clib/native/Runtime.c 29 May 2002 22:58:44 -0000 1.19 +++ libraries/clib/native/Runtime.c 8 Jul 2003 18:21:40 -0000 @@ -31,7 +31,7 @@ extern jboolean runFinalizerOnExit; * Exit this VM */ void -java_lang_Runtime_exitInternal(struct Hjava_lang_Runtime* r, jint v) +java_lang_Runtime_exit0(struct Hjava_lang_Runtime* r, jint v) { EXIT (v); } Index: libraries/javalib/Klasses.jar.bootstrap =================================================================== RCS file: /cvs/kaffe/kaffe/libraries/javalib/Klasses.jar.bootstrap,v retrieving revision 1.20 diff -u -3 -p -r1.20 Klasses.jar.bootstrap Binary files /tmp/cvsjiSgVJ and Klasses.jar.bootstrap differ Index: libraries/javalib/essential.files =================================================================== RCS file: /cvs/kaffe/kaffe/libraries/javalib/essential.files,v retrieving revision 1.10 diff -u -3 -p -r1.10 essential.files --- libraries/javalib/essential.files 28 Jun 2003 18:06:42 -0000 1.10 +++ libraries/javalib/essential.files 8 Jul 2003 18:21:42 -0000 @@ -283,7 +283,6 @@ kaffe/io/StdErrorStream.java kaffe/io/StdInputStream.java kaffe/io/StdOutputStream.java kaffe/lang/AppClassLoader.java -kaffe/lang/Application.java kaffe/lang/ApplicationException.java kaffe/lang/ApplicationResource.java kaffe/lang/ClassPathReader.java Index: libraries/javalib/java/lang/Runtime.java =================================================================== RCS file: /cvs/kaffe/kaffe/libraries/javalib/java/lang/Runtime.java,v retrieving revision 1.23 diff -u -3 -p -r1.23 Runtime.java --- libraries/javalib/java/lang/Runtime.java 28 Jun 2003 18:06:41 -0000 1.23 +++ libraries/javalib/java/lang/Runtime.java 8 Jul 2003 18:21:42 -0000 @@ -17,6 +17,8 @@ import java.io.OutputStream; import java.io.FileNotFoundException; import java.util.StringTokenizer; +import java.util.Vector; +import java.util.Enumeration; import kaffe.lang.ThreadStack; @@ -37,6 +39,8 @@ public interface MemoryAdvice { private static Runtime currentRuntime = new Runtime(); private static kaffe.lang.MemoryAdvice advice = kaffe.lang.MemoryAdvice.getInstance(); +private static Vector shutdownHooks = new Vector(0); +private static boolean VMShuttingDown = false; private Runtime () { } @@ -81,26 +85,31 @@ public Process exec(String[] cmdarray, S private native Process execInternal(String cmdary[], String envp[], File dir) throws IOException; + +protected void exitJavaCleanup() { + runShutdownHooks(); +} -public void exit(int status) { +public void exit(int status) throws SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkExit(status); - // Handle application extensions - if this thread is part of an - // application then we exit that rather than the whole thing. - if (!kaffe.lang.Application.exit(status)) { - exitInternal(status); - } - // kaffe.lang.Application.exit does not destroy the thread - // that invoked exit(). We stop that thread now. - Thread.currentThread().destroy(); + + /* First we cleanup the Virtual Machine */ + exitJavaCleanup(); + /* Now we run the VM exit function */ + exit0(status); } -public void halt(int status) { - exitInternal(status); +public void halt(int status) throws SecurityException { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkExit(status); + + exit0(status); } -native private void exitInternal(int status); +native private void exit0(int status); native public long freeMemory(); @@ -177,15 +186,68 @@ int waitForMemoryAdvice(int level) throw return (advice.waitForOtherColor(level)); } -public void addShutdownHook(Thread hook) { - // XXX implement me - System.err.println("WARNING: Not implemented method called " + - getClass().getName() + ".addShutdownHook()"); +private void runShutdownHooks() { + Enumeration hook_enum; + + /* According to Java 1.3 we need to run all hooks simultaneously + * and then wait for them. + */ + synchronized (this) { + VMShuttingDown = true; + } + /* We start all threads at once as in the specification */ + hook_enum = shutdownHooks.elements(); + while (hook_enum.hasMoreElements()) { + Thread hook = (Thread)hook_enum.nextElement(); + + try { + hook.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /* Now we wait for each thread */ + hook_enum = shutdownHooks.elements(); + while (hook_enum.hasMoreElements()) { + Thread hook = (Thread)hook_enum.nextElement(); + + try { + hook.join(); + } catch (Exception e) { + e.printStackTrace(); + } + } } -public boolean removeShutdownHook(Thread hook) { - // XXX implement me - return false; +public void addShutdownHook(Thread hook) throws IllegalArgumentException, IllegalStateException { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new RuntimePermission("shutdownHooks")); + + synchronized(this) { + if (VMShuttingDown) + throw new IllegalStateException("VM is shutting down."); + } + if (shutdownHooks.contains(hook)) + throw new IllegalArgumentException("Thread already in shutdown queue."); + if (hook.isAlive() || hook.isInterrupted() || hook.isDied()) + throw new IllegalArgumentException("Thread has already been started once."); + + shutdownHooks.addElement(hook); +} + +public boolean removeShutdownHook(Thread hook) throws IllegalStateException { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new RuntimePermission("shutdownHooks")); + + synchronized(this) { + if (VMShuttingDown) + throw new IllegalStateException("VM is shutting down."); + } + + return shutdownHooks.removeElement(hook); } native public void runFinalization(); Index: libraries/javalib/java/lang/System.java =================================================================== RCS file: /cvs/kaffe/kaffe/libraries/javalib/java/lang/System.java,v retrieving revision 1.34 diff -u -3 -p -r1.34 System.java --- libraries/javalib/java/lang/System.java 28 Jun 2003 18:06:41 -0000 1.34 +++ libraries/javalib/java/lang/System.java 8 Jul 2003 18:21:42 -0000 @@ -135,6 +135,10 @@ public static void runFinalizersOnExit(b Runtime.getRuntime().runFinalizersOnExit(value); } +private static void exitJavaCleanup() { + Runtime.getRuntime().exitJavaCleanup(); +} + public static void setErr(PrintStream err) { // XXX call security manager for RuntimePermission("SetIO") setErr0(err); Index: libraries/javalib/java/lang/Thread.java =================================================================== RCS file: /cvs/kaffe/kaffe/libraries/javalib/java/lang/Thread.java,v retrieving revision 1.40 diff -u -3 -p -r1.40 Thread.java --- libraries/javalib/java/lang/Thread.java 24 May 2003 20:07:07 -0000 1.40 +++ libraries/javalib/java/lang/Thread.java 8 Jul 2003 18:21:42 -0000 @@ -13,7 +13,6 @@ package java.lang; import java.util.HashMap; import java.util.Iterator; import java.security.AccessController; -import kaffe.lang.Application; import kaffe.lang.ApplicationResource; public class Thread @@ -91,9 +90,7 @@ public Thread(ThreadGroup group, Runnabl this.group.checkAccess(); this.group.add(this); - // make sure this.name is non-zero before calling addResource this.name = name.toCharArray(); - Application.addResource(this); this.target = target; this.interrupting = false; @@ -205,7 +202,6 @@ void finish() { if (tg != null) { tg.remove(this); } - Application.removeResource(this); } public void freeResource() { @@ -272,6 +268,10 @@ public static boolean interrupted() { boolean i = curr.interrupting; curr.interrupting = false; return (i); +} + +protected final boolean isDied() { + return dying; } public final boolean isAlive () { Index: test/regression/Makefile.am =================================================================== RCS file: /cvs/kaffe/kaffe/test/regression/Makefile.am,v retrieving revision 1.76 diff -u -3 -p -r1.76 Makefile.am --- test/regression/Makefile.am 2 Jun 2003 04:34:05 -0000 1.76 +++ test/regression/Makefile.am 8 Jul 2003 18:21:42 -0000 @@ -141,7 +141,8 @@ TEST_MISC = \ LostTrampolineFrame.java \ NetworkInterfaceTest.java \ InetAddressTest.java \ - InetSocketAddressTest.java + InetSocketAddressTest.java \ + HookTest.java TEST_REFLECTION = \ ReflectInvoke.java \
import java.lang.Thread; import java.lang.Exception; import java.lang.System; class HookTest_Hook extends Thread { private int hook_num; private int hook_sleep; public HookTest_Hook(int sleep, int num) { hook_num = num; hook_sleep = sleep; } public void run() { System.out.println("Hook " + hook_num + " started"); try { sleep(hook_sleep); } catch (Exception e) { e.printStackTrace(); } try { Runtime.getRuntime().addShutdownHook(new HookTest_Hook(0, -1)); System.out.println("Error: accepted Hook"); Runtime.getRuntime().halt(0); } catch (IllegalStateException ie) { } catch (Exception e) { e.printStackTrace(); } } } public class HookTest { static public void main(String args[]) { Thread t = new Thread() { public void run() { System.out.println("Thread started"); try { sleep(1000); } catch (Exception e) { e.printStackTrace(); } System.out.println("Exiting"); System.exit(0); } }; Thread a = new Thread(); a.start(); try { a.join(); } catch (Exception e) { e.printStackTrace(); } Runtime.getRuntime().addShutdownHook(new HookTest_Hook(1000, 0)); Runtime.getRuntime().addShutdownHook(new HookTest_Hook(500, 1)); try { Runtime.getRuntime().addShutdownHook(a); System.out.println("Should have raised IllegalArgumentException"); } catch (IllegalArgumentException e) { } catch (Exception e) { e.printStackTrace(); } t.start(); try { Thread.sleep(10000); } catch (Exception e) { e.printStackTrace(); } System.out.println("Normal exit"); } } // Sort Output /* Expected output: Exiting Hook 0 started Hook 1 started Thread started */