United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: 4826573 Deadlocks occur in window.createBufferStrategy()
4826573 : Deadlocks occur in window.createBufferStrategy()

Details
Type:
Bug
Submit Date:
2003-03-03
Status:
Resolved
Updated Date:
2003-09-29
Project Name:
JDK
Resolved Date:
2003-09-29
Component:
client-libs
OS:
windows_xp
Sub-Component:
2d
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
1.4.1_02
Fixed Versions:
5.0

Related Reports

Sub Tasks

Description

Name: jl125535			Date: 03/03/2003


FULL PRODUCT VERSION :
java version "1.4.1_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_02-b06)
Java HotSpot(TM) Client VM (build 1.4.1_02-b06, mixed mode)

FULL OS VERSION :
Microsoft Windows XP [Version 5.1.2600]

EXTRA RELEVANT SYSTEM CONFIGURATION :
Pentium 4 2.4Ghz, 512MB, Geforce4 Ti 4600 (tested on Nvidia drivers 40.72 and 41.09)

A DESCRIPTION OF THE PROBLEM :
(Regression from 1.4.1_01)

Calling window.createBufferStrategy() often deadlocks (about half the time on my machine.)

This did not occur in 1.4.0, 1.4.1 or 1.4.1_01

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run sample code at:
http://java.sun.com/docs/books/tutorial/extra/fullscreen/example-1dot4/MultiBufferTest.java

It may take several runs for deadlock to occur.

EXPECTED VERSUS ACTUAL BEHAVIOR :
deadlock should not occur.
(See error message)
locks occurs between main and AWT-EventQueue-0 threads on two objects:
a sun.awt.windows.WFramePeer
a java.awt.Component$AWTTreeLock

the main thread obtains locks in this order: WFramePeer, AWTTreeLock.
the awt thread obtains locks in this order: AWTTreeLock, WFramePeer.

thus, deadlock occurs.


ERROR MESSAGES/STACK TRACES THAT OCCUR :
Full thread dump Java HotSpot(TM) Client VM (1.4.1_02-b06 mixed mode):

"AWT-EventQueue-0" prio=7 tid=0x0AC9D450 nid=0x720 waiting for monitor entry [130df000..130dfd8c]
        at sun.awt.windows.WComponentPeer.replaceSurfaceData(WComponentPeer.java:316)
        - waiting to lock <02AE0350> (a sun.awt.windows.WFramePeer)
        - locked <02AE07B0> (a java.awt.Component$AWTTreeLock)
        at sun.awt.windows.WComponentPeer.displayChanged(WComponentPeer.java:351)
        at sun.awt.windows.WCanvasPeer.displayChanged(WCanvasPeer.java:42)
        at sun.awt.windows.WPanelPeer.displayChanged(WPanelPeer.java:118)
        at sun.awt.windows.WWindowPeer.displayChanged(WWindowPeer.java:185)
        at sun.awt.SunDisplayChanger.notifyListeners(SunDisplayChanger.java:102)

        at sun.awt.Win32GraphicsDevice.displayChanged(Win32GraphicsDevice.java:377)
        at sun.awt.Win32GraphicsEnvironment.displayChanged(Win32GraphicsEnvironment.java:92)
        at sun.awt.windows.WToolkit$4.run(WToolkit.java:723)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:178)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:448)
        at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:197)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:144)

        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:136)

        at java.awt.EventDispatchThread.run(EventDispatchThread.java:99)

"Java2D Disposer" daemon prio=10 tid=0x0AC99C50 nid=0x47c in Object.wait() [1308f000..1308fd8c]
        at java.lang.Object.wait(Native Method)
        - waiting on <02AE03F8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:111)
        - locked <02AE03F8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:127)
        at sun.java2d.Disposer.run(Disposer.java:97)
        at java.lang.Thread.run(Thread.java:536)

"AWT-Windows" daemon prio=7 tid=0x0AC96050 nid=0x6c0 runnable [1300f000..1300fd8c]
        at sun.awt.windows.WToolkit.eventLoop(Native Method)
        at sun.awt.windows.WToolkit.run(WToolkit.java:253)
        at java.lang.Thread.run(Thread.java:536)

"AWT-Shutdown" prio=5 tid=0x0AC943C8 nid=0x414 in Object.wait() [12fcf000..12fcfd8c]
        at java.lang.Object.wait(Native Method)
        - waiting on <02AE04C8> (a java.lang.Object)
        at java.lang.Object.wait(Object.java:426)
        at sun.awt.AWTAutoShutdown.run(AWTAutoShutdown.java:259)
        - locked <02AE04C8> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:536)

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

"Finalizer" daemon prio=9 tid=0x009A5378 nid=0x590 in Object.wait() [ab1f000..ab1fd8c]
        at java.lang.Object.wait(Native Method)
        - waiting on <02F6C358> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:111)
        - locked <02F6C358> (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=0x009A3FF8 nid=0x168 in Object.wait() [aadf000..aadfd8c]
        at java.lang.Object.wait(Native Method)
        - waiting on <02F6C3C0> (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 <02F6C3C0> (a java.lang.ref.Reference$Lock)

"main" prio=5 tid=0x00034648 nid=0x538 waiting for monitor entry [7f000..7fc40]
        at sun.awt.windows.WComponentPeer.replaceSurfaceData(WComponentPeer.java:315)
        - waiting to lock <02AE07B0> (a java.awt.Component$AWTTreeLock)
        at sun.awt.windows.WComponentPeer.createBuffers(WComponentPeer.java:698)

        - locked <02AE0350> (a sun.awt.windows.WFramePeer)
        at java.awt.Component$FlipBufferStrategy.createBuffers(Component.java:3048)
        at java.awt.Component$FlipBufferStrategy.<init>(Component.java:3017)
        at java.awt.Component.createBufferStrategy(Component.java:2926)
        at java.awt.Window.createBufferStrategy(Window.java:2046)
        at java.awt.Component.createBufferStrategy(Component.java:2858)
        at java.awt.Window.createBufferStrategy(Window.java:2021)
        at MultiBufferTest.<init>(MultiBufferTest.java:42)
        at MultiBufferTest.main(MultiBufferTest.java:102)

"VM Thread" prio=5 tid=0x009ECC98 nid=0x20c runnable

"VM Periodic Task Thread" prio=10 tid=0x009A77A0 nid=0x4fc waiting on condition

"Suspend Checker Thread" prio=10 tid=0x009A8428 nid=0x6b4 runnable

Found one Java-level deadlock:
=============================
"AWT-EventQueue-0":
  waiting to lock monitor 0x9a4aa4 (object 0x2ae0350, a sun.awt.windows.WFramePeer),
  which is held by "main"
"main":
  waiting to lock monitor 0x9a4a44 (object 0x2ae07b0, a java.awt.Component$AWTTreeLock),
  which is held by "AWT-EventQueue-0"

Java stack information for the threads listed above:
===================================================
"AWT-EventQueue-0":
        at sun.awt.windows.WComponentPeer.replaceSurfaceData(WComponentPeer.java:316)
        - waiting to lock <02AE0350> (a sun.awt.windows.WFramePeer)
        - locked <02AE07B0> (a java.awt.Component$AWTTreeLock)
        at sun.awt.windows.WComponentPeer.displayChanged(WComponentPeer.java:351)
        at sun.awt.windows.WCanvasPeer.displayChanged(WCanvasPeer.java:42)
        at sun.awt.windows.WPanelPeer.displayChanged(WPanelPeer.java:118)
        at sun.awt.windows.WWindowPeer.displayChanged(WWindowPeer.java:185)
        at sun.awt.SunDisplayChanger.notifyListeners(SunDisplayChanger.java:102)

        at sun.awt.Win32GraphicsDevice.displayChanged(Win32GraphicsDevice.java:377)
        at sun.awt.Win32GraphicsEnvironment.displayChanged(Win32GraphicsEnvironment.java:92)
        at sun.awt.windows.WToolkit$4.run(WToolkit.java:723)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:178)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:448)
        at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:197)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:144)

        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:136)

        at java.awt.EventDispatchThread.run(EventDispatchThread.java:99)
"main":
        at sun.awt.windows.WComponentPeer.replaceSurfaceData(WComponentPeer.java:315)
        - waiting to lock <02AE07B0> (a java.awt.Component$AWTTreeLock)
        at sun.awt.windows.WComponentPeer.createBuffers(WComponentPeer.java:698)

        - locked <02AE0350> (a sun.awt.windows.WFramePeer)
        at java.awt.Component$FlipBufferStrategy.createBuffers(Component.java:3048)
        at java.awt.Component$FlipBufferStrategy.<init>(Component.java:3017)
        at java.awt.Component.createBufferStrategy(Component.java:2926)
        at java.awt.Window.createBufferStrategy(Window.java:2046)
        at java.awt.Component.createBufferStrategy(Component.java:2858)
        at java.awt.Window.createBufferStrategy(Window.java:2021)
        at MultiBufferTest.<init>(MultiBufferTest.java:42)
        at MultiBufferTest.main(MultiBufferTest.java:102)

Found 1 deadlock.

REPRODUCIBILITY :
This bug can be reproduced often.

---------- BEGIN SOURCE ----------
/*
http://java.sun.com/docs/books/tutorial/extra/fullscreen/example-1dot4/MultiBufferTest.java
*/

/**
 * This test takes a number up to 13 as an argument (assumes 2 by
 * default) and creates a multiple buffer strategy with the number of
 * buffers given.  This application enters full-screen mode, if available,
 * and flips back and forth between each buffer (each signified by a different
 * color).
 */

import java.awt.*;
import java.awt.image.BufferStrategy;

public class MultiBufferTest {
    
    private static Color[] COLORS = new Color[] {
        Color.red, Color.blue, Color.green, Color.white, Color.black,
        Color.yellow, Color.gray, Color.cyan, Color.pink, Color.lightGray,
        Color.magenta, Color.orange, Color.darkGray };
    private static DisplayMode[] BEST_DISPLAY_MODES = new DisplayMode[] {
        new DisplayMode(640, 480, 32, 0),
        new DisplayMode(640, 480, 16, 0),
        new DisplayMode(640, 480, 8, 0)
    };
    
    Frame mainFrame;
    
    public MultiBufferTest(int numBuffers, GraphicsDevice device) {
        try {
            GraphicsConfiguration gc = device.getDefaultConfiguration();
            mainFrame = new Frame(gc);
            mainFrame.setUndecorated(true);
            mainFrame.setIgnoreRepaint(true);
            device.setFullScreenWindow(mainFrame);
            if (device.isDisplayChangeSupported()) {
                chooseBestDisplayMode(device);
            }
            Rectangle bounds = mainFrame.getBounds();
            mainFrame.createBufferStrategy(numBuffers);
            BufferStrategy bufferStrategy = mainFrame.getBufferStrategy();
            for (float lag = 2000.0f; lag > 0.00000006f; lag = lag / 1.33f) {
                for (int i = 0; i < numBuffers; i++) {
                    Graphics g = bufferStrategy.getDrawGraphics();
                    if (!bufferStrategy.contentsLost()) {
                        g.setColor(COLORS[i]);
                        g.fillRect(0,0,bounds.width, bounds.height);
                        bufferStrategy.show();
                        g.dispose();
                    }
                    try {
                        Thread.sleep((int)lag);
                    } catch (InterruptedException e) {}
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            device.setFullScreenWindow(null);
        }
    }
    
    private static DisplayMode getBestDisplayMode(GraphicsDevice device) {
        for (int x = 0; x < BEST_DISPLAY_MODES.length; x++) {
            DisplayMode[] modes = device.getDisplayModes();
            for (int i = 0; i < modes.length; i++) {
                if (modes[i].getWidth() == BEST_DISPLAY_MODES[x].getWidth()
                   && modes[i].getHeight() == BEST_DISPLAY_MODES[x].getHeight()
                   && modes[i].getBitDepth() == BEST_DISPLAY_MODES[x].getBitDepth()
                   ) {
                    return BEST_DISPLAY_MODES[x];
                }
            }
        }
        return null;
    }
    
    public static void chooseBestDisplayMode(GraphicsDevice device) {
        DisplayMode best = getBestDisplayMode(device);
        if (best != null) {
            device.setDisplayMode(best);
        }
    }
    
    public static void main(String[] args) {
        try {
            int numBuffers = 2;
            if (args != null && args.length > 0) {
                numBuffers = Integer.parseInt(args[0]);
                if (numBuffers < 2 || numBuffers > COLORS.length) {
                    System.err.println("Must specify between 2 and "
                        + COLORS.length + " buffers");
                    System.exit(1);
                }
            }
            GraphicsEnvironment env = GraphicsEnvironment.
                getLocalGraphicsEnvironment();
            GraphicsDevice device = env.getDefaultScreenDevice();
            MultiBufferTest test = new MultiBufferTest(numBuffers, device);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.exit(0);
    }
}


---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
lock the window's tree lock during the entire fullscreen/displaymode/bufferstrategy process.

synchronized (mainFrame.getTreeLock()) {
    device.setFullScreenWindow(mainFrame);
    if (device.isDisplayChangeSupported()) {
        chooseBestDisplayMode(device);
    }
    bounds = mainFrame.getBounds();
    mainFrame.createBufferStrategy(numBuffers);
}
(Review ID: 181959) 
======================================================================

                                    

Comments
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
tiger

FIXED IN:
tiger

INTEGRATED IN:
tiger
tiger-b22


                                     
2004-06-14
EVALUATION

Fullscreen is now owned by 2D.  The main thread should not be running once the 
EDT has started.  
###@###.### 2003-03-03

Committing to tiger.

Changing the interaction of threads is way too risky for this point in the 1.4.2 release.  The real fix for this problem lies somewhere in:
- ensuring one single lock for all awt interactions (instead of having both the AWT Tree Lock and various synchronized methods or blocks that synchronize on an instance)
- ensuring that multiple AWT locks (tree lock plus synchronized methods, etc.) are guaranteed to not happen out of order
- taking a close look at replaceSurface(), which takes both the Tree Lock and a lock on the peer instance
- taking a close look at displayChanged(), which forwards that windows event
onto the java event dispatch thread

It is the interaction between the dispatch thread (which is fielding the displayChanged() event do the to invokeLater() call in WToolkit.displayChanged()
and is thus calling replaceSurfaceData and taking the 2 locks in question) and the main thread (calling createBuffers() from the application, which locks the instance (via a synchronized method) and then calls replaceSurfaceData()).

###@###.### 2003-03-12

Relatively straightforward fix to this discrete problem: ensure that the locks taken in createBuffers() match the order of those taken in replaceSurfaceData.
Since createBuffers() calls replaceSurfaceData, we can actually find a way to avoid taking any locks in createBuffers() and do all of the work within the locks of replaceSurfaceData instead.  The only extra thing that createBuffers does is that it assigns a new value to the numBackBuffers variable in WComponentPeer.  We can create a new variation of replaceSurfaceData() that takes a new numBackBuffers value; this variation will do the same as the old
replaceSurfaceData(), except that it will also assign the numBackBuffers variable inside the locks, before it calls Win32SurfaceData.createData() (which creates the window surface with the appropriate number of back buffers).

Making this change will ensure that both the displayChange event and the createBuffers function will take the same locks in the same order (guaranteed, since they both take the same locks in the same (or similar) functions); thus no deadlock should be possible (at least not in this part of the code).

###@###.### 2003-09-21
                                     
2003-09-21
WORK AROUND

Call createBufferStrategy() on the event dispatch thread, thus guaranteeing that the events causing the deadlock will both occur on the same thread.  Do this by calling:
	EventQueue.invokeAndWait(new Runnable() {
		public void run() {
			frame.createBufferStrategy(2);
		}
	});

###@###.### 2003-03-13
                                     
2003-03-13



Hardware and Software, Engineered to Work Together