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)
 		{

Reply via email to