< prev index next >

src/java.desktop/share/classes/java/awt/SequencedEvent.java

Print this page
rev 52472 : 8204142: AWT hang occurs when sequenced events arrive out of sequence in multiple AppContexts
Summary: Improvements on the synchronization of SequencedEvent events from different AppContexts
Reviewed-by: serb

@@ -25,10 +25,11 @@
 
 package java.awt;
 
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.Iterator;
 import java.util.LinkedList;
 import sun.awt.AWTAccessor;
 import sun.awt.AppContext;
 import sun.awt.SunToolkit;
 

@@ -54,10 +55,11 @@
     private static final LinkedList<SequencedEvent> list = new LinkedList<>();
 
     private final AWTEvent nested;
     private AppContext appContext;
     private boolean disposed;
+    private final LinkedList<AWTEvent> pendingEvents = new LinkedList<>();
 
     private static boolean fxAppThreadIsDispatchThread;
     private Thread fxCheckSequenceThread;
     static {
         AWTAccessor.setSequencedEventAccessor(new AWTAccessor.SequencedEventAccessor() {

@@ -79,10 +81,39 @@
                 return null;
             }
         });
     }
 
+    private static final class SequencedEventsFilter implements EventFilter {
+        private final SequencedEvent currentSequencedEvent;
+        private SequencedEventsFilter(SequencedEvent currentSequencedEvent) {
+            this.currentSequencedEvent = currentSequencedEvent;
+        }
+        @Override
+        public FilterAction acceptEvent(AWTEvent ev) {
+            if (ev.getID() == ID) {
+                // Move forward dispatching only if the event is previous
+                // in SequencedEvent.list. Otherwise, hold it for reposting later.
+                synchronized (SequencedEvent.class) {
+                    Iterator<SequencedEvent> it = list.iterator();
+                    while (it.hasNext()) {
+                        SequencedEvent iev = it.next();
+                        if (iev.equals(currentSequencedEvent)) {
+                            break;
+                        } else if (iev.equals(ev)) {
+                            return FilterAction.ACCEPT;
+                        }
+                    }
+                }
+            } else if (ev.getID() == SentEvent.ID) {
+                return FilterAction.ACCEPT;
+            }
+            currentSequencedEvent.pendingEvents.add(ev);
+            return FilterAction.REJECT;
+        }
+    }
+
     /**
      * Constructs a new SequencedEvent which will dispatch the specified
      * nested event.
      *
      * @param nested the AWTEvent which this SequencedEvent's dispatch()

@@ -133,11 +164,12 @@
             if (getFirst() != this) {
                 if (EventQueue.isDispatchThread()) {
                     if (Thread.currentThread() instanceof EventDispatchThread) {
                         EventDispatchThread edt = (EventDispatchThread)
                                 Thread.currentThread();
-                        edt.pumpEvents(ID, () -> !SequencedEvent.this.isFirstOrDisposed());
+                        edt.pumpEventsForFilter(() -> !SequencedEvent.this.isFirstOrDisposed(),
+                                new SequencedEventsFilter(this));
                     } else {
                         if (fxAppThreadIsDispatchThread) {
                             fxCheckSequenceThread.start();
                             try {
                                 // check if event is dispatched or disposed

@@ -237,14 +269,10 @@
                 KeyboardFocusManager.getCurrentKeyboardFocusManager().
                     setCurrentSequencedEvent(null);
             }
             disposed = true;
         }
-        // Wake myself up
-        if (appContext != null) {
-            SunToolkit.postEvent(appContext, new SentEvent());
-        }
 
         SequencedEvent next = null;
 
         synchronized (SequencedEvent.class) {
           SequencedEvent.class.notifyAll();

@@ -261,7 +289,11 @@
       }
         // Wake up waiting threads
         if (next != null && next.appContext != null) {
             SunToolkit.postEvent(next.appContext, new SentEvent());
         }
+
+        for(AWTEvent e : pendingEvents) {
+            SunToolkit.postEvent(appContext, e);
+        }
     }
 }
< prev index next >