Hi,

This patch adds the ShutdownHook (Java 1.3) feature to kaffe. Here is a 
Changelog:

* libraries/clib/native/Application.c, 
libraries/javalib/kaffe/lang/Application.java: removed
* libraries/clib/native/Runtime.c: renamed exitInternal() into exit0()
* libraries/javalib/java/lang/Runtime.java (exitInternal, addShutdownHook, 
removeShutdownHook, exitJavaCleanup, runShutdownHooks): implement the 
Shutdown hook Java 1.3 feature, removed kaffe/lang/Application.
* libraries/javalib/java/lang/System.java (exitJavaCleanup): Added a hook for 
java.lang.Runtime.exitJavaCleanup.
* kaffe/kaffevm/threads.c: Call System.exitJavaCleanup() before final exit.

If you check it in, you will first need to delete kaffe/lang/Application.java 
and native/Application.c as mentioned. Hope it's allright.

Cheers,

Guilhem.
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 17:10:20 -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.48
diff -u -3 -p -r1.48 thread.c
--- kaffe/kaffevm/thread.c	11 Jun 2003 16:54:14 -0000	1.48
+++ kaffe/kaffevm/thread.c	8 Jul 2003 17:10:20 -0000
@@ -34,6 +34,7 @@
 #include "gc.h"
 #include "jni.h"
 #include "md.h"
+#include "java_lang_Runtime.h"
 
 /* If not otherwise specified, assume at least 1MB for main thread */
 #ifndef MAINSTACKSIZE
@@ -570,6 +571,10 @@ static
 void
 runfinalizer(void)
 {
+	Hjava_lang_Runtime *runtime;
+
+	do_execute_java_method(SystemClass, "exitJavaCleanup",
+			       "(Ljava/lang/Runtime;)V", NULL, true);
 	if (runFinalizerOnExit) {
 		invokeFinalizer();
 	}
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 17:10:20 -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 17:10:20 -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/cvsJ3t3rt 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 17:10:23 -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 17:10:23 -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 17:10:23 -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 17:10:23 -0000
@@ -274,6 +274,10 @@ public static boolean interrupted() {
 	return (i);
 }
 
+protected final boolean isDied() {
+	return dying;
+}
+
 public final boolean isAlive () {
 	return (started && !dying);
 }

Reply via email to