OpenJDK / zgc / zgc
changeset 5942:287c421fb9b2
6424157: java.awt.EventQueue push/pop might cause threading issues
Reviewed-by: ant, dcherepanov
author | art |
---|---|
date | Tue, 06 Jul 2010 17:59:56 +0400 |
parents | 1a56de1b70b3 |
children | 240bcabaca0f |
files | jdk/src/share/classes/java/awt/EventDispatchThread.java jdk/src/share/classes/java/awt/EventQueue.java jdk/src/share/classes/sun/awt/SunToolkit.java jdk/test/java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java jdk/test/java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.java jdk/test/java/awt/EventDispatchThread/PreserveDispathThread/PreserveDispatchThread.java jdk/test/java/awt/EventQueue/PushPopDeadlock2/PushPopTest.java |
diffstat | 7 files changed, 473 insertions(+), 229 deletions(-) [+] |
line wrap: on
line diff
--- 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);