--- old/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java 2012-09-08 02:30:02.012264300 +0400 +++ new/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java 2012-09-08 02:30:01.105212400 +0400 @@ -536,7 +536,7 @@ SunToolkit.postEvent(appContext, invocationEvent); // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock - sun.awt.SunToolkitSubclass.flushPendingEvents(appContext); + SunToolkit.flushPendingEvents(appContext); } else { // This should be the equivalent to EventQueue.invokeAndWait ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent); @@ -561,7 +561,7 @@ SunToolkit.postEvent(appContext, invocationEvent); // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock - sun.awt.SunToolkitSubclass.flushPendingEvents(appContext); + SunToolkit.flushPendingEvents(appContext); } else { // This should be the equivalent to EventQueue.invokeAndWait ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent); --- old/src/share/classes/java/awt/EventQueue.java 2012-09-08 02:30:08.055610000 +0400 +++ new/src/share/classes/java/awt/EventQueue.java 2012-09-08 02:30:07.181560000 +0400 @@ -1046,6 +1046,10 @@ } final boolean detachDispatchThread(EventDispatchThread edt, boolean forceDetach) { + /* + * Minimize discard possibility for non-posted events + */ + SunToolkit.flushPendingEvents(); /* * This synchronized block is to secure that the event dispatch * thread won't die in the middle of posting a new event to the @@ -1064,7 +1068,7 @@ * Fix for 4648733. Check both the associated java event * queue and the PostEventQueue. */ - if (!forceDetach && (peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) { + if (!forceDetach && (peekEvent() != null)) { return false; } dispatchThread = null; --- old/src/share/classes/sun/awt/SunToolkit.java 2012-09-08 02:30:12.860884800 +0400 +++ new/src/share/classes/sun/awt/SunToolkit.java 2012-09-08 02:30:12.007836000 +0400 @@ -506,40 +506,25 @@ postEvent(targetToAppContext(e.getSource()), pe); } - protected static final Lock flushLock = new ReentrantLock(); - private static boolean isFlushingPendingEvents = false; - /* * Flush any pending events which haven't been posted to the AWT * EventQueue yet. */ public static void flushPendingEvents() { - flushLock.lock(); - try { - // Don't call flushPendingEvents() recursively - if (!isFlushingPendingEvents) { - isFlushingPendingEvents = true; - AppContext appContext = AppContext.getAppContext(); - PostEventQueue postEventQueue = - (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY); - if (postEventQueue != null) { - postEventQueue.flush(); - } - } - } finally { - isFlushingPendingEvents = false; - flushLock.unlock(); - } + AppContext appContext = AppContext.getAppContext(); + flushPendingEvents(appContext); } - public static boolean isPostEventQueueEmpty() { - AppContext appContext = AppContext.getAppContext(); + /* + * Flush the PostEventQueue for the right AppContext. + * The default flushPendingEvents only flushes the thread-local context, + * which is not always correct, c.f. 3746956 + */ + public static void flushPendingEvents(AppContext appContext) { PostEventQueue postEventQueue = - (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY); + (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY); if (postEventQueue != null) { - return postEventQueue.noEvents(); - } else { - return true; + postEventQueue.flush(); } } @@ -2045,17 +2030,12 @@ private EventQueueItem queueTail = null; private final EventQueue eventQueue; - // For the case when queue is cleared but events are not posted - private volatile boolean isFlushing = false; + private Thread flushThread = null; PostEventQueue(EventQueue eq) { eventQueue = eq; } - public synchronized boolean noEvents() { - return queueHead == null && !isFlushing; - } - /* * Continually post pending AWTEvents to the Java EventQueue. The method * is synchronized to ensure the flush is completed before a new event @@ -2066,20 +2046,49 @@ * potentially lead to deadlock */ public void flush() { - EventQueueItem tempQueue; - synchronized (this) { - tempQueue = queueHead; - queueHead = queueTail = null; - isFlushing = true; - } + + Thread newThread = Thread.currentThread(); + try { + EventQueueItem tempQueue; + synchronized (this) { + // Avoid method recursion + if (newThread == flushThread) { + newThread = null; + return; + } + // Wait for other threads' flushing + while (flushThread != null) { + wait(); + } + // Skip everything if queue is empty + if (queueHead == null) { + notifyAll(); + return; + } + // Remember flushing thread + flushThread = newThread; + + tempQueue = queueHead; + queueHead = queueTail = null; + } while (tempQueue != null) { eventQueue.postEvent(tempQueue.event); tempQueue = tempQueue.next; } } + catch (InterruptedException e) { + // Couldn't allow exception go up, so at least recover the flag + newThread.interrupt(); + } finally { - isFlushing = false; + synchronized (this) { + // Forget flushing thread, inform other pending threads + if (newThread == flushThread) { + flushThread = null; + notifyAll(); + } + } } } --- old/src/macosx/classes/sun/awt/SunToolkitSubclass.java 2012-09-08 02:30:17.362142300 +0400 +++ /dev/null 2012-09-08 02:30:17.000000000 +0400 @@ -1,40 +0,0 @@ -/* - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package sun.awt; - -// This class exists only so we can flush the PostEventQueue for the right AppContext -// The default flushPendingEvents only flushes the thread-local context, which is wrong. -// c.f. 3746956 -public abstract class SunToolkitSubclass extends SunToolkit { - public static void flushPendingEvents(AppContext appContext) { - flushLock.lock(); - PostEventQueue postEventQueue = (PostEventQueue)appContext.get("PostEventQueue"); - if (postEventQueue != null) { - postEventQueue.flush(); - } - flushLock.unlock(); - } -}