AppContext issue in Apple Java 6 -- same issue in Oracle Java 7?
Doug Zwick
Doug.Zwick at blackboard.com
Thu Jun 27 09:25:41 PDT 2013
On 2013-06-26, at 6:55 PM, Michael Hall wrote:
> On Jun 26, 2013, at 5:46 PM, Doug Zwick wrote:
>
>> I have dug deeper into this, and we are somehow getting our code running on AWT-EventQueue-0 in the "main" ThreadGroup, and not on AWT-EventQueue-2 in the "javawsApplicationThreadGroup" group
>
> This is normal for applications, if not jws, maybe jws is running more like platform app's now?
> From my HalfPipe app.
>
> dojava
> javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { System.out.println(Thread.currentThread() + " " + javax.swing.SwingUtilities.isEventDispatchThread()); }});
> Thread[AWT-EventQueue-0,6,main] true
> dojava: done
>
> Although I was sort of remembering the AppKit thread being the actual EDT? Must be a misremember there.
> You aren't showing a deadlock. I think actual instances of stack crawls showing deadlock would be more useful to go on if theres a problem.
> As I remember there have been multiple AWT-EventQueue-# threads going back a long time, these haven't been a deadlock problem previously that I remember.
> Thread group I'm not sure how would apply?
Stand-alone apps typically have only one Swing event thread, AWT-EventQueue-0. When running under Web Start, apps typically have had two (-0 and -1), up through Java 7u21. These seem to be bound to the two different AppContext instances present in JWS apps. I didn't look into which one was the "right" EDT for the web start app code in 7u21.
Starting in 7u25, there are now three EDTs, -0, -1 and -2 that correspond to three different AppContexts. The threads of the process seem to be grouped in the same manner, with a thread group for each AppContext. As a heuristic, we can look at the ThreadGroup of the calling thread, and from that deduce which AppContext it is running in. AWT-EventQueue-0 seems bound to the "main" ThreadGroup (at least in our app), -1 seems bound to the "javawsSecurityThreadGroup" ThreadGroup, and -2 seems bound to the "javawsApplicationThreadGroup" ThreadGroup. There is also a "system" ThreadGroup, but that one has now AWT-EventQueue-x thread in it. The "javawsApplicationThreadGroup" group is where all our application threads are grouped (which is also new behaviour in 7u25, in 7u21 we had some threads running in "main"). "AppKit Thread" is a member of the "main" ThreadGroup. It looks like all native code callbacks on the AppKit thread will send any Runnables queued with SwingUtilities.invokeLater to AWT-EventQueue-0, and not AWT-EventQueue-2. This causes problems. The most obvious one is deadlocks. We were often getting situations where both AWT-EventQueue-0 and AWT-EventQueue-2 were contesting the AWT Tree Lock. Since different code paths through Swing acquire locks in different orders relative to acquiring the Tree Lock, we readily wound up in a state where one EDT held the Tree Lock and was waiting for another lock, while the other EDT had that other lock and was waiting for the Tree Lock. The only way that can happen is if an event has been posted to the wrong EDT. If the different EDTs routinely contested the same AWT Tree Lock, JWS apps would always be deadlocking. The different AppContexts must provide independent Swing/AWT environments to ensure that this does not happen.
However, the problem with menu items is worse than I first thought. In addition to the About, Preferences and Quit menu items calling back through the EAWT interface on the wrong thread, it turns out that EVERY menu item in the screen menu bar responds to mouse activation by posting the ActionListener.actionPerformed event to the wrong EDT, namely the EDT associated with the "main" thread group, and not the EDT associated with our application code. It is interesting to note that activation via accelerator key causes the event to be posted to the correct EDT.
We are working around this by checking the ThreadGroup before queuing Runnables with SwingUtilities.invokeLater, and if the ThreadGroup of the calling thread is not the same ThreadGroup associated with our main application startup thread (which we cache at startup time), we instead queue the Runnable for a worker thread that is running in the correct ThreadGroup and AppContext, and have it then queue the Runnable onto the EDT. This works well for invokeLater, but is more of a pain for invokeAndWait calls. Our deadlocks seem to have disappeared.
We appear to have a related issue with Apple's 1.6.0_51 build, where we cannot open windows in callbacks from screen menu bar menu items (or they open but their content does not paint). This does not appear to be an issue under 7u25.
This email and any attachments may contain confidential and proprietary information of Blackboard that is for the sole use of the intended recipient. If you are not the intended recipient, disclosure, copying, re-distribution or other use of any of this information is strictly prohibited. Please immediately notify the sender and delete this transmission if you received this email in error.
More information about the macosx-port-dev
mailing list