Deadlock in AppletWindowProvider

Beni hi;

I have same core app with two launchers; one starts as main() another as applet;

code is virtually identical;

when I use AppletWindowProvider for applet, EDT deadlocks here:


ComponentWindowProvider:

    @Override
    public void addWindowProviderListener( WindowProviderListener listener ) {
        int previous = listeners.size();
        super.addWindowProviderListener( listener );
        if( previous == 0 && listeners.size() > 0 && component != null ){
            component.addHierarchyListener( this.listener ); // HERE
            window = getWindowAncestor( component );
        }
    }

inside


Component:

    public void addHierarchyListener(HierarchyListener l) {
        if (l == null) {
            return;
        }
        boolean notifyAncestors;
        synchronized (this) {
            notifyAncestors =
                (hierarchyListener == null &&
                 (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) == 0);
            hierarchyListener = AWTEventMulticaster.add(hierarchyListener, l);
            notifyAncestors = (notifyAncestors && hierarchyListener != null);
            newEventsOnly = true;
        }
        if (notifyAncestors) {
            synchronized (getTreeLock()) {
                adjustListeningChildrenOnParent(AWTEvent.HIERARCHY_EVENT_MASK,
                                                1);
            }
        }
    }

my current workaround is to override this and make it empty:



public void addWindowProviderListener( WindowProviderListener listener ) {


and when I use DirectWindowProvider (with main() / JFrame as root instead of JApplet) all is fine!
no deadlocks anywhere;

since this is swing-internals related crap, instead of trying to find out where/why,
can you please just change your event detection logic from the HierarchyListener
to something else? (unless you can easily spot race condition in you code);

thank you;

Andrei

also making fields “protected” in the tree of AppletWindowProvider inheritance
could probably make applying changes / fixes easier;


    /** the child of the window to provide */
    private Component component;
    
    /** the current window of {@link #component} */
    private Window window;

I would really like to know how a Swing-app can create a deadlock, I’ve never seen that happen. Is it much code to reproduce this? And what version of JVM are you using?

I’m reluctant making protected fields. The probability that someone messes around and introduces memory leacks or destroyes the app otherwise is not so small. In the current case the “correct” workaround would be to create a custom WindowProvider (or, much better, find out how a deadlock can occure and repair it. That is really suspect - especially for a one-threaded Swing application).

got it; I will make project to reproduce this; beware: you’ll have to use maven :slight_smile:

Beni:

here is the project:

http://code.google.com/p/docking-frames/source/browse/#svn/demo/trunk/docking-frames-guts

to reproduce:

  1. run TraderApplication : runs fine;

  2. run TraderApplet : produces deadlock:



2010-10-11 10:42:57

"AWT-EventQueue-1" - Thread t@19
   java.lang.Thread.State: BLOCKED
	at java.awt.Component.addHierarchyListener(Component.java:5102)
	- waiting to lock <20e183e9> (a trader.TraderApplet) owned by "thread applet-trader.TraderApplet.class" t@13
	at bibliothek.gui.dock.util.ComponentWindowProvider.addWindowProviderListener(ComponentWindowProvider.java:70)
	at trader.AP_WindowProviderForApplet.addWindowProviderListener(AP_WindowProviderForApplet.java:40)
	at bibliothek.gui.dock.util.WindowProviderWrapper.setDelegate(WindowProviderWrapper.java:110)
	at bibliothek.gui.DockController.setRootWindowProvider(DockController.java:1104)
	at bibliothek.gui.DockFrontend.setOwner(DockFrontend.java:346)
	at bibliothek.gui.dock.common.CControl.<init>(CControl.java:365)
	at bibliothek.gui.dock.common.CControl.<init>(CControl.java:325)
	at bibliothek.gui.dock.common.CControl.<init>(CControl.java:302)
	at trader.AP_CControl.<init>(AP_CControl.java:19)
	at trader.AP_CControl$$FastClassByGuice$$3ac7b74a.newInstance(<generated>)
	at com.google.inject.internal.cglib.reflect.FastConstructor.newInstance(FastConstructor.java:40)
	at com.google.inject.DefaultConstructionProxyFactory$1.newInstance(DefaultConstructionProxyFactory.java:60)
	at com.google.inject.ConstructorInjector.construct(ConstructorInjector.java:85)
	at com.google.inject.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:111)
	at com.google.inject.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:45)
	at com.google.inject.InjectorImpl.callInContext(InjectorImpl.java:811)
	at com.google.inject.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:42)
	at com.google.inject.Scopes$1$1.get(Scopes.java:54)
	- locked <1d0bfedd> (a java.lang.Class)
	at com.google.inject.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:48)
	at com.google.inject.SingleParameterInjector.inject(SingleParameterInjector.java:42)
	at com.google.inject.SingleParameterInjector.getAll(SingleParameterInjector.java:66)
	at com.google.inject.ConstructorInjector.construct(ConstructorInjector.java:84)
	at com.google.inject.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:111)
	at com.google.inject.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:45)
	at com.google.inject.InjectorImpl.callInContext(InjectorImpl.java:811)
	at com.google.inject.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:42)
	at com.google.inject.Scopes$1$1.get(Scopes.java:54)
	- locked <1d0bfedd> (a java.lang.Class)
	at com.google.inject.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:48)
	at com.google.inject.InjectorImpl$4$1.call(InjectorImpl.java:758)
	at com.google.inject.InjectorImpl.callInContext(InjectorImpl.java:804)
	at com.google.inject.InjectorImpl$4.get(InjectorImpl.java:754)
	at com.google.inject.InjectorImpl.getInstance(InjectorImpl.java:793)
	at trader.GutsTest$2.run(GutsTest.java:80)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:199)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
	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


this might be a good chance for you to take a close look on guice;
may be it’s time to guice up the docking-frames? :slight_smile:

here is how Jean-Francois does it with guts and docking-frames:

http://kenai.com/projects/guts/sources/code/show/trunk/guts-sandbox/guts-gui-ex-docking-frames-common?rev=572

thank you;

you can setup m2e similar to this:

http://kenai.com/projects/guts/pages/SettingUpEclipse

http://kenai.com/projects/guts/pages/EclipseQuickStart

Ok, I’ll need some time to properly download and set up the project(s).

But from what I can see, I would really ask what this “thread applet-trader.TraderApplet.class” does, and why it keeps a lock. Currently I would label this as “not a DF specific issue”. Alright, don’t have the project right now, but what happens if you use “EventQueue.invokeLater” in your init method to set up the applet? If this “thread applet-trader.TraderApplet.class” keeps the lock the whole time, then fixing it might be tricky.

I would label this as „not a DF specific issue“.

yes; your are right;

there are 4 incompatible theading models in play:

  1. app in main()
  2. app in applet when run in ecllipse applet viewer;
  3. app in applet when run browser / legacy plugin;
  4. app in applet when run in browser / plugin2 (jnlp);

I have a solution that covers all so my „app“ feels ok
independent of launch container, but it is not nice so far;

thank you;