Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4098525
Votes 3
Synopsis showing Modal dialog from JPanel's paint/addNotify/doLayout causes deadlock
Category java:classes_swing
Reported Against 1.1.5
Release Fixed
State 11-Closed, Not a Defect, bug
Priority: 4-Low
Related Bugs
Submit Date 10-DEC-1997
Description




I am attempting to display a modal dialog before my GUI appears, but when I know the GUI is on
it's way to being shown.  I've tried using addNotify, doLayout, and paint (among other things).  I
was successful using addNotify on JDK 1.1.4.  I have not been able to get anything to work using 1.1.5.

This is a serious problem for my project.

There are a couple of problems.

1. If the class displaying the dialog is a subclass of Panel, the dialog will work if shown from
paint(), but not addNotify() or doLayout().  Displaying FileDialog rather than my Dialog subclass
works in all cases.  What is FileDialog's secret?

2.  If the class displaying the dialog is a subclass of JPanel, the dialog never works.  In the case
of paint(), the button seems to work, but the dispose() of the dialog hangs. Using addNotify or
doLayout will hang.   Again, FileDialog works in all cases.

I would like to have the calling object be a subclass of JPanel and override addNotify (which
did work with 1.1.4).  Even if I get something to work I am concerned since I don't understand
why some cases work and others don't, and what broke in 1.1.5.

Here is some code which displays the problems, there is the main class (Tester) and a dialog
class.  Commenting out different lines will show the different behaviors.

-----------------------------------------------------------------------

/*
If use Panel as superclass:
                addNotify   doLayout    paint
myDialog        no          no          yes
fileDialog      yes         yes         yes

If use JPanel as superclass:
Using paint, buttons work, but dialog.dispose() hangs.
Using addNotify and doLayout, nothing works.
                addNotify   doLayout    paint
myDialog        no          no          no
fileDialog      yes         yes         yes
*/

import java.awt.event.*;
import java.awt.*;
import java.util.*;
import com.sun.java.swing.*;


public class Tester
//extends Panel
extends JPanel
implements ActionListener
{

boolean addNotify = false, paint = false, doLayout = false;
FileDialog fileDialog;
MyDialog myDialog;
static JFrame frame;
boolean firstTime = true;

public Tester ()
throws Exception
{
	super();

	//---- Comment out all but one of the following 3 lines ---
	//addNotify = true;
	paint = true;
	//doLayout = true;

	if (addNotify)
        add(new Label("Dialog displayed during addNotify."));
	if (paint)
        add(new Label("Dialog displayed during paint."));
	if (doLayout)
        add(new Label("Dialog displayed during doLayout."));
    fileDialog = new FileDialog(frame);
    myDialog = new MyDialog(frame);
    Button button = new Button("dialog");
    button.addActionListener(this);
    add(button);
}

public void actionPerformed(ActionEvent event)
{
    myDialog.show();  // this works here
}

void showDialogs()
{
    fileDialog.show();
    myDialog.show();
}

public void addNotify()
{
    super.addNotify();
    if (addNotify)
        showDialogs();
}
public void paint(Graphics g)
{
    super.paint(g);
    if (paint && firstTime)
    {
        firstTime = false;
        showDialogs();
    }
}
public void doLayout()
{
    super.doLayout();
    if (doLayout && firstTime)
    {
        firstTime = false;
        showDialogs();
    }
}

public static void main(String args[])
    throws Exception
{
    WindowListener l = new WindowAdapter()
    {
        public void windowClosing(WindowEvent e)
        {
            System.exit(0);
        }
    };
	frame = new JFrame ("Test");
    frame.addWindowListener(l);
    frame.getContentPane().setLayout(new BorderLayout());
    Tester gui = new Tester();
    frame.getContentPane().add("Center", gui);
	frame.setSize(800, 600);
    frame.pack();
    frame.setVisible(true);
}

}


-----------------------------------------------------------------------


import java.awt.*;
import java.awt.event.*;


class MyDialog extends Dialog
implements ActionListener
{
  MyDialog(Frame parent)
  {
    //super(parent, "My Dialog", false);  // works
    super(parent, "My Dialog", true);  // doesn't

    add(new Label("Press the button"));

    Button okButton = new Button("OK");
    okButton.addActionListener(this);
    add(okButton);

    pack();
  }

  public void actionPerformed(ActionEvent event)
  {
    System.out.println("In handler");
    dispose();
    System.out.println("After dispose");
  }

}
(Review ID: 21742)
======================================================================
Work Around
N/A
Evaluation
[aim 1/8/97]
A thread dump shows a deadlock between "AWT-Modal" & "AWT-EventQueue-0"
threads. (thread dump below)

The reason this occurs with swing's JPanel and not with a regular
AWT Panel is because swing's JComponent paint() method will invoke
it's paintChildren method which acquires the AWT lock via getTreeLock().
So the thread that is in paintChildren ("AWT-EventQueue-0") has this
unified lock and then calls Dialog.show(), which then does a wait()
(for reasons I won't go into here) and starts up another thread,
"AWT-Modal", which then shows the dialog and inserts itself into the
Motif X thread queue processing.  "AWT-Modal" (via a map event) then
calls MPanelPeer.makeCursorsVisible, which attempts to get the
treeLock. hence->deadlock!  AWT-EventQueue-0 holds the treeLock and
is waiting on the AWT-Modal thread object, and AWT-Modal holds it's
lock and is waiting attempting to acquire treeLock.


   "AWT-Finalizer" (TID:0xee70ca00, sys_thread_t:0xede91db8, state:CW) prio=9
	java.lang.Object.wait(Object.java)
	sun.awt.AWTFinalizer.run(AWTFinalizer.java:48)
    "AWT-Modal" (TID:0xee70c890, sys_thread_t:0xedec1db8, state:MW) prio=5
	sun.awt.motif.MPanelPeer.makeCursorsVisible(MPanelPeer.java:50)
	sun.awt.motif.ModalThread.run(MDialogPeer.java:148)
    "AWT-Dispatch-Proxy" (TID:0xee70ca38, sys_thread_t:0xedef1db8, state:MW) prio=5
	java.awt.Container.getComponents(Container.java:138)
	com.sun.java.swing.JComponent.rectangleIsObscured(JComponent.java:2356)
	com.sun.java.swing.JComponent.paint(JComponent.java:536)
	java.awt.Container.paint(Container.java:702)
	com.sun.java.swing.JFrame.update(JFrame.java:172)
	java.awt.Component.dispatchEventImpl(Component.java:1725)
	java.awt.Container.dispatchEventImpl(Container.java:939)
	java.awt.Window.dispatchEventImpl(Window.java:443)
	java.awt.Component.dispatchEvent(Component.java:1704)
	java.awt.EventDispatchThread.run(EventDispatchThread.java:63)
    "AWT-Dispatch-Proxy" (TID:0xee70d0f0, sys_thread_t:0xedf21db8, state:MW) prio=5
	java.awt.Component$NativeInLightFixer.componentMoved(Component.java:2863)
	java.awt.AWTEventMulticaster.componentMoved(AWTEventMulticaster.java:115)
	java.awt.Component.processComponentEvent(Component.java:2173)
	java.awt.Component.processEvent(Component.java:2141)
	java.awt.Container.processEvent(Container.java:894)
	java.awt.Component.dispatchEventImpl(Component.java:1764)
	java.awt.Container.dispatchEventImpl(Container.java:939)
	java.awt.Component.dispatchEvent(Component.java:1704)
	java.awt.EventDispatchThread.run(EventDispatchThread.java:63)
    "TimerQueue" (TID:0xee70d048, sys_thread_t:0xedf51db8, state:CW) prio=4
	com.sun.java.swing.TimerQueue.run(TimerQueue.java:235)
	java.lang.Thread.run(Thread.java)
    "Screen Updater" (TID:0xee70cd98, sys_thread_t:0xedf81db8, state:CW) prio=4
	java.lang.Object.wait(Object.java)
	sun.awt.ScreenUpdater.nextEntry(ScreenUpdater.java:78)
	sun.awt.ScreenUpdater.run(ScreenUpdater.java:98)
    "AWT-Motif" (TID:0xee706960, sys_thread_t:0xedfb1db8, state:CW) prio=5
	java.lang.Thread.run(Thread.java)
    "AWT-Input" (TID:0xee706980, sys_thread_t:0xedfe1db8, state:CW) prio=5
    "AWT-EventQueue-0" (TID:0xee706998, sys_thread_t:0xee011db8, state:CW) prio=5
	java.lang.Object.wait(Object.java)
	sun.awt.motif.MDialogPeer.show(MDialogPeer.java:104)
	java.awt.Dialog.show(Dialog.java:220)
	Tester.showDialogs(Tester.java:64)
	Tester.paint(Tester.java:79)
	com.sun.java.swing.JComponent.paintChildren(JComponent.java:394)
	com.sun.java.swing.JComponent.paint(JComponent.java:540)
	com.sun.java.swing.JComponent.paintChildren(JComponent.java:394)
	com.sun.java.swing.JComponent.paint(JComponent.java:540)
	com.sun.java.swing.JLayeredPane.paint(JLayeredPane.java:393)
	com.sun.java.swing.JComponent.paintChildren(JComponent.java:394)
	com.sun.java.swing.JComponent.paint(JComponent.java:525)
	java.awt.Container.paint(Container.java:702)
	java.awt.Component.dispatchEventImpl(Component.java:1723)
	java.awt.Container.dispatchEventImpl(Container.java:939)
	java.awt.Window.dispatchEventImpl(Window.java:443)
	java.awt.Component.dispatchEvent(Component.java:1704)
	java.awt.EventDispatchThread.run(EventDispatchThread.java:63)
    "Finalizer thread" (TID:0xee700220, sys_thread_t:0xee2c1db8, state:CW) prio=1
    "Async Garbage Collector" (TID:0xee700268, sys_thread_t:0xee2f1db8, state:CW) prio=1
    "Idle thread" (TID:0xee7002b0, sys_thread_t:0xee3c1db8, state:R) prio=0 *current thread*
    "Clock" (TID:0xee700088, sys_thread_t:0xee3f1db8, state:CW) prio=12
    "main" (TID:0xee7000b0, sys_thread_t:0x69420, state:CW) prio=5
Monitor Cache Dump:
     xxxxx@xxxxx /EE746B18: owner "AWT-EventQueue-0" (0xee011db8, 3 entries)
	Waiting to enter:
	    "AWT-Dispatch-Proxy" (0xedf21db8)
	    "AWT-Dispatch-Proxy" (0xedef1db8)
	    "AWT-Modal" (0xedec1db8)
     xxxxx@xxxxx /EE765380: <unowned>
	Waiting to be notified:
	    "Screen Updater" (0xedf81db8)
     xxxxx@xxxxx /EE754558: <unowned>
	Waiting to be notified:
	    "AWT-Input" (0xedfe1db8)
	    "AWT-Motif" (0xedfb1db8)
     xxxxx@xxxxx /EE767340: <unowned>
	Waiting to be notified:
	    "AWT-Finalizer" (0xede91db8)
    <unknown key> (0xee2f1db8): <unowned>
	Waiting to be notified:
	    "Async Garbage Collector" (0xee2f1db8)
     xxxxx@xxxxx /EE765AF0: <unowned>
	Waiting to be notified:
	    "TimerQueue" (0xedf51db8)
     xxxxx@xxxxx /EE7678F0: owner "AWT-Modal" (0xedec1db8, 1 entry)
	Waiting to be notified:
	    "AWT-EventQueue-0" (0xee011db8)

The program should *not* show the modal dialog from the paint() method!!

I suspect the program also deadlocks in the addNotify/doLayout cases because
it's likely that in jdk1.1.5, AWT was fixed to properly acquire the
treeLock during these methods.

(This program is a good example of why Swing has made the statement that
it's not multi-thread capable; see http://java.sun.com/products/jfc/swingdoc/threads.html for more details).


-----------

A program should never call show() on a modal dialog while holding the
AWT treelock (or really any other locks on the GUI components) because
be design, this call will block while holding the lock.

This isn't something we can fix.

 xxxxx@xxxxx  1998-10-09
Comments
  
  Include a link with my name & email   

Submitted On 14-MAY-2000
seleyS
TimerQueue&quot; (TID:0xee70d048, sys_thread_t:0xedf51db8, state:CW) prio=4



PLEASE NOTE: JDK6 is formerly known as Project Mustang