[kaffe] Shutdown patch
Guilhem Lavaux
guilhem.lavaux@free.fr
Tue Jul 8 11:31:01 2003
--Boundary-00=_L+wC/O1zbNd/Nwv
Content-Type: Text/Plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Content-Description: clearsigned data
Content-Disposition: inline
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=3D20 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=
=20
normal exit. This one should be right: I had to move a intsDisable() just a=
t=20
the right place in jthread.c.
To add to the Changelog:
* test/regression/HookTest.java: new test case for=20
java.lang.Runtime.(add|remove)ShutdownHook
* libraries/java/lang/Thread.java (Thread, finish): removed calls to=20
kaffe/lang/Application
* kaffe/kaffevm/systems/unix-jthreads/jthread.c: moved intsDisable to permi=
t=20
the call to runOnExit in full threaded mode.
> thanks,
No problem,
Guilhem.
>
> tim
>
> _______________________________________________
> kaffe mailing list
> kaffe@kaffe.org
> http://kaffe.org/cgi-bin/mailman/listinfo/kaffe
--Boundary-00=_L+wC/O1zbNd/Nwv
Content-Type: text/x-diff;
charset="iso-8859-1";
name="shutdown.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="shutdown.patch"
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 \
--Boundary-00=_L+wC/O1zbNd/Nwv
Content-Type: text/x-java;
charset="iso-8859-1";
name="HookTest.java"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="HookTest.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
*/
--Boundary-00=_L+wC/O1zbNd/Nwv--