JDK-4701990 : Headless mode hang on exit when Toolkit is accessed
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.4.1
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: solaris_8
  • CPU: sparc
  • Submitted: 2002-06-13
  • Updated: 2003-04-12
  • Resolved: 2002-09-06
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.2 mantisFixed
Related Reports
Relates :  
Relates :  
Description
This bug occurs on Solaris and Linux.

It the Toolkit is accessed when running in Headless mode, the Java app will hang on exit.  The following test can be used to reproduce this:

---
import java.awt.*;

public class GetToolkit {
    public static void main(String[] args) {
        Toolkit tk = Toolkit.getDefaultToolkit();
    }
}
---

When run normally, this program runs to completion and then exits.  When run w/ -Djava.awt.headless=true, the app never exits.  This is true on Solaris w/ 1.4 & 1.4.1b14, and on Linux with 1.4.1b14.  The thread dump looks like this:

Full thread dump Java HotSpot(TM) Client VM (1.4.1-beta-b14 mixed mode):

"DestroyJavaVM" prio=5 tid=0x2c518 nid=0x1 waiting on condition [0..ffbfe194]

"AWT-Shutdown" prio=5 tid=0x1860d8 nid=0x9 in Object.wait() [f23ff000..f23ffc24]
        at java.lang.Object.wait(Native Method)
        - waiting on <f2c9dea8> (a java.lang.Object)
        at java.lang.Object.wait(Object.java:426)
        at sun.awt.AWTAutoShutdown.run(AWTAutoShutdown.java:259)
        - locked <f2c9dea8> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:536)

"Signal Dispatcher" daemon prio=10 tid=0xb8fd0 nid=0x7 waiting on condition [0..0]

"Finalizer" daemon prio=8 tid=0xb43d8 nid=0x4 in Object.wait() [f2b7f000..f2b7fc24]
        at java.lang.Object.wait(Native Method)
        - waiting on <f2c00490> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:111)
        - locked <f2c00490> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:127)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=0xb39a0 nid=0x3 in Object.wait() [facff000..facffc24]
        at java.lang.Object.wait(Native Method)
        - waiting on <f2c00380> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:426)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:113)
        - locked <f2c00380> (a java.lang.ref.Reference$Lock)

"VM Thread" prio=5 tid=0xb2578 nid=0x2 runnable 

"VM Periodic Task Thread" prio=10 tid=0xb7d20 nid=0x5 waiting on condition 
"Suspend Checker Thread" prio=10 tid=0xb8678 nid=0x6 runnable 

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mantis mantis-b02 FIXED IN: mantis mantis-b02 INTEGRATED IN: mantis mantis-b02
14-06-2004

EVALUATION Commit to fix in mantis (hang). ###@###.### 2002-06-13 Name: dsR10078 Date: 06/14/2002 The bug is reproducible on Solaris/Linux. It doesn't manifest on Windows. The automatic shutdown implementation uses a boolean flag "toolkit thread busy" that indicates whether the toolkit thread processes a native event or waits for a new event to appear on the native event queue. Automatic shutdown starts only if this flag is cleared. The current implementation initially sets this flag in SunToolkit constructor. When the toolkit thread starts, it clears the flag every time it enters idle state and sets it back when it exits idle state. On Solaris/Linux, the toolkit thread is not started in headless mode, so the flag is never cleared and automatic shutdown never starts. On Windows, the toolkit thread is started even if in headless mode, so the flag is cleared and AWT shuts down properly. ###@###.### 2002-06-14 ======================================================================
14-06-2002

SUGGESTED FIX Name: dsR10078 Date: 06/25/2002 Do not set the "toolkit thread busy" early in SunToolkit constructor. Instead, set it just before the toolkit thread starts. This fix moves the point at which AWTAutoShutdown state is changed. As such it might cause regressions of two types: 1)the application exits unexpectedly, as AWT shuts down prematurely; 2)the application hangs, as AWT doesn't shutdown when expected. This fix affects only the boolean "toolkit thread busy" flag. This flag is initially set when the singleton Toolkit instance is created. After that, platform-specific {M|W}Toolkit constructors start the toolkit thread and all further modifications to this flag are performed from the toolkit thread. Let's W1 and W2 denote Mantis running in the same conditions (application, options, user actions, timings and so on) without the fix and with the fix respectively. For both W1 and W2 the flag is set before the toolkit thread starts. In W2 the flag is set later than in W1. Before the flag is initially set in W1 and after the flag is initially set in W2, W1 and W2 become identical, so the regression could only happen because of the difference in behavior between W1 and W2 in the interval T when the flag is set in W1 and cleared in W2. In W1 AWT cannot shutdown in the interval T, since this flag must be cleared before AWT shutdown is triggered. This guarantees that if AWT shuts down in W1 then AWT shuts down in W2. For this reason the regression of the second type is not possible. Let's consider the regression of the first type: W2 exits, W1 doesn't exit. Since W1 doesn't exit, W2 can exit only because AWT shuts down in W2 in the interval T. W2 can exit because of shutdown only if there are no alive non-daemon threads at some point in the interval T. This implies that the thread that creates the singleton Toolkit instance is a daemon thread. So, the regression of the first type could only happen if the Toolkit instance is created on a daemon thread and there is a point in the interval T at which there are no alive non-daemon threads. In this scenario W1 can also exit depending on timings unless the application synchronizes some non-daemon thread with operations performed by the Toolkit constructors in the interval T, so that this non-daemon thread exits just after some of these operations is performed. It is very unlikely that this situation can occur in some existing application, but we should keep it in mind. After this fix is applied, another problem manifests - the AWT shutdown uses SunToolkit.postEvent to post shutdown events to all event dispatch threads. SunToolkit.postEvent eventually invokes SunToolkit.wakeupEventQueue. SunToolkit.wakeupEventQueue is a native method that is not included in headless library. As a result AWT shutdown fails with UnsafisfiedLinkerError. Additional fix is to include SunToolkit.wakeupEventQueue in headless library. ###@###.### 2002-06-14 ====================================================================== Name: dsR10078 Date: 06/27/2002 Use of native methods to bypass access restrictions is a bad style and should be avoided if possible. An alternative solution for this case is not to use SunToolkit.postEvent to post shutdown events, but call EventQueue.postEvent directly instead. Since client code can install a custom EventQueue (either via "AWT.EventQueueClass" property or with EventQueue.push), EventQueue.postEvent should only be called on the thread that belongs to the thread group of the AppContext associated with this EventQueue. The solution is to check if the AppContext associated with the EventQueue is different from the current AppContext and if it is, create a new daemon thread (within the appropriate thread group) that will invoke EventQueue.postEvent. Additionally, we should take care of the class loader to be used to execute EventQueue.postEvent (see similar bug 4378087). The problem is that if we don't set an appropriate class loader for the thread that invokes EventQueue.postEvent, it can fail to load classes. The heuristic is to save off a reference to the context ClassLoader used to create the AppContext and set this ClassLoader for the thread. ###@###.### 2002-06-14 ======================================================================
14-06-2002