diff --git a/jdk/src/share/classes/java/awt/EventQueue.java b/jdk/src/share/classes/java/awt/EventQueue.java
index 3e9febf79b7..b5635f4a25c 100644
--- a/jdk/src/share/classes/java/awt/EventQueue.java
+++ b/jdk/src/share/classes/java/awt/EventQueue.java
@@ -1027,7 +1027,9 @@ public class EventQueue {
synchronized (lock) {
Toolkit.getEventQueue().postEvent(event);
- lock.wait();
+ while (!event.isDispatched()) {
+ lock.wait();
+ }
}
Throwable eventThrowable = event.getThrowable();
diff --git a/jdk/src/share/classes/java/awt/event/InvocationEvent.java b/jdk/src/share/classes/java/awt/event/InvocationEvent.java
index 0959a86cb35..e21adf352bb 100644
--- a/jdk/src/share/classes/java/awt/event/InvocationEvent.java
+++ b/jdk/src/share/classes/java/awt/event/InvocationEvent.java
@@ -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 run()
method of the runnable
+ * 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 run
* method when dispatched. If notifier is non-null
,
* notifyAll()
will be called on it
- * immediately after run
returns.
+ * immediately after run
has returned or thrown an exception.
*
An invocation of the form InvocationEvent(source,
* runnable, notifier, catchThrowables)
* 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 notifyAll
* method will be called after
- * Runnable.run
has returned
+ * Runnable.run
has returned or
+ * thrown an exception
* @param catchThrowables Specifies whether dispatch
* should catch Throwable when executing
* the Runnable
's run
@@ -180,8 +192,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
* Constructs an InvocationEvent
with the specified
* source and ID which will execute the runnable's run
* method when dispatched. If notifier is non-null
,
- * notifyAll
will be called on it
- * immediately after run
returns.
+ * notifyAll
will be called on it immediately after
+ * run
has returned or thrown an exception.
*
This method throws an
* IllegalArgumentException
if source
* is null
.
@@ -195,7 +207,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
* run
method will be executed
* @param notifier The Object
whose notifyAll
* method will be called after
- * Runnable.run
has returned
+ * Runnable.run
has returned or
+ * thrown an exception
* @param catchThrowables Specifies whether dispatch
* should catch Throwable when executing the
* Runnable
's run
@@ -217,27 +230,33 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent {
/**
* Executes the Runnable's run()
method and notifies the
- * notifier (if any) when run()
returns.
+ * notifier (if any) when run()
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:
+ *
+ * while (!event.isDispatched()) { + * notifier.wait(); + * } + *+ * 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. + *
+ * 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. diff --git a/jdk/src/share/classes/sun/awt/im/InputMethodManager.java b/jdk/src/share/classes/sun/awt/im/InputMethodManager.java index caba8d6a152..9ee45e28e53 100644 --- a/jdk/src/share/classes/sun/awt/im/InputMethodManager.java +++ b/jdk/src/share/classes/sun/awt/im/InputMethodManager.java @@ -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(); diff --git a/jdk/test/java/awt/event/InvocationEvent/InvocationEventTest.java b/jdk/test/java/awt/event/InvocationEvent/InvocationEventTest.java new file mode 100644 index 00000000000..5fb83d10acf --- /dev/null +++ b/jdk/test/java/awt/event/InvocationEvent/InvocationEventTest.java @@ -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 "); + } + } +}