From dafa242f76a6ac77b5a4dab3f3350719fb340a8e Mon Sep 17 00:00:00 2001 From: Petr Pchelko Date: Thu, 10 Oct 2013 11:40:06 +0400 Subject: [PATCH] 8025588: [macosx] Frozen AppKit thread in 7u40 Reviewed-by: anthony, art, serb --- .../sun/lwawt/macosx/CInputMethod.java | 15 +-- .../sun/lwawt/macosx/CPlatformWindow.java | 2 +- .../sun/lwawt/macosx/CViewEmbeddedFrame.java | 2 +- .../classes/sun/lwawt/macosx/LWCToolkit.java | 16 ++- .../share/classes/java/awt/EventQueue.java | 4 + .../java/awt/event/InvocationEvent.java | 101 +++++++++++++++--- .../share/classes/sun/awt/AWTAccessor.java | 23 ++++ 7 files changed, 127 insertions(+), 36 deletions(-) diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CInputMethod.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CInputMethod.java index ecb2d5217f6..3f6109a4120 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CInputMethod.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CInputMethod.java @@ -620,8 +620,7 @@ public class CInputMethod extends InputMethodAdapter { retString[0] = new String(selectedText); }} }, fAwtFocussedComponent); - } catch (InterruptedException ie) { ie.printStackTrace(); } - catch (InvocationTargetException ite) { ite.printStackTrace(); } + } catch (InvocationTargetException ite) { ite.printStackTrace(); } synchronized(retString) { return retString[0]; } } @@ -669,8 +668,7 @@ public class CInputMethod extends InputMethodAdapter { }} }, fAwtFocussedComponent); - } catch (InterruptedException ie) { ie.printStackTrace(); } - catch (InvocationTargetException ite) { ite.printStackTrace(); } + } catch (InvocationTargetException ite) { ite.printStackTrace(); } synchronized(returnValue) { return returnValue; } } @@ -695,8 +693,7 @@ public class CInputMethod extends InputMethodAdapter { returnValue[0] = fIMContext.getInsertPositionOffset(); }} }, fAwtFocussedComponent); - } catch (InterruptedException ie) { ie.printStackTrace(); } - catch (InvocationTargetException ite) { ite.printStackTrace(); } + } catch (InvocationTargetException ite) { ite.printStackTrace(); } returnValue[1] = fCurrentTextLength; synchronized(returnValue) { return returnValue; } @@ -743,8 +740,7 @@ public class CInputMethod extends InputMethodAdapter { } }} }, fAwtFocussedComponent); - } catch (InterruptedException ie) { ie.printStackTrace(); } - catch (InvocationTargetException ite) { ite.printStackTrace(); } + } catch (InvocationTargetException ite) { ite.printStackTrace(); } synchronized(rect) { return rect; } } @@ -764,8 +760,7 @@ public class CInputMethod extends InputMethodAdapter { insertPositionOffset[0] = fIMContext.getInsertPositionOffset(); }} }, fAwtFocussedComponent); - } catch (InterruptedException ie) { ie.printStackTrace(); } - catch (InvocationTargetException ite) { ite.printStackTrace(); } + } catch (InvocationTargetException ite) { ite.printStackTrace(); } // This bit of gymnastics ensures that the returned location is within the composed text. // If it falls outside that region, the input method will commit the text, which is inconsistent with native diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index 8fca7df691d..97ff63228e9 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -884,7 +884,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo //Posting an empty to flush the EventQueue without blocking the main thread } }, target); - } catch (InterruptedException | InvocationTargetException e) { + } catch (InvocationTargetException e) { e.printStackTrace(); } } diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CViewEmbeddedFrame.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CViewEmbeddedFrame.java index 28acc26f6cc..6d843b88295 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CViewEmbeddedFrame.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CViewEmbeddedFrame.java @@ -97,6 +97,6 @@ public class CViewEmbeddedFrame extends EmbeddedFrame { setVisible(true); } }, this); - } catch (InterruptedException | InvocationTargetException ex) {} + } catch (InvocationTargetException ex) {} } } diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java index d698845e558..959b03868fb 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java @@ -548,22 +548,18 @@ public final class LWCToolkit extends LWToolkit { // Any selector invoked using ThreadUtilities performOnMainThread will be processed in doAWTRunLoop // The InvocationEvent will call LWCToolkit.stopAWTRunLoop() when finished, which will stop our manual runloop // Does not dispatch native events while in the loop - public static void invokeAndWait(Runnable event, Component component) throws InterruptedException, InvocationTargetException { + public static void invokeAndWait(Runnable runnable, Component component) throws InvocationTargetException { final long mediator = createAWTRunLoopMediator(); InvocationEvent invocationEvent = - new InvocationEvent(component != null ? component : Toolkit.getDefaultToolkit(), event) { - @Override - public void dispatch() { - try { - super.dispatch(); - } finally { + new InvocationEvent(component != null ? component : Toolkit.getDefaultToolkit(), + runnable, + () -> { if (mediator != 0) { stopAWTRunLoop(mediator); } - } - } - }; + }, + true); if (component != null) { AppContext appContext = SunToolkit.targetToAppContext(component); diff --git a/jdk/src/share/classes/java/awt/EventQueue.java b/jdk/src/share/classes/java/awt/EventQueue.java index d6a1dabfc72..8c144ebc889 100644 --- a/jdk/src/share/classes/java/awt/EventQueue.java +++ b/jdk/src/share/classes/java/awt/EventQueue.java @@ -1159,6 +1159,10 @@ public class EventQueue { if (entry.event instanceof SentEvent) { ((SentEvent)entry.event).dispose(); } + if (entry.event instanceof InvocationEvent) { + AWTAccessor.getInvocationEventAccessor() + .dispose((InvocationEvent)entry.event); + } if (prev == null) { queues[i].head = entry.next; } else { diff --git a/jdk/src/share/classes/java/awt/event/InvocationEvent.java b/jdk/src/share/classes/java/awt/event/InvocationEvent.java index 1f411e1ac1a..3f04a2316e8 100644 --- a/jdk/src/share/classes/java/awt/event/InvocationEvent.java +++ b/jdk/src/share/classes/java/awt/event/InvocationEvent.java @@ -25,6 +25,8 @@ package java.awt.event; +import sun.awt.AWTAccessor; + import java.awt.ActiveEvent; import java.awt.AWTEvent; @@ -56,6 +58,15 @@ import java.awt.AWTEvent; */ public class InvocationEvent extends AWTEvent implements ActiveEvent { + static { + AWTAccessor.setInvocationEventAccessor(new AWTAccessor.InvocationEventAccessor() { + @Override + public void dispose(InvocationEvent invocationEvent) { + invocationEvent.finishedDispatching(false); + } + }); + } + /** * Marks the first integer id for the range of invocation event ids. */ @@ -78,11 +89,21 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { /** * The (potentially null) Object whose notifyAll() method will be called - * immediately after the Runnable.run() method has returned or thrown an exception. + * immediately after the Runnable.run() method has returned or thrown an exception + * or after the event was disposed. * * @see #isDispatched */ - protected Object notifier; + protected volatile Object notifier; + + /** + * The (potentially null) Runnable whose run() method will be called + * immediately after the event was dispatched or disposed. + * + * @see #isDispatched + * @since 1.8 + */ + private final Runnable listener; /** * Indicates whether the run() method of the runnable @@ -147,7 +168,7 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * @see #InvocationEvent(Object, Runnable, Object, boolean) */ public InvocationEvent(Object source, Runnable runnable) { - this(source, runnable, null, false); + this(source, INVOCATION_DEFAULT, runnable, null, null, false); } /** @@ -171,7 +192,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * @param notifier The {@code Object} whose notifyAll * method will be called after * Runnable.run has returned or - * thrown an exception + * thrown an exception or after the event was + * disposed * @param catchThrowables Specifies whether dispatch * should catch Throwable when executing * the Runnable's run @@ -185,7 +207,39 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { */ public InvocationEvent(Object source, Runnable runnable, Object notifier, boolean catchThrowables) { - this(source, INVOCATION_DEFAULT, runnable, notifier, catchThrowables); + this(source, INVOCATION_DEFAULT, runnable, notifier, null, catchThrowables); + } + + /** + * Constructs an InvocationEvent with the specified + * source which will execute the runnable's run + * method when dispatched. If listener is non-null, + * listener.run() will be called immediately after + * run has returned, thrown an exception or the event + * was disposed. + *

This method throws an IllegalArgumentException + * if source is null. + * + * @param source The Object that originated + * the event + * @param runnable The Runnable whose + * run method will be + * executed + * @param listener The RunnableRunnable whose + * run() method will be called + * after the {@code InvocationEvent} + * was dispatched or disposed + * @param catchThrowables Specifies whether dispatch + * should catch Throwable when executing + * the Runnable's run + * method, or should instead propagate those + * Throwables to the EventDispatchThread's + * dispatch loop + * @throws IllegalArgumentException if source is null + */ + public InvocationEvent(Object source, Runnable runnable, Runnable listener, + boolean catchThrowables) { + this(source, INVOCATION_DEFAULT, runnable, null, listener, catchThrowables); } /** @@ -208,7 +262,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * @param notifier The Object whose notifyAll * method will be called after * Runnable.run has returned or - * thrown an exception + * thrown an exception or after the event was + * disposed * @param catchThrowables Specifies whether dispatch * should catch Throwable when executing the * Runnable's run @@ -221,13 +276,18 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { */ protected InvocationEvent(Object source, int id, Runnable runnable, Object notifier, boolean catchThrowables) { + this(source, id, runnable, notifier, null, catchThrowables); + } + + private InvocationEvent(Object source, int id, Runnable runnable, + Object notifier, Runnable listener, boolean catchThrowables) { super(source, id); this.runnable = runnable; this.notifier = notifier; + this.listener = listener; this.catchExceptions = catchThrowables; this.when = System.currentTimeMillis(); } - /** * Executes the Runnable's run() method and notifies the * notifier (if any) when run() has returned or thrown an exception. @@ -251,13 +311,7 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { runnable.run(); } } finally { - dispatched = true; - - if (notifier != null) { - synchronized (notifier) { - notifier.notifyAll(); - } - } + finishedDispatching(true); } } @@ -330,6 +384,25 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { return dispatched; } + /** + * Called when the event was dispatched or disposed + * @param dispatched true if the event was dispatched + * false if the event was disposed + */ + private void finishedDispatching(boolean dispatched) { + this.dispatched = dispatched; + + if (notifier != null) { + synchronized (notifier) { + notifier.notifyAll(); + } + } + + if (listener != null) { + listener.run(); + } + } + /** * 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/AWTAccessor.java b/jdk/src/share/classes/sun/awt/AWTAccessor.java index 8cd84ab3d21..a00a23453fe 100644 --- a/jdk/src/share/classes/sun/awt/AWTAccessor.java +++ b/jdk/src/share/classes/sun/awt/AWTAccessor.java @@ -31,6 +31,7 @@ import java.awt.*; import java.awt.KeyboardFocusManager; import java.awt.DefaultKeyboardFocusManager; import java.awt.event.InputEvent; +import java.awt.event.InvocationEvent; import java.awt.event.KeyEvent; import java.awt.geom.Point2D; import java.awt.peer.ComponentPeer; @@ -720,6 +721,13 @@ public final class AWTAccessor { void setPlatformResources(ResourceBundle bundle); } + /* + * An accessor object for the InvocationEvent class + */ + public interface InvocationEventAccessor { + void dispose(InvocationEvent event); + } + /* * Accessor instances are initialized in the static initializers of * corresponding AWT classes by using setters defined below. @@ -748,6 +756,7 @@ public final class AWTAccessor { private static DefaultKeyboardFocusManagerAccessor defaultKeyboardFocusManagerAccessor; private static SequencedEventAccessor sequencedEventAccessor; private static ToolkitAccessor toolkitAccessor; + private static InvocationEventAccessor invocationEventAccessor; /* * Set an accessor object for the java.awt.Component class. @@ -1159,4 +1168,18 @@ public final class AWTAccessor { return toolkitAccessor; } + + /* + * Get the accessor object for the java.awt.event.InvocationEvent class. + */ + public static void setInvocationEventAccessor(InvocationEventAccessor invocationEventAccessor) { + AWTAccessor.invocationEventAccessor = invocationEventAccessor; + } + + /* + * Set the accessor object for the java.awt.event.InvocationEvent class. + */ + public static InvocationEventAccessor getInvocationEventAccessor() { + return invocationEventAccessor; + } }