JDK-4363409 : Linux: Drag-n-Drop operation hangs up X window system
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.3.0
  • Priority: P1
  • Status: Closed
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2000-08-17
  • Updated: 2000-08-30
  • Resolved: 2000-08-30
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.3.0 linux-rc1Fixed
Description

Name: skR10017			Date: 08/17/2000



The following test creates a frame with two panels.
Upper panel ( dndJTextFieldSource class ) is Drag-n-Drop source from which you can drag.
Lower panel ( dndJTextFieldTarget class ) is Drag-n-Drop target to which you can drop.
MouseThread is a Thread which is used for test automation.
Test is automated with Robot class and should hang up X window system without any user
interaction. Please wait about ten seconds until mouse cursor stops moving.
Then you will not be able to do anything with windows on the screen.
The failure appears about 7 times from 10 attempts.

Bug is reproducible under all modes ( Client,Server,Classic )
and all WM ( KDE, Enlightment ) and under beta13 and beta15.

Bug is not reproducible under beta11 and builds with lower numbers.


------------------------test.java-----------------------------
import java.awt.*;
import java.awt.event.*;
import java.awt.dnd.*;
import java.awt.datatransfer.*;
import javax.swing.*;
import java.util.*;
import java.awt.Robot.*;

public class test
{
    public static MouseThread mt;

    public static void main(String [] args)
    {
 JPanel panel;
 Component dndsource;
 Component dndtarget;
        JPanel mainpanel = new JPanel();
        mainpanel.setLayout(new BoxLayout(mainpanel, BoxLayout.Y_AXIS));
        panel = new JPanel();
        dndtarget = (Component) new dndJTextFieldTarget("");
        dndsource = (Component) new dndJTextFieldSource("");
        panel.add(dndsource);
        mainpanel.add(panel);
        panel = new JPanel();
        panel.add(dndtarget);
        mainpanel.add(panel);
        JFrame frame=new JFrame();
        frame.getContentPane().add(mainpanel);
        frame.pack();
        frame.show();
        frame.setLocation(50,50);

        // Automation part:
        try
        {
            Thread.sleep(2000);

            Robot robot=new Robot();

            robot.mouseMove(150,150);
            Thread.sleep(100);
            robot.mousePress(InputEvent.BUTTON1_MASK);
            Thread.sleep(100);
            robot.mouseMove(150,300);

            mt=new MouseThread();
            mt.start();

            Thread.sleep(2000);

            robot.mouseRelease(InputEvent.BUTTON1_MASK);

            mt.shouldStop=true;
        }
        catch(Exception e)
        {
            System.out.println(e);
        }
    }
}

class MouseThread extends Thread
{
    public boolean shouldStop;
    public void run()
    {
        try
        {
            shouldStop=false;
            Robot robot=new Robot();

            for(;;)
            {

                for(int i=300;i<400;i++)
                {
                    if(shouldStop)break;
                    robot.mouseMove(150,i);
                    yield();
                }
                for(int i=400;i>300;i--)
                {
                    if(shouldStop)break;
                    robot.mouseMove(150,i);
                    yield();
                }
                if(shouldStop)break;
            }
        }
        catch(Exception e)
        {
            System.out.println(e);
        }

    }
}

class dndJTextFieldSource extends JTextField implements Transferable,
       DragGestureListener,
       DragSourceListener
{
 private static    DataFlavor[] dataFlavors = null;
        static {

            Vector tmpFlavors = new Vector();

            tmpFlavors.addElement(DataFlavor.stringFlavor);
            try {
                tmpFlavors.addElement(DataFlavor.stringFlavor);
                tmpFlavors.addElement(new DataFlavor("text/plain"));
            }
            catch (ClassNotFoundException e) {
            }
            catch (Exception e) {
            }
            dataFlavors = new DataFlavor[tmpFlavors.size()];
            tmpFlavors.copyInto(dataFlavors);
        }

 dndJTextFieldSource(String s) {
  super(s);
  DragSource dragSource = DragSource.getDefaultDragSource();
  dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, this);
 }
   public Dimension getPreferredSize() {
  return new Dimension(200, 150);
 }
 public Dimension getMaximumSize() {
  return new Dimension(200, 150);
 }
 public void dragGestureRecognized(DragGestureEvent gestureEvent) {
  gestureEvent.startDrag(null, this, this);
 }
 public void dragEnter(DragSourceDragEvent dragEvent) {
 }
 public void dragOver(DragSourceDragEvent dragEvent) {
 }
 public void dragGestureChanged(DragSourceDragEvent dragEvent) {
 }
 public void dragExit(DragSourceEvent dragEvent) {
 }
 public void dragDropEnd(DragSourceDropEvent dragEvent) {
 }
 public void dropActionChanged(DragSourceDragEvent event) {
 }
 public DataFlavor[] getTransferDataFlavors() {
            return dataFlavors;
 }
 public boolean isDataFlavorSupported(DataFlavor queryFlavor) {
            return true;
 }
 public Object getTransferData(DataFlavor chosenFlavor) throws UnsupportedFlavorException  {
            String text = getText();
            return text;
 }
}

class dndJTextFieldTarget extends JTextField implements DropTargetListener {
 dndJTextFieldTarget(String text) {
            super(text);
            setDropTarget(new DropTarget(this, this));
 }
 public Dimension getPreferredSize() {
  return new Dimension(200, 250);
 }
 public void dragEnter(DropTargetDragEvent event) {
 }
 public void dragOver(DropTargetDragEvent event) {
 }
 public void dragExit(DropTargetEvent event) {
 }
 public void drop(DropTargetDropEvent dropEvent) {
        }
 public void dragScroll(DropTargetDragEvent event) {
 }
 public void dropActionChanged(DropTargetDragEvent event) {
 }
}
--------------------------------------------------------------------------

======================================================================

Full thread dump:

"Thread-1" prio=1 tid=0x804e768 nid=0x32ea runnable [0..0xbfffd844]

"TimerQueue" daemon prio=1 tid=0x81b69f8 nid=0x3324 waiting on monitor [0xbe1ff000..0xbe1ffac4]
        at java.lang.Object.wait(Native Method)
        at javax.swing.TimerQueue.postExpiredTimers(TimerQueue.java:215)
        at javax.swing.TimerQueue.run(TimerQueue.java:230)
        at java.lang.Thread.run(Thread.java:484)

"Screen Updater" prio=1 tid=0x81a0eb8 nid=0x3322 waiting on monitor [0xbe3ff000..0xbe3ffac4]
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:420)
        at sun.awt.ScreenUpdater.nextEntry(ScreenUpdater.java:75)
        at sun.awt.ScreenUpdater.run(ScreenUpdater.java:95)

"AWT-Motif" prio=1 tid=0x813bc58 nid=0x3320 waiting for monitor entry [0xbe7fe000..0xbe7ffac4]
        at sun.awt.motif.MDropTargetContextPeer.handleEnterMessage(MDropTargetContextPeer.java:408)
        at sun.awt.motif.MToolkit.run(Native Method)
        at java.lang.Thread.run(Thread.java:484)

"SunToolkit.PostEventQueue-0" prio=1 tid=0x812d120 nid=0x331f waiting on monitor [0xbe9ff000..0xbe9ffac4]
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:420)
        at sun.awt.PostEventQueue.run(SunToolkit.java:496)

"AWT-EventQueue-0" prio=1 tid=0x812ca68 nid=0x331e waiting for monitor entry [0xbebff000..0xbebffac4]
        at sun.awt.motif.MComponentPeer.pGetLocationOnScreen(Native Method)
        at sun.awt.motif.MComponentPeer.getLocationOnScreen(MComponentPeer.java:649)
        at java.awt.Component.getLocationOnScreen_NoTreeLock(Component.java:1231)
        at java.awt.Component.getLocationOnScreen(Component.java:1216)
        at javax.swing.Autoscroller$AutoScrollTimerAction.actionPerformed(Autoscroller.java:49)
        at javax.swing.Timer.fireActionPerformed(Timer.java:150)
        at javax.swing.Timer$DoPostEvent.run(Timer.java:108)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:154)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:331)
        at java.awt.EventDispatchThread.pumpOneEvent(EventDispatchThread.java:103)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:84)

"Signal Dispatcher" daemon prio=1 tid=0x8095030 nid=0x331c runnable [0..0]

"Finalizer" daemon prio=1 tid=0x808e0e0 nid=0x331a waiting on monitor [0xbf3ff000..0xbf3ffac4]
        at java.lang.Object.wait(Native Method)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:108)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:123)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:162)

"Reference Handler" daemon prio=1 tid=0x808d5b8 nid=0x3319 waiting on monitor [0xbf5ff000..0xbf5ffac4]
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:420)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:110)

"VM Thread" prio=1 tid=0x8058bb0 nid=0x3318 runnable 

"VM Periodic Task Thread" prio=1 tid=0x8094710 nid=0x331b waiting on monitor 

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: generic FIXED IN: kest-linux-rc1 INTEGRATED IN: kest-linux-rc1 VERIFIED IN: kest-linux-rc1
14-06-2004

EVALUATION Recall that previously we had changed all of the Motif DnD callback functions to hold AWT_LOCK during Java upcalls. We had also changed the calls to invokeAndWait (and one call to invokeLater which subsequently blocked) to release AWT_LOCK beforehand. The postulate here was that the DnD subsystem was in a consistent state and could tolerate changes to the Component hierarchy, for example. This argument is similar to the one I made on Windows when I added code to start a new native message pump. Unfortunately, these changes were not sufficient because client code could still deadlock with the DnD subsystem over the tree lock. MDropTargetContextPeer attemps to acquire the tree lock in four places, each before calls to findComponentAt. If a client-code method has the tree lock at this point, and has called down into native code, deadlock will ensue. The fix is to remove the synchronization on the tree lock. While this seems dangerous, it is actually the same fix we applied across the code in 1.1.7. In that release, we changed all of the Unix native code to hold AWT_LOCK during upcalls, and removed synchronization on the tree lock from the peers. The reasoning was that while holding the AWT_LOCK, no substantive changes can be made to the Component hierarchy anyways. For example, a Component cannot be removed from its Container because removeNotify() will block in native code. david.mendenhall@east 2000-08-22
22-08-2000