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,8 +1027,10 @@ public class EventQueue {
|
|||||||
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
Toolkit.getEventQueue().postEvent(event);
|
Toolkit.getEventQueue().postEvent(event);
|
||||||
|
while (!event.isDispatched()) {
|
||||||
lock.wait();
|
lock.wait();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Throwable eventThrowable = event.getThrowable();
|
Throwable eventThrowable = event.getThrowable();
|
||||||
if (eventThrowable != null) {
|
if (eventThrowable != null) {
|
||||||
|
@ -78,10 +78,21 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The (potentially null) Object whose notifyAll() method will be called
|
* 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;
|
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
|
* Set to true if dispatch() catches Throwable and stores it in the
|
||||||
* exception instance variable. If false, Throwables are propagated up
|
* 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>
|
* source which will execute the runnable's <code>run</code>
|
||||||
* method when dispatched. If notifier is non-<code>null</code>,
|
* method when dispatched. If notifier is non-<code>null</code>,
|
||||||
* <code>notifyAll()</code> will be called on it
|
* <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,
|
* <p>An invocation of the form <tt>InvocationEvent(source,
|
||||||
* runnable, notifier, catchThrowables)</tt>
|
* runnable, notifier, catchThrowables)</tt>
|
||||||
* behaves in exactly the same way as the invocation of
|
* behaves in exactly the same way as the invocation of
|
||||||
@ -159,7 +170,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
|
|||||||
* executed
|
* executed
|
||||||
* @param notifier The {@code Object} whose <code>notifyAll</code>
|
* @param notifier The {@code Object} whose <code>notifyAll</code>
|
||||||
* method will be called after
|
* 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>
|
* @param catchThrowables Specifies whether <code>dispatch</code>
|
||||||
* should catch Throwable when executing
|
* should catch Throwable when executing
|
||||||
* the <code>Runnable</code>'s <code>run</code>
|
* 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
|
* Constructs an <code>InvocationEvent</code> with the specified
|
||||||
* source and ID which will execute the runnable's <code>run</code>
|
* source and ID which will execute the runnable's <code>run</code>
|
||||||
* method when dispatched. If notifier is non-<code>null</code>,
|
* method when dispatched. If notifier is non-<code>null</code>,
|
||||||
* <code>notifyAll</code> will be called on it
|
* <code>notifyAll</code> will be called on it immediately after
|
||||||
* immediately after <code>run</code> returns.
|
* <code>run</code> has returned or thrown an exception.
|
||||||
* <p>This method throws an
|
* <p>This method throws an
|
||||||
* <code>IllegalArgumentException</code> if <code>source</code>
|
* <code>IllegalArgumentException</code> if <code>source</code>
|
||||||
* is <code>null</code>.
|
* is <code>null</code>.
|
||||||
@ -195,7 +207,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
|
|||||||
* <code>run</code> method will be executed
|
* <code>run</code> method will be executed
|
||||||
* @param notifier The <code>Object</code> whose <code>notifyAll</code>
|
* @param notifier The <code>Object</code> whose <code>notifyAll</code>
|
||||||
* method will be called after
|
* 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>
|
* @param catchThrowables Specifies whether <code>dispatch</code>
|
||||||
* should catch Throwable when executing the
|
* should catch Throwable when executing the
|
||||||
* <code>Runnable</code>'s <code>run</code>
|
* <code>Runnable</code>'s <code>run</code>
|
||||||
@ -217,9 +230,12 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the Runnable's <code>run()</code> method and notifies the
|
* 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() {
|
public void dispatch() {
|
||||||
|
try {
|
||||||
if (catchExceptions) {
|
if (catchExceptions) {
|
||||||
try {
|
try {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
@ -234,6 +250,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
|
|||||||
else {
|
else {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
dispatched = true;
|
||||||
|
|
||||||
if (notifier != null) {
|
if (notifier != null) {
|
||||||
synchronized (notifier) {
|
synchronized (notifier) {
|
||||||
@ -241,6 +259,7 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns any Exception caught while executing the Runnable's <code>run()
|
* Returns any Exception caught while executing the Runnable's <code>run()
|
||||||
@ -277,6 +296,40 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
|
|||||||
return when;
|
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.
|
* Returns a parameter string identifying this event.
|
||||||
* This method is useful for event-logging and for debugging.
|
* This method is useful for event-logging and for debugging.
|
||||||
|
@ -358,8 +358,10 @@ class ExecutableInputMethodManager extends InputMethodManager
|
|||||||
AppContext requesterAppContext = SunToolkit.targetToAppContext(requester);
|
AppContext requesterAppContext = SunToolkit.targetToAppContext(requester);
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
SunToolkit.postEvent(requesterAppContext, event);
|
SunToolkit.postEvent(requesterAppContext, event);
|
||||||
|
while (!event.isDispatched()) {
|
||||||
lock.wait();
|
lock.wait();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Throwable eventThrowable = event.getThrowable();
|
Throwable eventThrowable = event.getThrowable();
|
||||||
if (eventThrowable != null) {
|
if (eventThrowable != null) {
|
||||||
|
@ -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