summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog28
-rw-r--r--NEWS2
-rw-r--r--java/lang/Thread.java178
-rw-r--r--java/lang/ThreadGroup.java5
-rw-r--r--vm/reference/java/lang/VMThread.java5
5 files changed, 215 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 8a2c28fa1..44fc3dcbc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2006-04-12 Mark Wielaard <mark@klomp.org>
+
+ Port UncaughtExceptionHandler support from generics branch.
+ * NEWS: Document Thread.UncaughtExceptionHandler VMThread change.
+
+2006-04-12 Andrew John Hughes <gnu_andrew@member.fsf.org>
+
+ * 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 <tromey@redhat.com>
+
+ * 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.
+
2006-04-11 Bryce McKinlay <mckinlay@redhat.com>
* java/io/DataOutputStream.java (writeUTF): Re-use fixed length byte
diff --git a/NEWS b/NEWS
index 2ea62aa48..1bc11e6ed 100644
--- a/NEWS
+++ b/NEWS
@@ -29,6 +29,8 @@ Runtime interface changes:
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)
diff --git a/java/lang/Thread.java b/java/lang/Thread.java
index 76df1037b..34825e3cd 100644
--- a/java/lang/Thread.java
+++ b/java/lang/Thread.java
@@ -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 @@ import java.util.Map;
* @author Tom Tromey
* @author John Keiser
* @author Eric Blake (ebb9@email.byu.edu)
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
* @see Runnable
* @see Runtime#exit(int)
* @see #run()
@@ -130,15 +131,27 @@ public class Thread implements Runnable
/** 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 @@ public class Thread implements Runnable
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 @@ public class Thread implements Runnable
this.priority = priority;
this.daemon = daemon;
this.contextClassLoader = ClassLoader.getSystemClassLoader();
+ synchronized (Thread.class)
+ {
+ this.threadId = nextThreadId++;
+ }
+
}
/**
@@ -1000,4 +1023,157 @@ public class Thread implements Runnable
}
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 <tromey@redhat.com>
+ * @author Andrew John Hughes <gnu_andrew@member.fsf.org>
+ * @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);
+ }
}
diff --git a/java/lang/ThreadGroup.java b/java/lang/ThreadGroup.java
index 6e4c27a71..7fbef88f4 100644
--- a/java/lang/ThreadGroup.java
+++ b/java/lang/ThreadGroup.java
@@ -37,6 +37,7 @@ exception statement from your version. */
package java.lang;
+import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Vector;
/**
@@ -53,7 +54,7 @@ import java.util.Vector;
* @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 @@ public class ThreadGroup
{
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)
diff --git a/vm/reference/java/lang/VMThread.java b/vm/reference/java/lang/VMThread.java
index aa0b8347a..b864b7f81 100644
--- a/vm/reference/java/lang/VMThread.java
+++ b/vm/reference/java/lang/VMThread.java
@@ -123,7 +123,10 @@ final class VMThread
{
try
{
- thread.group.uncaughtException(thread, t);
+ Thread.UncaughtExceptionHandler handler = thread.getUncaughtExceptionHandler();
+ if (handler == null)
+ handler = thread.group;
+ handler.uncaughtException(thread, t);
}
catch(Throwable ignore)
{