The following was added upstream:
2006-04-12 Mark Wielaard <[EMAIL PROTECTED]>
Port UncaughtExceptionHandler support from generics branch.
* NEWS: Document Thread.UncaughtExceptionHandler VMThread change.
2006-04-12 Andrew John Hughes <[EMAIL PROTECTED]>
* java/lang/Thread.java:
(setUncaughtExceptionHandler(UncaughtExceptionHandler):
Added docs and security check.
(getUncaughtExceptionHandler()): Documented.
(setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler):
Added docs and security check.
(getDefaultUncaughtExceptionHandler()): Documented.
(getId()): Documented.
2006-04-12 Tom Tromey <[EMAIL PROTECTED]>
* vm/reference/java/lang/VMThread.java (run): Use thread's
uncaught handler.
* java/lang/Thread.java (defaultHandler): New field.
(setDefaultUncaughtExceptionHandler,
getDefaultUncaughtExceptionHandler, setUncaughtExceptionHandler,
getUncaughtExceptionHandler): New methods.
* java/lang/ThreadGroup.java (ThreadGroup): Implements
UncaughtExceptionHandler.
(uncaughtException): Use getDefaultUncaughtExceptionHandler.
Note that for full UncaughtExceptionHandler you also need a runtime with
an updated VMThread support as described in the NEWS file. But the patch
will make things compile and mostly work.
Index: NEWS
===================================================================
RCS file: /cvsroot/classpath/classpath/NEWS,v
retrieving revision 1.130
diff -u -r1.130 NEWS
--- NEWS 29 Mar 2006 13:10:11 -0000 1.130
+++ NEWS 12 Apr 2006 11:52:52 -0000
@@ -29,6 +29,8 @@
now have a new native getModifiersInternal() method. The public
getModifiers() method in each case has been rewritten in terms of
this method.
+* The reference implementation of VMThread has been updated to handle
+ the new Thread.UncaughtExceptionHandler support.
New in release 0.90 (March 6, 2006)
Index: java/lang/Thread.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/Thread.java,v
retrieving revision 1.18
diff -u -r1.18 Thread.java
--- java/lang/Thread.java 16 Feb 2006 09:53:13 -0000 1.18
+++ java/lang/Thread.java 12 Apr 2006 11:52:52 -0000
@@ -1,5 +1,5 @@
/* Thread -- an independent thread of executable code
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation
This file is part of GNU Classpath.
@@ -81,6 +81,7 @@
* @author Tom Tromey
* @author John Keiser
* @author Eric Blake ([EMAIL PROTECTED])
+ * @author Andrew John Hughes ([EMAIL PROTECTED])
* @see Runnable
* @see Runtime#exit(int)
* @see #run()
@@ -130,15 +131,27 @@
/** The context classloader for this Thread. */
private ClassLoader contextClassLoader;
+
+ /** This thread's ID. */
+ private final long threadId;
/** The next thread number to use. */
private static int numAnonymousThreadsCreated;
+
+ /** The next thread ID to use. */
+ private static long nextThreadId;
+
+ /** The default exception handler. */
+ private static UncaughtExceptionHandler defaultHandler;
/** Thread local storage. Package accessible for use by
* InheritableThreadLocal.
*/
WeakIdentityHashMap locals;
+ /** The uncaught exception handler. */
+ UncaughtExceptionHandler exceptionHandler;
+
/**
* Allocates a new <code>Thread</code> object. This constructor has
* the same effect as <code>Thread(null, null,</code>
@@ -342,6 +355,11 @@
this.name = name.toString();
this.runnable = target;
this.stacksize = size;
+
+ synchronized (Thread.class)
+ {
+ this.threadId = nextThreadId++;
+ }
priority = current.priority;
daemon = current.daemon;
@@ -371,6 +389,11 @@
this.priority = priority;
this.daemon = daemon;
this.contextClassLoader = ClassLoader.getSystemClassLoader();
+ synchronized (Thread.class)
+ {
+ this.threadId = nextThreadId++;
+ }
+
}
/**
@@ -1000,4 +1023,157 @@
}
return locals;
}
+
+ /**
+ * Assigns the given <code>UncaughtExceptionHandler</code> to this
+ * thread. This will then be called if the thread terminates due
+ * to an uncaught exception, pre-empting that of the
+ * <code>ThreadGroup</code>.
+ *
+ * @param h the handler to use for this thread.
+ * @throws SecurityException if the current thread can't modify this thread.
+ * @since 1.5
+ */
+ public void setUncaughtExceptionHandler(UncaughtExceptionHandler h)
+ {
+ SecurityManager sm = SecurityManager.current; // Be thread-safe.
+ if (sm != null)
+ sm.checkAccess(this);
+ exceptionHandler = h;
+ }
+
+ /**
+ * <p>
+ * Returns the handler used when this thread terminates due to an
+ * uncaught exception. The handler used is determined by the following:
+ * </p>
+ * <ul>
+ * <li>If this thread has its own handler, this is returned.</li>
+ * <li>If not, then the handler of the thread's <code>ThreadGroup</code>
+ * object is returned.</li>
+ * <li>If both are unavailable, then <code>null</code> is returned.</li>
+ * </ul>
+ *
+ * @return the appropriate <code>UncaughtExceptionHandler</code> or
+ * <code>null</code> if one can't be obtained.
+ * @since 1.5
+ */
+ public UncaughtExceptionHandler getUncaughtExceptionHandler()
+ {
+ return exceptionHandler;
+ }
+
+ /**
+ * <p>
+ * Sets the default uncaught exception handler used when one isn't
+ * provided by the thread or its associated <code>ThreadGroup</code>.
+ * This exception handler is used when the thread itself does not
+ * have an exception handler, and the thread's <code>ThreadGroup</code>
+ * does not override this default mechanism with its own. As the group
+ * calls this handler by default, this exception handler should not defer
+ * to that of the group, as it may lead to infinite recursion.
+ * </p>
+ * <p>
+ * Uncaught exception handlers are used when a thread terminates due to
+ * an uncaught exception. Replacing this handler allows default code to
+ * be put in place for all threads in order to handle this eventuality.
+ * </p>
+ *
+ * @param h the new default uncaught exception handler to use.
+ * @throws SecurityException if a security manager is present and
+ * disallows the runtime permission
+ * "setDefaultUncaughtExceptionHandler".
+ * @since 1.5
+ */
+ public static void
+ setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler h)
+ {
+ SecurityManager sm = SecurityManager.current; // Be thread-safe.
+ if (sm != null)
+ sm.checkPermission(new RuntimePermission("setDefaultUncaughtExceptionHandler"));
+ defaultHandler = h;
+ }
+
+ /**
+ * Returns the handler used by default when a thread terminates
+ * unexpectedly due to an exception, or <code>null</code> if one doesn't
+ * exist.
+ *
+ * @return the default uncaught exception handler.
+ * @since 1.5
+ */
+ public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler()
+ {
+ return defaultHandler;
+ }
+
+ /**
+ * Returns the unique identifier for this thread. This ID is generated
+ * on thread creation, and may be re-used on its death.
+ *
+ * @return a positive long number representing the thread's ID.
+ * @since 1.5
+ */
+ public long getId()
+ {
+ return threadId;
+ }
+
+ /**
+ * <p>
+ * This interface is used to handle uncaught exceptions
+ * which cause a <code>Thread</code> to terminate. When
+ * a thread, t, is about to terminate due to an uncaught
+ * exception, the virtual machine looks for a class which
+ * implements this interface, in order to supply it with
+ * the dying thread and its uncaught exception.
+ * </p>
+ * <p>
+ * The virtual machine makes two attempts to find an
+ * appropriate handler for the uncaught exception, in
+ * the following order:
+ * </p>
+ * <ol>
+ * <li>
+ * <code>t.getUncaughtExceptionHandler()</code> --
+ * the dying thread is queried first for a handler
+ * specific to that thread.
+ * </li>
+ * <li>
+ * <code>t.getThreadGroup()</code> --
+ * the thread group of the dying thread is used to
+ * handle the exception. If the thread group has
+ * no special requirements for handling the exception,
+ * it may simply forward it on to
+ * <code>Thread.getDefaultUncaughtExceptionHandler()</code>,
+ * the default handler, which is used as a last resort.
+ * </li>
+ * </ol>
+ * <p>
+ * The first handler found is the one used to handle
+ * the uncaught exception.
+ * </p>
+ *
+ * @author Tom Tromey <[EMAIL PROTECTED]>
+ * @author Andrew John Hughes <[EMAIL PROTECTED]>
+ * @since 1.5
+ * @see Thread#getUncaughtExceptionHandler()
+ * @see Thread#setUncaughtExceptionHander(java.lang.Thread.UncaughtExceptionHandler)
+ * @see Thread#getDefaultUncaughtExceptionHandler()
+ * @see
+ * Thread#setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler)
+ */
+ public interface UncaughtExceptionHandler
+ {
+ /**
+ * Invoked by the virtual machine with the dying thread
+ * and the uncaught exception. Any exceptions thrown
+ * by this method are simply ignored by the virtual
+ * machine.
+ *
+ * @param thr the dying thread.
+ * @param exc the uncaught exception.
+ */
+ void uncaughtException(Thread thr, Throwable exc);
+ }
}
Index: java/lang/ThreadGroup.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/ThreadGroup.java,v
retrieving revision 1.19
diff -u -r1.19 ThreadGroup.java
--- java/lang/ThreadGroup.java 2 Jul 2005 20:32:39 -0000 1.19
+++ java/lang/ThreadGroup.java 12 Apr 2006 11:52:52 -0000
@@ -37,6 +37,7 @@
package java.lang;
+import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Vector;
/**
@@ -53,7 +54,7 @@
* @since 1.0
* @status updated to 1.4
*/
-public class ThreadGroup
+public class ThreadGroup implements UncaughtExceptionHandler
{
/** The Initial, top-level ThreadGroup. */
static ThreadGroup root = new ThreadGroup();
@@ -545,6 +546,8 @@
{
if (parent != null)
parent.uncaughtException(thread, t);
+ else if (Thread.getDefaultUncaughtExceptionHandler() != null)
+ Thread.getDefaultUncaughtExceptionHandler().uncaughtException(thread, t);
else if (! (t instanceof ThreadDeath))
{
if (t == null)
Index: vm/reference/java/lang/VMThread.java
===================================================================
RCS file: /cvsroot/classpath/classpath/vm/reference/java/lang/VMThread.java,v
retrieving revision 1.9
diff -u -r1.9 VMThread.java
--- vm/reference/java/lang/VMThread.java 1 Nov 2005 18:30:09 -0000 1.9
+++ vm/reference/java/lang/VMThread.java 12 Apr 2006 11:52:52 -0000
@@ -123,7 +123,10 @@
{
try
{
- thread.group.uncaughtException(thread, t);
+ Thread.UncaughtExceptionHandler handler = thread.getUncaughtExceptionHandler();
+ if (handler == null)
+ handler = thread.group;
+ handler.uncaughtException(thread, t);
}
catch(Throwable ignore)
{