6424157: java.awt.EventQueue push/pop might cause threading issues
Reviewed-by: ant, dcherepanov
--- a/jdk/src/share/classes/java/awt/EventDispatchThread.java Thu Jun 24 11:50:18 2010 +0400
+++ b/jdk/src/share/classes/java/awt/EventDispatchThread.java Tue Jul 06 17:59:56 2010 +0400
@@ -61,85 +61,43 @@
* @since 1.1
*/
class EventDispatchThread extends Thread {
+
private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread");
private EventQueue theQueue;
private boolean doDispatch = true;
+ private boolean threadDeathCaught = false;
+
private static final int ANY_EVENT = -1;
private Vector<EventFilter> eventFilters = new Vector<EventFilter>();
- // used in handleException
- private int modalFiltersCount = 0;
EventDispatchThread(ThreadGroup group, String name, EventQueue queue) {
super(group, name);
- theQueue = queue;
+ setEventQueue(queue);
}
- void stopDispatchingImpl(boolean wait) {
- // Note: We stop dispatching via a flag rather than using
- // Thread.interrupt() because we can't guarantee that the wait()
- // we interrupt will be EventQueue.getNextEvent()'s. -fredx 8-11-98
-
- StopDispatchEvent stopEvent = new StopDispatchEvent();
-
- // wait for the dispatcher to complete
- if (Thread.currentThread() != this) {
-
- // fix 4122683, 4128923
- // Post an empty event to ensure getNextEvent is unblocked
- //
- // We have to use postEventPrivate instead of postEvent because
- // EventQueue.pop calls EventDispatchThread.stopDispatching.
- // Calling SunToolkit.flushPendingEvents in this case could
- // lead to deadlock.
- theQueue.postEventPrivate(stopEvent);
-
- if (wait) {
- try {
- join();
- } catch(InterruptedException e) {
- }
- }
- } else {
- stopEvent.dispatch();
- }
-
- theQueue.detachDispatchThread(this, false);
- }
-
+ /*
+ * Must be called on EDT only, that's why no synchronization
+ */
public void stopDispatching() {
- stopDispatchingImpl(true);
- }
-
- public void stopDispatchingLater() {
- stopDispatchingImpl(false);
- }
-
- class StopDispatchEvent extends AWTEvent implements ActiveEvent {
- /*
- * serialVersionUID
- */
- static final long serialVersionUID = -3692158172100730735L;
-
- public StopDispatchEvent() {
- super(EventDispatchThread.this,0);
- }
-
- public void dispatch() {
- doDispatch = false;
- }
+ doDispatch = false;
}
public void run() {
- try {
- pumpEvents(new Conditional() {
- public boolean evaluate() {
- return true;
+ while (true) {
+ try {
+ pumpEvents(new Conditional() {
+ public boolean evaluate() {
+ return true;
+ }
+ });
+ } finally {
+ EventQueue eq = getEventQueue();
+ if (eq.detachDispatchThread(this) || threadDeathCaught) {
+ break;
}
- });
- } finally {
- theQueue.detachDispatchThread(this, true);
+ }
}
}
@@ -190,7 +148,6 @@
}
}
eventFilters.add(k, filter);
- modalFiltersCount++;
} else {
eventFilters.add(filter);
}
@@ -200,28 +157,25 @@
void removeEventFilter(EventFilter filter) {
synchronized (eventFilters) {
- if (eventFilters.contains(filter)) {
- if (filter instanceof ModalEventFilter) {
- modalFiltersCount--;
- }
- eventFilters.remove(filter);
- }
+ eventFilters.remove(filter);
}
}
boolean pumpOneEventForFilters(int id) {
+ AWTEvent event = null;
+ boolean eventOK = false;
try {
- AWTEvent event;
- boolean eventOK;
- EventQueueDelegate.Delegate delegate =
- EventQueueDelegate.getDelegate();
+ EventQueue eq = null;
+ EventQueueDelegate.Delegate delegate = null;
do {
+ // EventQueue may change during the dispatching
+ eq = getEventQueue();
+ delegate = EventQueueDelegate.getDelegate();
+
if (delegate != null && id == ANY_EVENT) {
- event = delegate.getNextEvent(theQueue);
+ event = delegate.getNextEvent(eq);
} else {
- event = (id == ANY_EVENT)
- ? theQueue.getNextEvent()
- : theQueue.getNextEvent(id);
+ event = (id == ANY_EVENT) ? eq.getNextEvent() : eq.getNextEvent(id);
}
eventOK = true;
@@ -252,13 +206,15 @@
if (delegate != null) {
handle = delegate.beforeDispatch(event);
}
- theQueue.dispatchEvent(event);
+ eq.dispatchEvent(event);
if (delegate != null) {
delegate.afterDispatch(event, handle);
}
+
return true;
}
catch (ThreadDeath death) {
+ threadDeathCaught = true;
return false;
}
@@ -267,12 +223,10 @@
// Threads in the AppContext
}
- // Can get and throw only unchecked exceptions
- catch (RuntimeException e) {
- processException(e);
- } catch (Error e) {
+ catch (Throwable e) {
processException(e);
}
+
return true;
}
@@ -281,14 +235,14 @@
eventLog.fine("Processing exception: " + e);
}
getUncaughtExceptionHandler().uncaughtException(this, e);
- // don't rethrow the exception to avoid EDT recreation
}
- boolean isDispatching(EventQueue eq) {
- return theQueue.equals(eq);
+ public synchronized EventQueue getEventQueue() {
+ return theQueue;
}
-
- EventQueue getEventQueue() { return theQueue; }
+ public synchronized void setEventQueue(EventQueue eq) {
+ theQueue = eq;
+ }
private static class HierarchyEventFilter implements EventFilter {
private Component modalComponent;
--- a/jdk/src/share/classes/java/awt/EventQueue.java Thu Jun 24 11:50:18 2010 +0400
+++ b/jdk/src/share/classes/java/awt/EventQueue.java Tue Jul 06 17:59:56 2010 +0400
@@ -138,6 +138,15 @@
private final Lock pushPopLock;
private final Condition pushPopCond;
+ /*
+ * Dummy runnable to wake up EDT from getNextEvent() after
+ push/pop is performed
+ */
+ private final static Runnable dummyRunnable = new Runnable() {
+ public void run() {
+ }
+ };
+
private EventDispatchThread dispatchThread;
private final ThreadGroup threadGroup =
@@ -219,22 +228,22 @@
* @param theEvent an instance of <code>java.awt.AWTEvent</code>,
* or a subclass of it
*/
- final void postEventPrivate(AWTEvent theEvent) {
+ private final void postEventPrivate(AWTEvent theEvent) {
theEvent.isPosted = true;
pushPopLock.lock();
try {
- if (dispatchThread == null && nextQueue == null) {
+ if (nextQueue != null) {
+ // Forward the event to the top of EventQueue stack
+ nextQueue.postEventPrivate(theEvent);
+ return;
+ }
+ if (dispatchThread == null) {
if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
return;
} else {
initDispatchThread();
}
}
- if (nextQueue != null) {
- // Forward event to top of EventQueue stack.
- nextQueue.postEventPrivate(theEvent);
- return;
- }
postEvent(theEvent, getPriority(theEvent));
} finally {
pushPopLock.unlock();
@@ -242,29 +251,20 @@
}
private static int getPriority(AWTEvent theEvent) {
- if (theEvent instanceof PeerEvent &&
- (((PeerEvent)theEvent).getFlags() &
- PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0)
- {
- return ULTIMATE_PRIORITY;
+ if (theEvent instanceof PeerEvent) {
+ PeerEvent peerEvent = (PeerEvent)theEvent;
+ if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {
+ return ULTIMATE_PRIORITY;
+ }
+ if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) {
+ return HIGH_PRIORITY;
+ }
+ if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) {
+ return LOW_PRIORITY;
+ }
}
-
- if (theEvent instanceof PeerEvent &&
- (((PeerEvent)theEvent).getFlags() &
- PeerEvent.PRIORITY_EVENT) != 0)
- {
- return HIGH_PRIORITY;
- }
-
- if (theEvent instanceof PeerEvent &&
- (((PeerEvent)theEvent).getFlags() &
- PeerEvent.LOW_PRIORITY_EVENT) != 0)
- {
- return LOW_PRIORITY;
- }
-
int id = theEvent.getID();
- if (id == PaintEvent.PAINT || id == PaintEvent.UPDATE) {
+ if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) {
return LOW_PRIORITY;
}
return NORM_PRIORITY;
@@ -501,16 +501,9 @@
SunToolkit.flushPendingEvents();
pushPopLock.lock();
try {
- for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
- if (queues[i].head != null) {
- EventQueueItem entry = queues[i].head;
- queues[i].head = entry.next;
- if (entry.next == null) {
- queues[i].tail = null;
- }
- uncacheEQItem(entry);
- return entry.event;
- }
+ AWTEvent event = getNextEventPrivate();
+ if (event != null) {
+ return event;
}
AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
pushPopCond.await();
@@ -520,6 +513,24 @@
} while(true);
}
+ /*
+ * Must be called under the lock. Doesn't call flushPendingEvents()
+ */
+ AWTEvent getNextEventPrivate() throws InterruptedException {
+ for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
+ if (queues[i].head != null) {
+ EventQueueItem entry = queues[i].head;
+ queues[i].head = entry.next;
+ if (entry.next == null) {
+ queues[i].tail = null;
+ }
+ uncacheEQItem(entry);
+ return entry.event;
+ }
+ }
+ return null;
+ }
+
AWTEvent getNextEvent(int id) throws InterruptedException {
do {
/*
@@ -659,7 +670,9 @@
dispatchThread.stopDispatching();
}
} else {
- System.err.println("unable to dispatch event: " + event);
+ if (eventLog.isLoggable(PlatformLogger.FINE)) {
+ eventLog.fine("Unable to dispatch event: " + event);
+ }
}
}
@@ -761,15 +774,23 @@
pushPopLock.lock();
try {
- EventQueue toPush = this;
- while (toPush.nextQueue != null) {
- toPush = toPush.nextQueue;
+ EventQueue topQueue = this;
+ while (topQueue.nextQueue != null) {
+ topQueue = topQueue.nextQueue;
+ }
+
+ if ((topQueue.dispatchThread != null) &&
+ (topQueue.dispatchThread.getEventQueue() == this))
+ {
+ newEventQueue.dispatchThread = topQueue.dispatchThread;
+ topQueue.dispatchThread.setEventQueue(newEventQueue);
}
// Transfer all events forward to new EventQueue.
- while (toPush.peekEvent() != null) {
+ while (topQueue.peekEvent() != null) {
try {
- newEventQueue.postEventPrivate(toPush.getNextEvent());
+ // Use getNextEventPrivate() as it doesn't call flushPendingEvents()
+ newEventQueue.postEventPrivate(topQueue.getNextEventPrivate());
} catch (InterruptedException ie) {
if (eventLog.isLoggable(PlatformLogger.FINE)) {
eventLog.fine("Interrupted push", ie);
@@ -777,28 +798,21 @@
}
}
- newEventQueue.previousQueue = toPush;
+ // Wake up EDT waiting in getNextEvent(), so it can
+ // pick up a new EventQueue. Post the waking event before
+ // topQueue.nextQueue is assigned, otherwise the event would
+ // go newEventQueue
+ topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
- /*
- * Stop the event dispatch thread associated with the currently
- * active event queue, so that after the new queue is pushed
- * on the top this event dispatch thread won't prevent AWT from
- * being automatically shut down.
- * Use stopDispatchingLater() to avoid deadlock: stopDispatching()
- * waits for the dispatch thread to exit, which in turn waits
- * for the lock in EQ.detachDispatchThread(), which is hold by
- * this method.
- */
- if (toPush.dispatchThread != null) {
- toPush.dispatchThread.stopDispatchingLater();
+ newEventQueue.previousQueue = topQueue;
+ topQueue.nextQueue = newEventQueue;
+
+ AppContext appContext = AppContext.getAppContext();
+ if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) {
+ appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
}
- toPush.nextQueue = newEventQueue;
-
- AppContext appContext = AppContext.getAppContext();
- if (appContext.get(AppContext.EVENT_QUEUE_KEY) == toPush) {
- appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
- }
+ pushPopCond.signalAll();
} finally {
pushPopLock.unlock();
}
@@ -822,44 +836,51 @@
eventLog.fine("EventQueue.pop(" + this + ")");
}
- EventDispatchThread dt = null;
pushPopLock.lock();
try {
- EventQueue toPop = this;
- while (toPop.nextQueue != null) {
- toPop = toPop.nextQueue;
+ EventQueue topQueue = this;
+ while (topQueue.nextQueue != null) {
+ topQueue = topQueue.nextQueue;
}
- EventQueue prev = toPop.previousQueue;
- if (prev == null) {
+ EventQueue prevQueue = topQueue.previousQueue;
+ if (prevQueue == null) {
throw new EmptyStackException();
}
- toPop.previousQueue = null;
+
+ topQueue.previousQueue = null;
+ prevQueue.nextQueue = null;
// Transfer all events back to previous EventQueue.
- prev.nextQueue = null;
- while (toPop.peekEvent() != null) {
+ while (topQueue.peekEvent() != null) {
try {
- prev.postEventPrivate(toPop.getNextEvent());
+ prevQueue.postEventPrivate(topQueue.getNextEventPrivate());
} catch (InterruptedException ie) {
if (eventLog.isLoggable(PlatformLogger.FINE)) {
eventLog.fine("Interrupted pop", ie);
}
}
}
- AppContext appContext = AppContext.getAppContext();
- if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
- appContext.put(AppContext.EVENT_QUEUE_KEY, prev);
+
+ if ((topQueue.dispatchThread != null) &&
+ (topQueue.dispatchThread.getEventQueue() == this))
+ {
+ prevQueue.dispatchThread = topQueue.dispatchThread;
+ topQueue.dispatchThread.setEventQueue(prevQueue);
}
- dt = toPop.dispatchThread;
+ AppContext appContext = AppContext.getAppContext();
+ if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
+ appContext.put(AppContext.EVENT_QUEUE_KEY, prevQueue);
+ }
+
+ // Wake up EDT waiting in getNextEvent(), so it can
+ // pick up a new EventQueue
+ topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
+
+ pushPopCond.signalAll();
} finally {
pushPopLock.unlock();
}
-
- if (dt != null) {
- dt.stopDispatching(); // Must be done outside synchronized
- // block to avoid possible deadlock
- }
}
/**
@@ -907,9 +928,9 @@
try {
AppContext appContext = AppContext.getAppContext();
if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {
- dispatchThread = (EventDispatchThread)
- AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
+ dispatchThread = AccessController.doPrivileged(
+ new PrivilegedAction<EventDispatchThread>() {
+ public EventDispatchThread run() {
EventDispatchThread t =
new EventDispatchThread(threadGroup,
name,
@@ -919,7 +940,8 @@
t.setDaemon(false);
return t;
}
- });
+ }
+ );
AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
dispatchThread.start();
}
@@ -928,7 +950,7 @@
}
}
- final void detachDispatchThread(EventDispatchThread edt, boolean restart) {
+ final boolean detachDispatchThread(EventDispatchThread edt) {
/*
* This synchronized block is to secure that the event dispatch
* thread won't die in the middle of posting a new event to the
@@ -939,26 +961,21 @@
*/
pushPopLock.lock();
try {
- EventDispatchThread oldDispatchThread = dispatchThread;
- if (dispatchThread == edt) {
- dispatchThread = null;
- }
- if (restart) {
+ if (edt == dispatchThread) {
/*
- * Event dispatch thread dies in case of an uncaught exception.
- * A new event dispatch thread for this queue will be started
- * only if a new event is posted to it. In case if no more
- * events are posted after this thread died all events that
- * currently are in the queue will never be dispatched.
+ * 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 ((peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) {
- initDispatchThread();
+ return false;
}
- AWTAutoShutdown.getInstance().notifyThreadFree(oldDispatchThread);
+ dispatchThread = null;
}
+ AWTAutoShutdown.getInstance().notifyThreadFree(edt);
+ return true;
} finally {
pushPopLock.unlock();
}
--- a/jdk/src/share/classes/sun/awt/SunToolkit.java Thu Jun 24 11:50:18 2010 +0400
+++ b/jdk/src/share/classes/sun/awt/SunToolkit.java Tue Jul 06 17:59:56 2010 +0400
@@ -39,6 +39,7 @@
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import sun.util.logging.PlatformLogger;
import sun.misc.SoftCache;
@@ -592,7 +593,7 @@
}
PostEventQueue postEventQueue =
(PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
- if(postEventQueue != null) {
+ if (postEventQueue != null) {
postEventQueue.postEvent(event);
}
}
@@ -610,16 +611,29 @@
postEvent(targetToAppContext(e.getSource()), pe);
}
+ private 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() {
- AppContext appContext = AppContext.getAppContext();
- PostEventQueue postEventQueue =
- (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
- if(postEventQueue != null) {
- postEventQueue.flush();
+ 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();
}
}
@@ -2079,12 +2093,14 @@
eventQueue = eq;
}
- public boolean noEvents() {
+ public synchronized boolean noEvents() {
return queueHead == null;
}
/*
- * Continually post pending AWTEvents to the Java EventQueue.
+ * 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.
*/
public synchronized void flush() {
EventQueueItem tempQueue = queueHead;
--- a/jdk/test/java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java Thu Jun 24 11:50:18 2010 +0400
+++ b/jdk/test/java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java Tue Jul 06 17:59:56 2010 +0400
@@ -1,3 +1,26 @@
+/*
+ * Copyright (c) 2010, 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.
+ *
+ * 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
@bug 6304473 6727884
--- a/jdk/test/java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.java Thu Jun 24 11:50:18 2010 +0400
+++ b/jdk/test/java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.java Tue Jul 06 17:59:56 2010 +0400
@@ -34,35 +34,40 @@
import java.awt.*;
import java.awt.event.*;
-import java.lang.Math;
+
+import sun.awt.SunToolkit;
+
import test.java.awt.regtesthelpers.Util;
public class LoopRobustness {
- static int clicks = 0;
+
final static long TIMEOUT = 5000;
final static Object LOCK = new Object();
- static volatile boolean notifyOccur = false;
- public static void main(String [] args) {
+ public static int clicks = 0;
+ public static volatile boolean notifyOccured = false;
+ public static volatile boolean otherExceptionsCaught = false;
+
+ public static void main(String [] args) throws Exception {
ThreadGroup mainThreadGroup = Thread.currentThread().getThreadGroup();
long at;
//wait for a TIMEOUT giving a chance to a new Thread above to accomplish its stuff.
- synchronized (LoopRobustness.LOCK){
+ synchronized (LoopRobustness.LOCK) {
new Thread(new TestThreadGroup(mainThreadGroup, "TestGroup"), new Impl()).start();
at = System.currentTimeMillis();
try {
- while(!notifyOccur && System.currentTimeMillis() - at < TIMEOUT) {
+ while (!notifyOccured && (System.currentTimeMillis() - at < TIMEOUT)) {
LoopRobustness.LOCK.wait(1000);
}
- } catch(InterruptedException e){
+ } catch (InterruptedException e) {
throw new RuntimeException("Test interrupted.", e);
}
}
- if( !notifyOccur){
+ if (!notifyOccured) {
//notify doesn't occur after a reasonable time.
- throw new RuntimeException("Test failed. Second Thread didn't notify MainThread.");
+ throw new RuntimeException("Test FAILED: second thread hasn't notified MainThread");
}
//now wait for two clicks
@@ -75,7 +80,10 @@
}
}
if (clicks != 2) {
- throw new RuntimeException("robot should press button twice");
+ throw new RuntimeException("Test FAILED: robot should press button twice");
+ }
+ if (otherExceptionsCaught) {
+ throw new RuntimeException("Test FAILED: unexpected exceptions caught");
}
}
}
@@ -83,18 +91,11 @@
class Impl implements Runnable{
static Robot robot;
public void run() {
+ SunToolkit.createNewAppContext();
+
Button b = new Button("Press me to test the AWT-Event Queue thread");
Frame lr = new Frame("ROBUST FRAME");
- /* Must load Toolkit on this thread only, rather then on Main.
- If load on Main (on the parent ThreadGroup of current ThreadGroup) then
- EDT will be created on Main thread and supplied with it's own exceptionHandler,
- which just throws an Exception and terminates current thread.
- The test implies that EDT is created on the child ThreadGroup (testThreadGroup)
- which is supplied with its own uncaughtException().
- */
- Toolkit.getDefaultToolkit();
lr.setBounds(100, 100, 300, 100);
-
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
LoopRobustness.clicks++;
@@ -107,40 +108,46 @@
try {
robot = new Robot();
- } catch(AWTException e){
+ } catch (AWTException e) {
throw new RuntimeException("Test interrupted.", e);
}
Util.waitForIdle(robot);
synchronized (LoopRobustness.LOCK){
LoopRobustness.LOCK.notify();
- LoopRobustness.notifyOccur = true;
+ LoopRobustness.notifyOccured = true;
}
int i = 0;
- while(i < 2){
+ while (i < 2) {
robot.mouseMove(b.getLocationOnScreen().x + b.getWidth()/2,
- b.getLocationOnScreen().y + b.getHeight()/2 );
+ b.getLocationOnScreen().y + b.getHeight()/2);
+ Util.waitForIdle(robot);
robot.mousePress(InputEvent.BUTTON1_MASK);
- // robot.delay(10);
+ Util.waitForIdle(robot);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
+ Util.waitForIdle(robot);
i++;
- robot.delay(1000);
}
}
}
class TestThreadGroup extends ThreadGroup {
- TestThreadGroup(ThreadGroup threadGroup, String name){
+ TestThreadGroup(ThreadGroup threadGroup, String name) {
super(threadGroup, name);
}
- public void uncaughtException(Thread exitedThread, Throwable e) {
- e.printStackTrace();
- if ((e instanceof ExceptionInInitializerError) || (e instanceof
- NoClassDefFoundError)){
- throw new RuntimeException("Test failed: other Exceptions were thrown ", e);
+ public void uncaughtException(Thread thread, Throwable e) {
+ System.out.println("Exception caught: " + e);
+ e.printStackTrace(System.out);
+ System.out.flush();
+ if ((e instanceof ExceptionInInitializerError) ||
+ (e instanceof NoClassDefFoundError))
+ {
+ // These two are expected
+ return;
}
+ LoopRobustness.otherExceptionsCaught = true;
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/EventDispatchThread/PreserveDispathThread/PreserveDispatchThread.java Tue Jul 06 17:59:56 2010 +0400
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2010, 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.
+ *
+ * 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
+ @bug 6424157
+ @author Artem Ananiev: area=eventqueue
+ @run main PreserveDispatchThread
+*/
+
+import java.awt.*;
+import java.awt.event.*;
+
+public class PreserveDispatchThread {
+
+ private static volatile Frame f;
+ private static volatile Dialog d;
+
+ private static volatile boolean isEDT = true;
+
+ public static void main(String[] args) throws Exception {
+ f = new Frame("F");
+ f.setSize(320, 340);
+ f.setLocationRelativeTo(null);
+ f.setVisible(true);
+
+ try {
+ test1();
+ if (!isEDT) {
+ throw new RuntimeException("Test FAILED (test1): event dispatch thread is changed");
+ }
+
+ test2();
+ if (!isEDT) {
+ throw new RuntimeException("Test FAILED (test2): event dispatch thread is changed");
+ }
+
+ test3();
+ if (!isEDT) {
+ throw new RuntimeException("Test FAILED (test3): event dispatch thread is changed");
+ }
+ } finally {
+ if (d != null) {
+ d.dispose();
+ }
+ f.dispose();
+ }
+ }
+
+ /*
+ * Tests that push/pop doesn't change the dispatch thread if
+ * called on EDT.
+ */
+ private static void test1() throws Exception {
+ EventQueue.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ TestEventQueue teq = new TestEventQueue();
+ EventQueue seq = Toolkit.getDefaultToolkit().getSystemEventQueue();
+ try {
+ seq.push(teq);
+ d = new TestDialog();
+ d.setVisible(true);
+ checkEDT();
+ } finally {
+ teq.pop();
+ }
+ checkEDT();
+ }
+ });
+ }
+
+ /*
+ * Tests that push/pop doesn't change the dispatch thread if
+ * called on the main thread.
+ */
+ private static void test2() throws Exception {
+ TestEventQueue teq = new TestEventQueue();
+ EventQueue seq = Toolkit.getDefaultToolkit().getSystemEventQueue();
+ try {
+ seq.push(teq);
+ EventQueue.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ checkEDT();
+ d = new TestDialog();
+ d.setVisible(true);
+ checkEDT();
+ }
+ });
+ } finally {
+ teq.pop();
+ }
+ }
+
+ private static final Object test3Lock = new Object();
+ private static boolean test3Sync = false;
+
+ /*
+ * A complex test: several nested invokeLater() are called and
+ * in every runnable a check for EDT is performed. At the ent
+ * of the test we wait for all the runnables to be processed
+ * and the dialog is disposed; otherwise the last EDT check can
+ * be later than this method returns and the whole test is passed.
+ */
+ private static void test3() throws Exception {
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ d = new Dialog(f, true);
+ d.setSize(240, 180);
+ d.setLocationRelativeTo(f);
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ d.setVisible(true);
+ checkEDT();
+ }
+ });
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ TestEventQueue teq = new TestEventQueue();
+ EventQueue seq = Toolkit.getDefaultToolkit().getSystemEventQueue();
+ try {
+ seq.push(teq);
+ checkEDT();
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ d.dispose();
+ checkEDT();
+ synchronized (test3Lock) {
+ test3Sync = true;
+ test3Lock.notify();
+ }
+ }
+ });
+ } finally {
+ teq.pop();
+ }
+ checkEDT();
+ }
+ });
+ checkEDT();
+ }
+ });
+ synchronized (test3Lock) {
+ while (!test3Sync) {
+ try {
+ test3Lock.wait();
+ } catch (InterruptedException ie) {
+ break;
+ }
+ }
+ }
+ // Make sure all the nested invokeLater/invokeAndWait are processed
+ EventQueue.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ }
+ });
+ }
+
+ private static void checkEDT() {
+ isEDT = isEDT && EventQueue.isDispatchThread();
+ }
+
+ private static class TestEventQueue extends EventQueue {
+ public TestEventQueue() {
+ super();
+ }
+ public void pop() {
+ super.pop();
+ }
+ }
+
+ private static class TestDialog extends Dialog {
+ private volatile boolean dialogShown = false;
+ private volatile boolean paintCalled = false;
+ public TestDialog() {
+ super(f, true);
+ setSize(240, 180);
+ setLocationRelativeTo(f);
+ addComponentListener(new ComponentAdapter() {
+ @Override
+ public void componentShown(ComponentEvent e) {
+ if (paintCalled) {
+ dispose();
+ }
+ dialogShown = true;
+ }
+ });
+ }
+ @Override
+ public void paint(Graphics g) {
+ if (dialogShown) {
+ dispose();
+ }
+ paintCalled = true;
+ }
+ }
+
+}
--- a/jdk/test/java/awt/EventQueue/PushPopDeadlock2/PushPopTest.java Thu Jun 24 11:50:18 2010 +0400
+++ b/jdk/test/java/awt/EventQueue/PushPopDeadlock2/PushPopTest.java Tue Jul 06 17:59:56 2010 +0400
@@ -43,6 +43,7 @@
Runnable dummy = new Runnable() {
public void run() {
System.err.println("Dummy is here.");
+ System.err.flush();
}
};
EventQueue seq = Toolkit.getDefaultToolkit().getSystemEventQueue();
@@ -58,10 +59,11 @@
Runnable runnable = new Runnable() {
public void run() {
System.err.println("Dummy from SunToolkit");
+ System.err.flush();
}
};
InvocationEvent ie = new InvocationEvent(eq2, runnable, null, false);
- System.err.println(ie);
+// System.err.println(ie);
SunToolkit.postEvent(SunToolkit.targetToAppContext(frame), ie);
eq1.pop();
frame.dispose();
@@ -70,14 +72,14 @@
class MyEventQueue1 extends EventQueue {
- public void pop() throws EmptyStackException {
+ public void pop() {
super.pop();
}
}
class MyEventQueue2 extends EventQueue {
- protected void pop() throws EmptyStackException {
+ protected void pop() {
System.err.println("pop2()");
Thread.dumpStack();
try {
@@ -85,7 +87,8 @@
public void run() {
Runnable runnable = new Runnable() {
public void run() {
- System.err.println("Dummy from here");
+ System.err.println("Dummy from pop");
+ System.err.flush();
}
};
InvocationEvent ie = new InvocationEvent(MyEventQueue2.this, runnable, null, false);