jdk/src/share/classes/sun/awt/SunToolkit.java
changeset 13775 3ab536cab1d1
parent 13656 776ac504ea9b
child 15983 26a673dec5b2
--- a/jdk/src/share/classes/sun/awt/SunToolkit.java	Wed Sep 12 21:16:39 2012 +0400
+++ b/jdk/src/share/classes/sun/awt/SunToolkit.java	Thu Sep 13 19:53:13 2012 +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,48 @@
      * potentially lead to deadlock
      */
     public void flush() {
-        EventQueueItem tempQueue;
-        synchronized (this) {
-            tempQueue = queueHead;
-            queueHead = queueTail = null;
-            isFlushing = true;
-        }
+
+        Thread newThread = Thread.currentThread();
+
         try {
-            while (tempQueue != null) {
-                eventQueue.postEvent(tempQueue.event);
-                tempQueue = tempQueue.next;
+            EventQueueItem tempQueue;
+            synchronized (this) {
+                // Avoid method recursion
+                if (newThread == flushThread) {
+                    return;
+                }
+                // Wait for other threads' flushing
+                while (flushThread != null) {
+                    wait();
+                }
+                // Skip everything if queue is empty
+                if (queueHead == null) {
+                    return;
+                }
+                // Remember flushing thread
+                flushThread = newThread;
+
+                tempQueue = queueHead;
+                queueHead = queueTail = null;
+            }
+            try {
+                while (tempQueue != null) {
+                    eventQueue.postEvent(tempQueue.event);
+                    tempQueue = tempQueue.next;
+                }
+            }
+            finally {
+                // Only the flushing thread can get here
+                synchronized (this) {
+                    // Forget flushing thread, inform other pending threads
+                    flushThread = null;
+                    notifyAll();
+                }
             }
         }
-        finally {
-            isFlushing = false;
+        catch (InterruptedException e) {
+            // Couldn't allow exception go up, so at least recover the flag
+            newThread.interrupt();
         }
     }