Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 352992 - [IDE] Invalid Thread Access when using Nebula components
Summary: [IDE] Invalid Thread Access when using Nebula components
Status: CLOSED WONTFIX
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.7   Edit
Hardware: All All
: P3 minor (vote)
Target Milestone: ---   Edit
Assignee: Platform UI Triaged CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords:
Depends on:
Blocks:
 
Reported: 2011-07-25 07:10 EDT by Wim Jongman CLA
Modified: 2019-11-14 03:07 EST (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Wim Jongman CLA 2011-07-25 07:10:35 EDT
In our Eclipse RCP product we use the OSGi directive autostart=true. This revealed an interesting problem. 

If we have the o.e.ui.presentations.r21 plugin in our list of plugins, the autostart directive causes this plugin to start in a Daemon thread before workbench creation. The R21PresentationPlugin will call Display.getDefault() in its R21Colors class [1]-line-178. All other Eclipse agnostic SWT calls will also use Display.getDefault() (e.g. the Nebula widgets) instead of the preferred Workbench.getDisplay() method. The display that is returned, is the one that is created by the R21 initial call to Display.

When the workbench starts AFTER the first call of Display.getDefault() then Display.getDefault() will return a different Display than the one created in the Workbench.createDisplay() method.

Obviously, the various createPartControl methods will be called with the Workbench Display but the Nebula, or other DOIY widgets will be using the Display.getDefault() causing InvalidThreadAccess to be thrown.

[1] http://dev.eclipse.org/viewcvs/viewvc.cgi/org.eclipse.ui.internal.r21presentation/src/org/eclipse/ui/internal/r21presentation/R21Colors.java?revision=1.1&view=markup&sortby=rev
Comment 1 Thomas Schindl CLA 2011-07-25 08:06:58 EDT
Remy what would you expect nebula to call instead of Display.getDefault()? Should we call Display.getCurrent() it's still very strange that something we are having 2 displays. IIRC the assumption that Display.getDefault() is correct in Nebula because we only expect people to create/use our code from the UI-Thread
Comment 2 Remy Suen CLA 2011-07-25 08:19:36 EDT
(In reply to comment #1)
> Remy what would you expect nebula to call instead of Display.getDefault()?

I guess the safest option is what SWT does which is to have constructors that take a widget or display. Because then you would just reuse that one instead of having to "reach out" using static methods.

Of course, the above involves introducing new APIs so that's not exactly a viable solution per se.

> Should we call Display.getCurrent() it's still very strange that something we
> are having 2 displays. IIRC the assumption that Display.getDefault() is correct
> in Nebula because we only expect people to create/use our code from the
> UI-Thread

I agree with your statements here.

Perhaps it might be possible to delay the initialization of these workbench colours but I haven't looked at the code yet.
Comment 3 Thomas Schindl CLA 2011-07-25 08:21:26 EDT
oh i just saw that you move this from swt to ui - I was under the impression that you moved it to nebula ;-)
Comment 4 Wim Jongman CLA 2011-07-25 08:34:54 EDT
#3 - This is not a Nebula problem. This is the preferred way of getting the correct display in SWT.

#2 Remy, this is not only R21 plugin but also debug.ui plugin and there could be many more. I think the workbench code should accept the already created display.
Comment 5 Wim Jongman CLA 2011-07-25 08:38:55 EDT
just a thought: If I call Display.getDefault() in some thread and I am the first one to call it then this Thread will become the UI thread. What happens if the Thread ends because it was just some worker? The default variable in Display is still initialized.
Comment 6 Thomas Schindl CLA 2011-07-25 08:42:25 EDT
(In reply to comment #5)
> just a thought: If I call Display.getDefault() in some thread and I am the
> first one to call it then this Thread will become the UI thread. What happens
> if the Thread ends because it was just some worker? The default variable in
> Display is still initialized.

I think that this is the problem because with your autostart its some arbitary OSGi-Thread probably something those things are initialized in a static block
Comment 7 Paul Webster CLA 2011-07-25 08:46:31 EDT
(In reply to comment #4)
> #3 - This is not a Nebula problem. This is the preferred way of getting the
> correct display in SWT.
> #2 Remy, this is not only R21 plugin but also debug.ui plugin and there could
> be many more. I think the workbench code should accept the already created
> display.

In the workbench, IWorkbench.getDisplay() is the only guaranteed method of having the workbench work correctly.  It's been that way since before 3.0.

No application is allowed to make display calls before the workbench creation has started ... unless they call PlatformUI.createDisplay().  You can do that at the beginning of your RCP application if you wish.


That also means you should not do something that causes plugins (like the r21 presentation) to start before the workbench is up, or at least the workbench display has been created.

There might be something we could do kill the r21 plugin startup if the workbench creation is not in progress.

PW
Comment 8 Remy Suen CLA 2011-07-25 08:47:52 EDT
(In reply to comment #4)
> #2 Remy, this is not only R21 plugin but also debug.ui plugin and there could
> be many more.

Debug changed that code, see bug 250048.

> I think the workbench code should accept the already created
> display.

This feels rather risky to me.
Comment 9 Wim Jongman CLA 2011-07-25 09:27:45 EDT
Is it save to say that display.getDefault() is broken when you use it in Eclipse? 

> This feels rather risky to me.

Okay but if not all parties play along with this "unknown rule" then there should be some guarding code in Workbench.createDisplay()

It could signal that there is already a Display thread initialized and throw a warning. 

** WARNING - DISPLAY CREATED BEFORE WORKBENCH INIT COMPLETED


Tools like Nebula should avoid calling Display.getDefault() but rather use their parent widget to get the Display. This is really an important pattern for SWT widget developers that want to use their widgets inside the Workbench.
Comment 10 Wim Jongman CLA 2011-07-25 10:01:11 EDT
(In reply to comment #9)

Here is a stacktrace (from bug 250048) demonstrating that calling PreferenceConverter calls Display.getDefault(). The PreferenceConverter is called from the debug.ui plugin. 

Daemon Thread [Start Level Event Dispatcher] (Suspended (entry into method
getDefault in Display))    
    Display.getDefault() line: 1632    
    PreferenceConverter.<clinit>() line: 81    
    DebugUIPreferenceInitializer.setDefault(IPreferenceStore, String, RGB,
boolean) line: 186    
    DebugUIPreferenceInitializer.setThemeBasedPreferences(IPreferenceStore,
boolean) line: 204    
    DebugUIPreferenceInitializer.initializeDefaultPreferences() line: 79    
    PreferenceServiceRegistryHelper$1.run() line: 281    
    SafeRunner.run(ISafeRunnable) line: 42    
    PreferenceServiceRegistryHelper.runInitializer(IConfigurationElement) line:
284    
    PreferenceServiceRegistryHelper.applyRuntimeDefaults(String, WeakReference)
line: 130    
    PreferencesService.applyRuntimeDefaults(String, WeakReference) line: 369    
    DefaultPreferences.applyRuntimeDefaults() line: 166    
    DefaultPreferences.load() line: 237    
    DefaultPreferences(EclipsePreferences).create(EclipsePreferences, String,
Object) line: 307    
    DefaultPreferences(EclipsePreferences).internalNode(String, boolean,
Object) line: 543    
    DefaultPreferences(EclipsePreferences).node(String) line: 669    
    DefaultScope(AbstractScope).getNode(String) line: 38    
    DefaultScope.getNode(String) line: 67    
    ScopedPreferenceStore.getDefaultPreferences() line: 250    
    ScopedPreferenceStore.getPreferenceNodes(boolean) line: 285    
    ScopedPreferenceStore.internalGet(String) line: 475    
    ScopedPreferenceStore.getString(String) line: 535    
    PerspectiveManager.initPerspectives() line: 990    
    PerspectiveManager.startup() line: 253    
    DebugUIPlugin.start(BundleContext) line: 501    
    BundleContextImpl$1.run() line: 783    
    AccessController.doPrivileged(PrivilegedExceptionAction<T>) line: not
available [native method]    
    BundleContextImpl.startActivator(BundleActivator) line: 774    
    BundleContextImpl.start() line: 755    
    BundleHost.startWorker(int) line: 370    
    BundleHost(AbstractBundle).resume() line: 374    
    Framework.resumeBundle(AbstractBundle) line: 1067    
    StartLevelManager.resumeBundles(AbstractBundle[], boolean, int) line: 561   
    StartLevelManager.resumeBundles(AbstractBundle[], int) line: 546    
    StartLevelManager.incFWSL(int, AbstractBundle[]) line: 459    
    StartLevelManager.doSetStartLevel(int) line: 243    
    StartLevelManager.dispatchEvent(Object, Object, int, Object) line: 440    
    EventManager.dispatchEvent(Set, EventDispatcher, int, Object) line: 227    
    EventManager$EventThread.run() line: 337
Comment 11 Paul Webster CLA 2011-07-25 10:11:50 EDT
(In reply to comment #10)
> (In reply to comment #9)
> 
> Here is a stacktrace (from bug 250048) demonstrating that calling
> PreferenceConverter calls Display.getDefault(). The PreferenceConverter is
> called from the debug.ui plugin. 
>     

Sorry, what is causing this bundle to be started before the workbench?  If it is not the workbench, we need to fix it or understand it.  Most eclipse plugins are not OSGi bundles, they cannot be started by the OSGi framework at an arbitrary time
Comment 12 Wim Jongman CLA 2011-07-25 11:29:45 EDT
(In reply to comment #11)
> 
> Sorry, what is causing this bundle to be started before the workbench?

Yes, there is a case of old meets new here. We rely on OSGi services in our product. They should be started. Because there are so many of them we experimented with autostarting all bundles. This was when this "bug" revealed itself.

Now we need to go back to maintaining a list with autostarted bundles which is quite the anti-pattern. 

> is not the workbench, we need to fix it or understand it.  Most eclipse plugins
> are not OSGi bundles, they cannot be started by the OSGi framework at an
> arbitrary time

Yes. I see and agree. Is it not possible to defer all OSGi startup activities until after the Application has started that initializes the Workbench? 

It is just hard to prevent calling Display.getDefault(). One should know that calling it could interfere with the Workbench. Should I file a bug for this?

By the way: the debug.ui "Activator" is subclassing AbstractUIPlugin. One could imagine that plugins of this class should work with the workbench to avoid stuff like this.
Comment 13 Paul Webster CLA 2011-07-25 11:52:27 EDT
This is not something that can be dealt with internally.  The application starts the workbench, and workbench dependent plugins cannot start before the workbench.  That's the architecture of the workbench application.

It sounds like you are using the shotgun approach of starting all the bundles so the ones that provide OSGi services can register programmatically.  A better solution in equinox is to use Declarative Services to make the all of the services available to the OSGi framework.  As they are consumed, their contributing bundles will be started, and bundles like debug.ui will be back in their lazy-loading state.

PW
Comment 14 Wim Jongman CLA 2011-07-25 12:10:15 EDT
 
> It sounds like you are using the shotgun approach of starting all the bundles
> so the ones that provide OSGi services can register programmatically.  A better
> solution in equinox is to use Declarative Services to make the all of the
> services available to the OSGi framework.  As they are consumed, their
> contributing bundles will be started, and bundles like debug.ui will be back in
> their lazy-loading state.

We do use that but the service bundles need to be started before DS can register the services they contain. So this brings us back to maintaining a list.
Comment 15 Paul Webster CLA 2011-07-25 12:34:20 EDT
(In reply to comment #14)
> We do use that but the service bundles need to be started before DS can
> register the services they contain. So this brings us back to maintaining a
> list.

I don't understand, don't they just need to be installed to get DS to work?  They don't need to be started (in the OSGi meaning of the word) as that would defeat the purpose of DS.

In a pure OSGi world they do have to maintain a list of bundles that need to be started, they don't just start all they can find.

PW
Comment 16 Wim Jongman CLA 2011-07-25 16:01:58 EDT
(In reply to comment #15)
> (In reply to comment #14)
> > We do use that but the service bundles need to be started before DS can
> > register the services they contain. So this brings us back to maintaining a
> > list.
> 
> I don't understand, don't they just need to be installed to get DS to work? 
> They don't need to be started (in the OSGi meaning of the word) as that would
> defeat the purpose of DS.

I'm pretty sure bundles need to be started to let DS activate a service and bind that service into other services. Stopping a bundle brings the service down and DS then unbinds the references it has previously bound.

> 

What do we do with this? I would like to see some notion in the error log when this occurs. I am happy to write a patch but only if others (i.e. the people in charge of accepting the patch) see the value of such a message.
Comment 17 Thomas Schindl CLA 2011-07-25 16:11:21 EDT
we are using DS heavily in our applications and don't autostart anything. At the moement we request the service DS does the right thing.
Comment 18 Thomas Watson CLA 2011-07-25 17:28:19 EDT
(In reply to comment #17)
> we are using DS heavily in our applications and don't autostart anything. At
> the moement we request the service DS does the right thing.

This is because you are using bundles that have a lazy activation policy (Bundle-ActivationPolicy: lazy).  The platform (Equinox) has a default policy (see bug 177641 which shows that p2 is depending on this) which will persistently activate such bundles to get them into the "lazy" STARTING state.

DS runtime understands that the bundle is in this "lazy" STARTING state and will process DS components for such bundles even though they have not reached the ACTIVE state.  This can be one because bundles in the STARTING state have a valid BundleContext which DS can use to register services with.  So technically you don't have an "eager" started bundles, but you do have many lazy activated bundles that have been marked for activation.  We are just delaying their activation until the first class load.

It sounds like Wim has other bundles with DS components which do not use the lazy activation policy (this is very common in the traditional OSGi crowd).  Such bundles will not be processed by DS until they are eagerly activated.
Comment 19 Wim Jongman CLA 2011-07-26 06:32:13 EDT
sorry for repeating myself but this should really be a separate comment:

What do we do with this bug? I would like to see some notion in the error log when
this occurs. I am happy to write a patch but only if others (i.e. the people in
charge of accepting the patch) see the value of such a message.

What do y'all think?
Comment 20 Oleg Besedin CLA 2011-07-26 10:17:23 EDT
(In reply to comment #9)
> Okay but if not all parties play along with this "unknown rule" then there
> should be some guarding code in Workbench.createDisplay()
> 
> It could signal that there is already a Display thread initialized and throw a
> warning. 
> 
> ** WARNING - DISPLAY CREATED BEFORE WORKBENCH INIT COMPLETED
> 

(In reply to comment #19)
> What do we do with this bug? I would like to see some notion in the error log
> when
> this occurs. I am happy to write a patch but only if others (i.e. the people in
> charge of accepting the patch) see the value of such a message.

It is probably a good idea for the IDEApplication. I would not put such condition in the workbench code itself.

A typical UI application calls PlatformUI#createDisplay() API and is responsible for the display lifecycle. An application could get creative and, say, display a custom login screen with its own display before starting workbench, then have workbench re-use that display (hopefully, it will be in the same thread).

As Paul and Tom stated, in your case the confusion was caused by altering startup order. The startup order is a very sensitive areas and really should not be casually changed. It is fine to provide hints for the bundles you develop, but changing startup order of other bundles without deep understanding of their connections is an exercise that is bound to fail. Just leave it to the OSGi to figure out :-).
Comment 21 Lars Vogel CLA 2019-11-14 03:07:15 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

If the bug is still relevant, please remove the "stalebug" whiteboard tag.