6852111: Unhandled 'spurious wakeup' in java.awt.EventQueue.invokeAndWait()
Introduced InvocationEvent.isDispatched method Reviewed-by: art, anthony
This commit is contained in:
parent
85e10718ce
commit
1fbf705739
@ -1027,7 +1027,9 @@ public class EventQueue {
|
||||
|
||||
synchronized (lock) {
|
||||
Toolkit.getEventQueue().postEvent(event);
|
||||
lock.wait();
|
||||
while (!event.isDispatched()) {
|
||||
lock.wait();
|
||||
}
|
||||
}
|
||||
|
||||
Throwable eventThrowable = event.getThrowable();
|
||||
|
@ -78,10 +78,21 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
|
||||
|
||||
/**
|
||||
* The (potentially null) Object whose notifyAll() method will be called
|
||||
* immediately after the Runnable.run() method returns.
|
||||
* immediately after the Runnable.run() method has returned or thrown an exception.
|
||||
*
|
||||
* @see #isDispatched
|
||||
*/
|
||||
protected Object notifier;
|
||||
|
||||
/**
|
||||
* Indicates whether the <code>run()</code> method of the <code>runnable</code>
|
||||
* was executed or not.
|
||||
*
|
||||
* @see #isDispatched
|
||||
* @since 1.7
|
||||
*/
|
||||
private volatile boolean dispatched = false;
|
||||
|
||||
/**
|
||||
* Set to true if dispatch() catches Throwable and stores it in the
|
||||
* exception instance variable. If false, Throwables are propagated up
|
||||
@ -144,7 +155,7 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
|
||||
* source which will execute the runnable's <code>run</code>
|
||||
* method when dispatched. If notifier is non-<code>null</code>,
|
||||
* <code>notifyAll()</code> will be called on it
|
||||
* immediately after <code>run</code> returns.
|
||||
* immediately after <code>run</code> has returned or thrown an exception.
|
||||
* <p>An invocation of the form <tt>InvocationEvent(source,
|
||||
* runnable, notifier, catchThrowables)</tt>
|
||||
* behaves in exactly the same way as the invocation of
|
||||
@ -159,7 +170,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
|
||||
* executed
|
||||
* @param notifier The {@code Object} whose <code>notifyAll</code>
|
||||
* method will be called after
|
||||
* <code>Runnable.run</code> has returned
|
||||
* <code>Runnable.run</code> has returned or
|
||||
* thrown an exception
|
||||
* @param catchThrowables Specifies whether <code>dispatch</code>
|
||||
* should catch Throwable when executing
|
||||
* the <code>Runnable</code>'s <code>run</code>
|
||||
@ -180,8 +192,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
|
||||
* Constructs an <code>InvocationEvent</code> with the specified
|
||||
* source and ID which will execute the runnable's <code>run</code>
|
||||
* method when dispatched. If notifier is non-<code>null</code>,
|
||||
* <code>notifyAll</code> will be called on it
|
||||
* immediately after <code>run</code> returns.
|
||||
* <code>notifyAll</code> will be called on it immediately after
|
||||
* <code>run</code> has returned or thrown an exception.
|
||||
* <p>This method throws an
|
||||
* <code>IllegalArgumentException</code> if <code>source</code>
|
||||
* is <code>null</code>.
|
||||
@ -195,7 +207,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
|
||||
* <code>run</code> method will be executed
|
||||
* @param notifier The <code>Object</code> whose <code>notifyAll</code>
|
||||
* method will be called after
|
||||
* <code>Runnable.run</code> has returned
|
||||
* <code>Runnable.run</code> has returned or
|
||||
* thrown an exception
|
||||
* @param catchThrowables Specifies whether <code>dispatch</code>
|
||||
* should catch Throwable when executing the
|
||||
* <code>Runnable</code>'s <code>run</code>
|
||||
@ -217,27 +230,33 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
|
||||
|
||||
/**
|
||||
* Executes the Runnable's <code>run()</code> method and notifies the
|
||||
* notifier (if any) when <code>run()</code> returns.
|
||||
* notifier (if any) when <code>run()</code> has returned or thrown an exception.
|
||||
*
|
||||
* @see #isDispatched
|
||||
*/
|
||||
public void dispatch() {
|
||||
if (catchExceptions) {
|
||||
try {
|
||||
try {
|
||||
if (catchExceptions) {
|
||||
try {
|
||||
runnable.run();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
if (t instanceof Exception) {
|
||||
exception = (Exception) t;
|
||||
}
|
||||
throwable = t;
|
||||
}
|
||||
}
|
||||
else {
|
||||
runnable.run();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
if (t instanceof Exception) {
|
||||
exception = (Exception) t;
|
||||
}
|
||||
throwable = t;
|
||||
}
|
||||
}
|
||||
else {
|
||||
runnable.run();
|
||||
}
|
||||
} finally {
|
||||
dispatched = true;
|
||||
|
||||
if (notifier != null) {
|
||||
synchronized (notifier) {
|
||||
notifier.notifyAll();
|
||||
if (notifier != null) {
|
||||
synchronized (notifier) {
|
||||
notifier.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -277,6 +296,40 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
|
||||
return when;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the event is dispatched or any exception is
|
||||
* thrown while dispatching, {@code false} otherwise. The method should
|
||||
* be called by a waiting thread that calls the {@code notifier.wait()} method.
|
||||
* Since spurious wakeups are possible (as explained in {@link Object#wait()}),
|
||||
* this method should be used in a waiting loop to ensure that the event
|
||||
* got dispatched:
|
||||
* <pre>
|
||||
* while (!event.isDispatched()) {
|
||||
* notifier.wait();
|
||||
* }
|
||||
* </pre>
|
||||
* If the waiting thread wakes up without dispatching the event,
|
||||
* the {@code isDispatched()} method returns {@code false}, and
|
||||
* the {@code while} loop executes once more, thus, causing
|
||||
* the awakened thread to revert to the waiting mode.
|
||||
* <p>
|
||||
* If the {@code notifier.notifyAll()} happens before the waiting thread
|
||||
* enters the {@code notifier.wait()} method, the {@code while} loop ensures
|
||||
* that the waiting thread will not enter the {@code notifier.wait()} method.
|
||||
* Otherwise, there is no guarantee that the waiting thread will ever be woken
|
||||
* from the wait.
|
||||
*
|
||||
* @return {@code true} if the event has been dispatched, or any exception
|
||||
* has been thrown while dispatching, {@code false} otherwise
|
||||
* @see #dispatch
|
||||
* @see #notifier
|
||||
* @see #catchExceptions
|
||||
* @since 1.7
|
||||
*/
|
||||
public boolean isDispatched() {
|
||||
return dispatched;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a parameter string identifying this event.
|
||||
* This method is useful for event-logging and for debugging.
|
||||
|
@ -358,7 +358,9 @@ class ExecutableInputMethodManager extends InputMethodManager
|
||||
AppContext requesterAppContext = SunToolkit.targetToAppContext(requester);
|
||||
synchronized (lock) {
|
||||
SunToolkit.postEvent(requesterAppContext, event);
|
||||
lock.wait();
|
||||
while (!event.isDispatched()) {
|
||||
lock.wait();
|
||||
}
|
||||
}
|
||||
|
||||
Throwable eventThrowable = event.getThrowable();
|
||||
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
@test
|
||||
@bug 6852111
|
||||
@summary Unhandled 'spurious wakeup' in java.awt.EventQueue.invokeAndWait()
|
||||
@author dmitry.cherepanov@sun.com: area=awt.event
|
||||
@run main InvocationEventTest
|
||||
*/
|
||||
|
||||
/**
|
||||
* InvocationEventTest.java
|
||||
*
|
||||
* summary: Tests new isDispatched method of the InvocationEvent class
|
||||
*/
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
public class InvocationEventTest
|
||||
{
|
||||
public static void main(String []s) throws Exception
|
||||
{
|
||||
Toolkit tk = Toolkit.getDefaultToolkit();
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
}
|
||||
};
|
||||
Object lock = new Object();
|
||||
InvocationEvent event = new InvocationEvent(tk, runnable, lock, true);
|
||||
|
||||
if (event.isDispatched()) {
|
||||
throw new RuntimeException(" Initially, the event shouldn't be dispatched ");
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
tk.getSystemEventQueue().postEvent(event);
|
||||
while(!event.isDispatched()) {
|
||||
lock.wait();
|
||||
}
|
||||
}
|
||||
|
||||
if(!event.isDispatched()) {
|
||||
throw new RuntimeException(" Finally, the event should be dispatched ");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user