7108598: Pogo Table Games freeze with JDK 7
authorbagiras
Wed, 16 Nov 2011 15:40:59 +0400
changeset 11094 1f244f2719d3
parent 11093 e753252dc8a9
child 11095 51b42f922950
7108598: Pogo Table Games freeze with JDK 7 Reviewed-by: art, ant
jdk/src/share/classes/java/awt/Component.java
jdk/src/share/classes/java/awt/Container.java
jdk/test/java/awt/print/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java
--- a/jdk/src/share/classes/java/awt/Component.java	Sat Nov 12 04:13:38 2011 +0400
+++ b/jdk/src/share/classes/java/awt/Component.java	Wed Nov 16 15:40:59 2011 +0400
@@ -666,9 +666,10 @@
      * can lead to a deadlock if client code also uses synchronization
      * by a component object. For every such situation revealed we should
      * consider possibility of replacing "this" with the package private
-     * objectLock object introduced below. So far there're 2 issues known:
+     * objectLock object introduced below. So far there're 3 issues known:
      * - CR 6708322 (the getName/setName methods);
-     * - CR 6608764 (the PropertyChangeListener machinery).
+     * - CR 6608764 (the PropertyChangeListener machinery);
+     * - CR 7108598 (the Container.paint/KeyboardFocusManager.clearMostRecentFocusOwner methods).
      *
      * Note: this field is considered final, though readObject() prohibits
      * initializing final fields.
--- a/jdk/src/share/classes/java/awt/Container.java	Sat Nov 12 04:13:38 2011 +0400
+++ b/jdk/src/share/classes/java/awt/Container.java	Wed Nov 16 15:40:59 2011 +0400
@@ -1950,7 +1950,7 @@
      */
     public void paint(Graphics g) {
         if (isShowing()) {
-            synchronized (this) {
+            synchronized (getObjectLock()) {
                 if (printing) {
                     if (printingThreads.contains(Thread.currentThread())) {
                         return;
@@ -2004,7 +2004,7 @@
         if (isShowing()) {
             Thread t = Thread.currentThread();
             try {
-                synchronized (this) {
+                synchronized (getObjectLock()) {
                     if (printingThreads == null) {
                         printingThreads = new HashSet();
                     }
@@ -2013,7 +2013,7 @@
                 }
                 super.print(g);  // By default, Component.print() calls paint()
             } finally {
-                synchronized (this) {
+                synchronized (getObjectLock()) {
                     printingThreads.remove(t);
                     printing = !printingThreads.isEmpty();
                 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/print/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java	Wed Nov 16 15:40:59 2011 +0400
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7108598
+ * @summary Container.paint/KeyboardFocusManager.clearMostRecentFocusOwner methods deadlock
+ * @library ../../regtesthelpers
+ * @author Oleg Pekhovskiy
+ * @build Util
+ * @run main/timeout=20 PaintSetEnabledDeadlock
+ */
+
+import java.awt.*;
+import java.awt.event.*;
+import test.java.awt.regtesthelpers.Util;
+
+public class PaintSetEnabledDeadlock extends Frame {
+
+    final TestPanel panel;
+    final Button button;
+
+    public static void main(String[] args) {
+        PaintSetEnabledDeadlock frame = new PaintSetEnabledDeadlock();
+        frame.setSize(200, 200);
+        frame.setVisible(true);
+
+        Robot robot = Util.createRobot();
+        robot.setAutoDelay(100);
+        robot.setAutoWaitForIdle(true);
+
+        for (int i = 0; i < 20; ++i) {
+            Util.clickOnComp(frame.panel, robot);
+            Util.clickOnComp(frame.button, robot);
+        }
+
+        frame.panel.stop();
+        frame.dispose();
+
+        System.out.println("Test passed.");
+    }
+
+    public PaintSetEnabledDeadlock() {
+        super("7108598 test");
+        setLayout(new GridLayout(1, 2));
+        addWindowListener(new WindowAdapter() {
+
+            @Override
+            public void windowClosing(WindowEvent e) {
+                panel.stop();
+                System.exit(0);
+            }
+        });
+        panel = new TestPanel();
+        add(panel);
+        button = new Button("Enable");
+        button.addMouseListener(new MouseAdapter() {
+
+            @Override
+            public void mousePressed(MouseEvent e) {
+                panel.setEnabled(true);
+                panel.sync();
+                panel.repaint();
+            }
+        });
+        add(button);
+    }
+}
+
+class TestPanel extends Panel implements Runnable {
+
+    Image image = null;
+    Thread thread = null;
+    volatile boolean active = true;
+    final Object sync = new Object();
+    Panel panel = this;
+
+    public TestPanel() {
+        addMouseListener(new MouseAdapter() {
+
+            @Override
+            public void mouseReleased(MouseEvent e) {
+                synchronized (panel) {
+                    sync();
+                    panel.setEnabled(false);
+                }
+                panel.repaint();
+            }
+        });
+        thread = new Thread(this);
+        thread.start();
+    }
+
+    @Override
+    public void paint(Graphics paramGraphics) {
+        synchronized (getTreeLock()) {
+            Rectangle rect = getBounds();
+            if (image == null) {
+                image = createImage(rect.width, rect.height);
+            }
+
+            if (image != null) {
+                paramGraphics.drawImage(image, 0, 0, this);
+            }
+        }
+    }
+
+    @Override
+    public void run() {
+        while (active) {
+            try {
+                synchronized (sync) {
+                    sync.wait();
+                }
+            } catch (InterruptedException ex) {
+            }
+            if (active) {
+                draw();
+            }
+        }
+    }
+
+    public void stop() {
+        active = false;
+        try {
+            synchronized (sync) {
+                sync.notify();
+            }
+            synchronized (thread) {
+                thread.wait();
+            }
+        } catch (InterruptedException ex) {
+        }
+    }
+
+    public void draw() {
+        synchronized (getTreeLock()) {
+            if (image != null) {
+                Graphics localGraphics = image.getGraphics();
+                Dimension size = getSize();
+                localGraphics.setColor(isEnabled() ? Color.green : Color.red);
+                localGraphics.fillRect(0, 0, size.width, size.height);
+                super.paint(localGraphics);
+                localGraphics.dispose();
+                getTreeLock().notifyAll();
+            }
+        }
+    }
+
+    public void sync() {
+        synchronized (sync) {
+            sync.notify();
+        }
+    }
+}