src/share/classes/sun/awt/SunToolkit.java

Print this page

        

@@ -504,44 +504,29 @@
                 }
             }, PeerEvent.ULTIMATE_PRIORITY_EVENT);
         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();
-        }
+        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);
         if (postEventQueue != null) {
-            return postEventQueue.noEvents();
-        } else {
-            return true;
+            postEventQueue.flush();
         }
     }
 
     /*
      * Execute a chunk of code on the Java event handler thread for the

@@ -2043,45 +2028,69 @@
 class PostEventQueue {
     private EventQueueItem queueHead = null;
     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
      * can be posted to this queue.
      *
      * 7177040: The method couldn't be wholly synchronized because of calls
      * of EventQueue.postEvent() that uses pushPopLock, otherwise it could
      * potentially lead to deadlock
      */
     public void flush() {
+
+        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;
-            isFlushing = true;
         }
-        try {
             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();
+                }
+            }
         }
     }
 
     /*
      * Enqueue an AWTEvent to be posted to the Java EventQueue.