Bug 879 - Threads deadlock in native keyboardfocus calls made form multiple threads
Summary: Threads deadlock in native keyboardfocus calls made form multiple threads
Status: RESOLVED FIXED
Alias: None
Product: Newt
Classification: JogAmp
Component: windows (show other bugs)
Version: 1
Hardware: pc_x86_64 windows
: P1 critical
Assignee: Sven Gothel
URL:
Depends on:
Blocks: 892
  Show dependency treegraph
 
Reported: 2013-10-30 23:09 CET by Harvey Harrison
Modified: 2013-11-18 20:52 CET (History)
1 user (show)

See Also:
Type: ---
SCM Refs:
0be87f241c0f0b2f5881d9a602ce12378b8e453d 23697c7921039e9655a5760e21d7029598b679d7 d544c839f6df10f20977c786a446833f3aa7ef13 177d0da1a9a8e031f15efa9e89465f8ed97f25e5
Workaround: ---


Attachments
patch for discussion purposes, likely breaks things (1.67 KB, text/plain)
2013-10-30 23:09 CET, Harvey Harrison
Details
Another workaround patch, tested on Java 6 and 7 on windows 7 (1.98 KB, patch)
2013-11-12 21:52 CET, Harvey Harrison
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Harvey Harrison 2013-10-30 23:09:19 CET
Created attachment 531 [details]
patch for discussion purposes, likely breaks things

Stack dumps once everthing locks up, the RenderThread stays in the _requestFocus
native method forever at this point.

"RenderThread-Display-.windows_nil-1-EDT-1" daemon prio=6 tid=0x000000000f622000 nid=0xe6c runnable [0x000000001417e000]
   java.lang.Thread.State: RUNNABLE
	at sun.awt.windows.WComponentPeer._requestFocus(Native Method)
	at sun.awt.windows.WComponentPeer.requestFocus(Unknown Source)
	at java.awt.Component.requestFocusHelper(Unknown Source)
	at java.awt.Component.requestFocusHelper(Unknown Source)
	at java.awt.Component.requestFocus(Unknown Source)
	at com.jogamp.newt.awt.NewtCanvasAWT.access$301(NewtCanvasAWT.java:83)
	at com.jogamp.newt.awt.NewtCanvasAWT$FocusAction.run(NewtCanvasAWT.java:179)
	at jogamp.newt.WindowImpl.focusAction(WindowImpl.java:1789)
	at jogamp.newt.WindowImpl.requestFocus(WindowImpl.java:1761)
	at jogamp.newt.WindowImpl.requestFocus(WindowImpl.java:1757)
	at jogamp.newt.driver.windows.DisplayDriver.DispatchMessages0(Native Method)
	at jogamp.newt.driver.windows.DisplayDriver.dispatchMessagesNative(DisplayDriver.java:85)
	at jogamp.newt.DisplayImpl.dispatchMessages(DisplayImpl.java:496)
	at jogamp.newt.DisplayImpl$5.run(DisplayImpl.java:419)
	at jogamp.newt.DefaultEDTUtil$EventDispatchThread.run(DefaultEDTUtil.java:308)

   Locked ownable synchronizers:
	- None


"AWT-EventQueue-0" prio=6 tid=0x0000000009aa1800 nid=0x27e0 runnable [0x000000000daec000]
   java.lang.Thread.State: RUNNABLE
	at sun.awt.KeyboardFocusManagerPeerImpl.getNativeFocusedWindow(Native Method)
	at sun.awt.KeyboardFocusManagerPeerImpl.getCurrentFocusedWindow(Unknown Source)
	at java.awt.KeyboardFocusManager.getNativeFocusedWindow(Unknown Source)
	at java.awt.KeyboardFocusManager.markClearGlobalFocusOwner(Unknown Source)
	- locked <0x000000075a9026a8> (a java.util.LinkedList)
	at java.awt.KeyboardFocusManager._clearGlobalFocusOwner(Unknown Source)
	at java.awt.KeyboardFocusManager.clearGlobalFocusOwner(Unknown Source)
	at jogamp.newt.awt.event.AWTParentWindowAdapter.focusGained(AWTParentWindowAdapter.java:75)
	at java.awt.Component.processFocusEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
	at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
	at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.awt.EventQueue.access$000(Unknown Source)
	at java.awt.EventQueue$1.run(Unknown Source)
	at java.awt.EventQueue$1.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
	at java.awt.EventQueue$2.run(Unknown Source)
	at java.awt.EventQueue$2.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.SequencedEvent.dispatch(Unknown Source)
	at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.awt.EventQueue.access$000(Unknown Source)
	at java.awt.EventQueue$1.run(Unknown Source)
	at java.awt.EventQueue$1.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
	at java.awt.EventQueue$2.run(Unknown Source)
	at java.awt.EventQueue$2.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)

   Locked ownable synchronizers:
	- None

"AWT-Windows" daemon prio=6 tid=0x0000000007b71000 nid=0x1418 waiting for monitor entry [0x0000000009ebe000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at java.awt.KeyboardFocusManager.shouldNativelyFocusHeavyweight(Unknown Source)
	- waiting to lock <0x000000075a9026a8> (a java.util.LinkedList)
	at sun.awt.windows.WToolkit.eventLoop(Native Method)
	at sun.awt.windows.WToolkit.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)

   Locked ownable synchronizers:
	- None
Comment 1 Sven Gothel 2013-10-30 23:32:10 CET
(11:21:11 PM) sgothel: hmm .. the whole focus traversal .. (so you have an overview) .. in NewtCanvasAWT is to extend AWT's traversal w/ our NEWT child
(11:21:41 PM) sgothel: I would love to see this fixed for sure

(11:22:33 PM) hharrison: If there was a knob we could set without patching to just 'ignore keyboardfocus' we could also use that

(11:24:06 PM) sgothel: we don't need to wait, i.e. the native calls explicitly state wait=false - b/c of this problem
(11:24:20 PM) sgothel: so it is designed to be all deferred ..
(11:25:08 PM) sgothel: the only problem is .. hmm is that the NEWT-EDT command waits for Component.requestFocus(Unknown Source)
(11:25:42 PM) sgothel: after that .. if gives the focus back to NEWT
(11:25:49 PM) sgothel: thats while it's waiting ..
(11:25:59 PM) hharrison: and injecting events onto two queues feels...maybe like an even worse problem
(11:26:08 PM) sgothel: so if the tail (give focus back to NEWT) would work on AWT-EDT .. maybe
(11:26:19 PM) sgothel: as long it's all non-waiting
(11:26:24 PM) sgothel: non-blocking
(11:27:13 PM) sgothel: NewtCanvasAWT could inject a runnable to AWT-EDT to perform the AWT requestFocus() + action to call NEWT-EDT to focus NEWT window (non-blocking)
(11:27:21 PM) sgothel: all non-blocking .. streaming
(11:27:36 PM) sgothel: maybe we can try this ..
(11:27:57 PM) sgothel: I look at it .. if it passes our unit tests .. good
(11:28:16 PM) sgothel: and solves these issues
Comment 2 Sven Gothel 2013-10-31 22:08:54 CET
Please provide a unit test - or a manual test case reproducing the dealock,
so we can analyze the issue better and confirm the future change.
Comment 3 Jesse 2013-11-06 15:21:10 CET
Just wanted to comment that I am getting this as well, same call stack. Easy way to reproduce this is to put canvas.requestFocusInWindow() inside mouseClicked event on a MouseListener and then click away/into the window over and over.
Comment 4 Sven Gothel 2013-11-11 21:40:42 CET
Same remedy (AWT-EDT task streaming) may apply to Bug 893.
Comment 5 Harvey Harrison 2013-11-12 21:52:37 CET
Created attachment 540 [details]
Another workaround patch, tested on Java 6 and 7 on windows 7

Again, mostly for discussion purposes.
Comment 6 Sven Gothel 2013-11-17 03:15:17 CET
Since we manage focus key traversal ourselves w/o requiring the AWT component to have the focus,
it seems that we simply can drop requesting the focus. 

TestParentingFocus03KeyTraversalAWT: Works on X11 and Windows

I have to double check this ..

@@ -190,16 +190,9 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
             if(DEBUG) {
                 System.err.println("NewtCanvasAWT.FocusAction: "+Display.getThreadName()+", isOnscreen "+isOnscreen+", hasFocus "+hasFocus()+", isParent "+isParent+", isFS "+isFullscreen);
             }
-            if(isParent && !isFullscreen) {
-                // Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus.
-                if(!hasFocus()) {
-                    // Acquire the AWT focus 1st for proper AWT traversal
-                    NewtCanvasAWT.super.requestFocus();
-                }
-                if(isOnscreen) {
-                    // Remove the AWT focus in favor of the native NEWT focus
-                    KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
-                }
+            if( isParent && !isFullscreen && isOnscreen ) {
+                // Remove the AWT focus in favor of the native NEWT focus
+                KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
             }
             return false; // NEWT shall proceed requesting the native focus
         }
Comment 7 Sven Gothel 2013-11-17 03:23:14 CET
(In reply to comment #6)
> Since we manage focus key traversal ourselves w/o requiring the AWT
> component to have the focus,

Commit cb7118fc875b6722803e4b11d5681671962a8d3a
introduced function to query the next or previous 'to be focused' component:
   AWTMisc.getNextFocus(..) .. etc.
Comment 8 Sven Gothel 2013-11-17 04:56:31 CET
0be87f241c0f0b2f5881d9a602ce12378b8e453d
    Since we manage focus key traversal ourselves w/o requiring the AWT
    component to have the focus[1],
    we simply can drop requesting the focus for 'focus hopping' NEWT -> AWT -> NEWT[2].
    
    Further more, 'MenuSelectionManager.defaultManager().clearSelectedPath()'
    must be performed on AWT-EDT w/o blocking. Otherwise it may perform blocking tasks on AWT-EDT.
    
    [1] Commit cb7118fc875b6722803e4b11d5681671962a8d3a
    introduced function to query the next or previous 'to be focused' component:
       AWTMisc.getNextFocus(..) .. etc.
    
    [2] Focus hopping is also addressed in Bug 892
Comment 9 Sven Gothel 2013-11-18 01:41:03 CET
23697c7921039e9655a5760e21d7029598b679d7
    NewtCanvasAWT.FocusAction must take focus when in offscreen-mode (OSX/CALayer)
    since the NEWT window _is_ offscreen (no input events) and AWT events are translated to NEWT.
    
    Regression of commit 0be87f241c0f0b2f5881d9a602ce12378b8e453d
Comment 10 Harvey Harrison 2013-11-18 18:47:55 CET
Running with commit d8f7418f170aba4703df2b11d5ae11598f71a796 I still see the following deadlock, I wonder, is there any harm in just firing a purpose built runnable into the AWT eventQueue to call the KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner()
bit?




"RenderThread-Display-.windows_nil-1-EDT-1" daemon prio=6 tid=0x0000000008f88000 nid=0x21c4 runnable [0x00000000115ae000]
   java.lang.Thread.State: RUNNABLE
	at sun.awt.KeyboardFocusManagerPeerImpl.getNativeFocusedWindow(Native Method)
	at sun.awt.KeyboardFocusManagerPeerImpl.getCurrentFocusedWindow(KeyboardFocusManagerPeerImpl.java:27)
	at java.awt.KeyboardFocusManager.getNativeFocusedWindow(KeyboardFocusManager.java:567)
	at java.awt.KeyboardFocusManager.markClearGlobalFocusOwner(KeyboardFocusManager.java:2496)
	- locked <0x00000007af1a4768> (a java.util.LinkedList)
	at java.awt.KeyboardFocusManager._clearGlobalFocusOwner(KeyboardFocusManager.java:550)
	at java.awt.KeyboardFocusManager.clearGlobalFocusOwner(KeyboardFocusManager.java:546)
	at com.jogamp.newt.awt.NewtCanvasAWT$FocusAction.run(NewtCanvasAWT.java:215)
	at jogamp.newt.WindowImpl.focusAction(WindowImpl.java:1920)
	at jogamp.newt.WindowImpl.requestFocus(WindowImpl.java:1892)
	at jogamp.newt.WindowImpl.requestFocus(WindowImpl.java:1888)
	at jogamp.newt.driver.windows.DisplayDriver.DispatchMessages0(Native Method)
	at jogamp.newt.driver.windows.DisplayDriver.dispatchMessagesNative(DisplayDriver.java:88)
	at jogamp.newt.DisplayImpl.dispatchMessages(DisplayImpl.java:540)
	at jogamp.newt.DisplayImpl$5.run(DisplayImpl.java:463)
	at jogamp.newt.DefaultEDTUtil$NEDT.run(DefaultEDTUtil.java:326)

   Locked ownable synchronizers:
	- None


"AWT-EventQueue-0" prio=6 tid=0x0000000006da3800 nid=0x27c4 runnable [0x000000000c8bc000]
   java.lang.Thread.State: RUNNABLE
	at sun.awt.windows.WComponentPeer._requestFocus(Native Method)
	at sun.awt.windows.WComponentPeer.requestFocus(WComponentPeer.java:623)
	at java.awt.Component.requestFocusHelper(Component.java:7447)
	at java.awt.Component.requestFocusInWindow(Component.java:7330)
	at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:361)
	at java.awt.Component.dispatchEventImpl(Component.java:4525)
	at java.awt.Container.dispatchEventImpl(Container.java:2097)
	at java.awt.Window.dispatchEventImpl(Window.java:2482)
	at java.awt.Component.dispatchEvent(Component.java:4481)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:648)
	at java.awt.EventQueue.access$000(EventQueue.java:84)
	at java.awt.EventQueue$1.run(EventQueue.java:607)
	at java.awt.EventQueue$1.run(EventQueue.java:605)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:98)
	at java.awt.EventQueue$2.run(EventQueue.java:621)
	at java.awt.EventQueue$2.run(EventQueue.java:619)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:618)
	at java.awt.SequencedEvent.dispatch(SequencedEvent.java:101)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:646)
	at java.awt.EventQueue.access$000(EventQueue.java:84)
	at java.awt.EventQueue$1.run(EventQueue.java:607)
	at java.awt.EventQueue$1.run(EventQueue.java:605)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:98)
	at java.awt.EventQueue$2.run(EventQueue.java:621)
	at java.awt.EventQueue$2.run(EventQueue.java:619)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:618)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

   Locked ownable synchronizers:
	- None

"AWT-Windows" daemon prio=6 tid=0x0000000006d85000 nid=0x17a4 waiting for monitor entry [0x000000000844e000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at java.awt.KeyboardFocusManager.shouldNativelyFocusHeavyweight(KeyboardFocusManager.java:2304)
	- waiting to lock <0x00000007af1a4768> (a java.util.LinkedList)
	at sun.awt.windows.WToolkit.eventLoop(Native Method)
	at sun.awt.windows.WToolkit.run(WToolkit.java:293)
	at java.lang.Thread.run(Thread.java:662)

   Locked ownable synchronizers:
	- None
Comment 11 Harvey Harrison 2013-11-18 19:14:14 CET
Patch I've been hammering on this morning that seems to be holding up:

diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
index 49bd0d7..56da037 100644
--- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
+++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
@@ -212,8 +212,9 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
             if( isParent && !isFullscreen ) { // must be parent of newtChild _and_ newtChild not fullscreen
                 if( isOnscreen ) {
                     // Remove the AWT focus in favor of the native NEWT focus
-                    KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
-                } else if( !isOnscreen ) {
+                    AWTEDTExecutor.singleton.invoke(false, new ClearFocusOwner());
+                }
+                else {
                     // In offscreen mode we require the focus!
                     if( !hasFocus() ) {
                         // Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus.
@@ -226,8 +227,16 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
     }
     private final FocusAction focusAction = new FocusAction();
 
+    private static class ClearFocusOwner implements Runnable {
+        @Override
+        public void run() {
+            KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
+        }
+    }
+
Comment 12 Harvey Harrison 2013-11-18 20:12:45 CET
Commits available at https://github.com/AusencoSimulation/jogl.git

commit d544c839f6df10f20977c786a446833f3aa7ef13
Author: Harvey Harrison <harvey.harrison@gmail.com>
Date:   Mon Nov 18 10:54:35 2013 -0800

    jogl: do the clearGlobalFocusOwner() call on the AWT EDT in NewtCanvasAWT
    
    Otherwise we can deadlock in the native focusrequest calls from the AWT thread,
    see bug 879 for the details.
    
    Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com>

commit 0a9d16f057727652220a5983b65f22f427df6a22
Author: Harvey Harrison <harvey.harrison@gmail.com>
Date:   Mon Nov 18 10:55:30 2013 -0800

    jogl: simplify conditional that repeats test for isOnScreen
    
    if (isOnscreen)
    else if (!isOnScreen)
    
    change to
    
    if (isOnscreen)
    else
    
    Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com>

commit 417675219de9fb5fceca5771812366ae8768b658
Author: Harvey Harrison <harvey.harrison@gmail.com>
Date:   Mon Nov 18 10:54:01 2013 -0800

    jogl: add missing @Override annotation in NewtCanvasAWT
    
    Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com>
Comment 13 Sven Gothel 2013-11-18 20:52:22 CET
added Harvey's git-sha1 values to SCM Refs. field.