7186109: Simplify lock machinery for PostEventQueue & EventQueue
Reviewed-by: art, anthony, dholmes
This commit is contained in:
parent
589854449e
commit
08a51f1378
@ -536,7 +536,7 @@ public class LWCToolkit extends LWToolkit {
|
||||
SunToolkit.postEvent(appContext, invocationEvent);
|
||||
|
||||
// 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
|
||||
sun.awt.SunToolkitSubclass.flushPendingEvents(appContext);
|
||||
SunToolkit.flushPendingEvents(appContext);
|
||||
} else {
|
||||
// This should be the equivalent to EventQueue.invokeAndWait
|
||||
((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
|
||||
@ -561,7 +561,7 @@ public class LWCToolkit extends LWToolkit {
|
||||
SunToolkit.postEvent(appContext, invocationEvent);
|
||||
|
||||
// 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
|
||||
sun.awt.SunToolkitSubclass.flushPendingEvents(appContext);
|
||||
SunToolkit.flushPendingEvents(appContext);
|
||||
} else {
|
||||
// This should be the equivalent to EventQueue.invokeAndWait
|
||||
((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
|
||||
|
@ -1046,6 +1046,10 @@ public class EventQueue {
|
||||
}
|
||||
|
||||
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
|
||||
* thread won't die in the middle of posting a new event to the
|
||||
@ -1060,11 +1064,8 @@ public class EventQueue {
|
||||
/*
|
||||
* Don't detach the thread if any events are pending. Not
|
||||
* 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;
|
||||
}
|
||||
dispatchThread = null;
|
||||
|
@ -506,40 +506,25 @@ public abstract class SunToolkit extends Toolkit
|
||||
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 @@ class PostEventQueue {
|
||||
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 @@ class PostEventQueue {
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user