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
*/

Reply via email to