< prev index next >

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

Print this page
rev 13428 : 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

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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

@@ -23,10 +23,11 @@
  * questions.
  */
 
 package java.awt;
 
+import java.util.Iterator;
 import java.util.LinkedList;
 import sun.awt.AWTAccessor;
 import sun.awt.AppContext;
 import sun.awt.SunToolkit;
 

@@ -52,10 +53,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<>();
 
     static {
         AWTAccessor.setSequencedEventAccessor(new AWTAccessor.SequencedEventAccessor() {
             public AWTEvent getNested(AWTEvent sequencedEvent) {
                 return ((SequencedEvent)sequencedEvent).nested;

@@ -64,10 +66,39 @@
                 return event instanceof SequencedEvent;
             }
         });
     }
 
+    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()

@@ -102,15 +133,12 @@
 
             if (getFirst() != this) {
                 if (EventQueue.isDispatchThread()) {
                     EventDispatchThread edt = (EventDispatchThread)
                         Thread.currentThread();
-                    edt.pumpEvents(SentEvent.ID, new Conditional() {
-                        public boolean evaluate() {
-                            return !SequencedEvent.this.isFirstOrDisposed();
-                        }
-                    });
+                    edt.pumpEventsForFilter(() -> !SequencedEvent.this.isFirstOrDisposed(),
+                            new SequencedEventsFilter(this));
                 } else {
                     while(!isFirstOrDisposed()) {
                         synchronized (SequencedEvent.class) {
                             try {
                                 SequencedEvent.class.wait(1000);

@@ -195,14 +223,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();

@@ -219,7 +243,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 >