提交 67cc9038 编写于 作者: B bagiras

7186109: Simplify lock machinery for PostEventQueue & EventQueue

Reviewed-by: art, anthony, dholmes
上级 fe821b19
...@@ -536,7 +536,7 @@ public class LWCToolkit extends LWToolkit { ...@@ -536,7 +536,7 @@ public class LWCToolkit extends LWToolkit {
SunToolkit.postEvent(appContext, invocationEvent); SunToolkit.postEvent(appContext, invocationEvent);
// 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
sun.awt.SunToolkitSubclass.flushPendingEvents(appContext); SunToolkit.flushPendingEvents(appContext);
} else { } else {
// This should be the equivalent to EventQueue.invokeAndWait // This should be the equivalent to EventQueue.invokeAndWait
((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent); ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
...@@ -561,7 +561,7 @@ public class LWCToolkit extends LWToolkit { ...@@ -561,7 +561,7 @@ public class LWCToolkit extends LWToolkit {
SunToolkit.postEvent(appContext, invocationEvent); SunToolkit.postEvent(appContext, invocationEvent);
// 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
sun.awt.SunToolkitSubclass.flushPendingEvents(appContext); SunToolkit.flushPendingEvents(appContext);
} else { } else {
// This should be the equivalent to EventQueue.invokeAndWait // This should be the equivalent to EventQueue.invokeAndWait
((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent); ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
......
...@@ -1046,6 +1046,10 @@ public class EventQueue { ...@@ -1046,6 +1046,10 @@ public class EventQueue {
} }
final boolean detachDispatchThread(EventDispatchThread edt, boolean forceDetach) { 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 * This synchronized block is to secure that the event dispatch
* thread won't die in the middle of posting a new event to the * thread won't die in the middle of posting a new event to the
...@@ -1060,11 +1064,8 @@ public class EventQueue { ...@@ -1060,11 +1064,8 @@ public class EventQueue {
/* /*
* Don't detach the thread if any events are pending. Not * Don't detach the thread if any events are pending. Not
* sure if it's a possible scenario, though. * sure if it's a possible scenario, though.
*
* 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; return false;
} }
dispatchThread = null; dispatchThread = null;
......
...@@ -506,40 +506,25 @@ public abstract class SunToolkit extends Toolkit ...@@ -506,40 +506,25 @@ public abstract class SunToolkit extends Toolkit
postEvent(targetToAppContext(e.getSource()), pe); 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 * Flush any pending events which haven't been posted to the AWT
* EventQueue yet. * EventQueue yet.
*/ */
public static void flushPendingEvents() { public static void flushPendingEvents() {
flushLock.lock(); AppContext appContext = AppContext.getAppContext();
try { flushPendingEvents(appContext);
// 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();
}
} }
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 postEventQueue =
(PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY); (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
if (postEventQueue != null) { if (postEventQueue != null) {
return postEventQueue.noEvents(); postEventQueue.flush();
} else {
return true;
} }
} }
...@@ -2045,17 +2030,12 @@ class PostEventQueue { ...@@ -2045,17 +2030,12 @@ class PostEventQueue {
private EventQueueItem queueTail = null; private EventQueueItem queueTail = null;
private final EventQueue eventQueue; private final EventQueue eventQueue;
// For the case when queue is cleared but events are not posted private Thread flushThread = null;
private volatile boolean isFlushing = false;
PostEventQueue(EventQueue eq) { PostEventQueue(EventQueue eq) {
eventQueue = eq; eventQueue = eq;
} }
public synchronized boolean noEvents() {
return queueHead == null && !isFlushing;
}
/* /*
* Continually post pending AWTEvents to the Java EventQueue. The method * Continually post pending AWTEvents to the Java EventQueue. The method
* is synchronized to ensure the flush is completed before a new event * is synchronized to ensure the flush is completed before a new event
...@@ -2066,20 +2046,48 @@ class PostEventQueue { ...@@ -2066,20 +2046,48 @@ class PostEventQueue {
* potentially lead to deadlock * potentially lead to deadlock
*/ */
public void flush() { public void flush() {
EventQueueItem tempQueue;
synchronized (this) { Thread newThread = Thread.currentThread();
tempQueue = queueHead;
queueHead = queueTail = null;
isFlushing = true;
}
try { try {
while (tempQueue != null) { EventQueueItem tempQueue;
eventQueue.postEvent(tempQueue.event); synchronized (this) {
tempQueue = tempQueue.next; // 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 { catch (InterruptedException e) {
isFlushing = false; // Couldn't allow exception go up, so at least recover the flag
newThread.interrupt();
} }
} }
......
/*
* Copyright (c) 2012, 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.
*/
/**
* @test PostEventOrderingTest.java
* @bug 4171596 6699589
* @summary Checks that the posting of events between the PostEventQueue
* @summary and the EventQueue maintains proper ordering.
* @run main PostEventOrderingTest
* @author fredx
*/
import java.awt.*;
import java.awt.event.*;
import sun.awt.AppContext;
import sun.awt.SunToolkit;
public class PostEventOrderingTest {
static boolean testPassed = true;
public static void main(String[] args) throws Throwable {
EventQueue q = Toolkit.getDefaultToolkit().getSystemEventQueue();
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) {
q.postEvent(new PostActionEvent());
for (int k = 0; k < 10; k++) {
SunToolkit.postEvent(AppContext.getAppContext(), new PostActionEvent());
}
}
for (int k = 0; k < 100; k++) {
SunToolkit.postEvent(AppContext.getAppContext(), new PostActionEvent());
}
}
for (;;) {
Thread.currentThread().sleep(100);
if (q.peekEvent() == null) {
Thread.currentThread().sleep(100);
if (q.peekEvent() == null)
break;
}
}
if (!testPassed) {
throw new Exception("PostEventOrderingTest FAILED -- events dispatched out of order.");
} else {
System.out.println("PostEventOrderingTest passed!");
}
}
}
class PostActionEvent extends ActionEvent implements ActiveEvent {
static int counter = 0;
static int mostRecent = -1;
int myval;
public PostActionEvent() {
super("", ACTION_PERFORMED, "" + counter);
myval = counter++;
}
public void dispatch() {
//System.out.println("myval = "+myval+", mostRecent = "+mostRecent+", diff = "+(myval-mostRecent)+".");
if ((myval - mostRecent) != 1)
PostEventOrderingTest.testPassed = false;
mostRecent = myval;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册