--- 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();
+ }
+ }
+}