Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Eclipse 4 » Invalid Thread Access on EclipseContext.dispose()(Eclipse 4.2)
Invalid Thread Access on EclipseContext.dispose() [message #1061926] Tue, 04 June 2013 18:15 Go to next message
Jo Jaquinta is currently offline Jo JaquintaFriend
Messages: 40
Registered: January 2013
Location: Boston
Member

So I have a situation where I do some work on a background thread. Since I use injection in there, I create an EclipseContext, populate it, do my business and then dispose it. However I'm getting an Invalid Thread Access when I do the dispose.
I use MVC a lot and I usually get this sort of error when I've forgotten to detach a UI object from listening to a back end object. But this trace doesn't seem to go through any of my usual suspects.
Does this look like a bug I should report? Or am I doing something wrong?


Exception in thread "Autorun" org.eclipse.e4.core.di.InjectionException: org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:63)
at org.eclipse.e4.core.internal.contexts.ContextObjectSupplier$ContextInjectionListener.update(ContextObjectSupplier.java:88)
at org.eclipse.e4.core.internal.contexts.TrackableComputationExt.update(
TrackableComputationExt.java:107)
at org.eclipse.e4.core.internal.contexts.EclipseContext.processScheduled(EclipseContext.java:328)
at org.eclipse.e4.core.internal.contexts.EclipseContext.set(EclipseContext.java:342)
at org.eclipse.e4.core.internal.contexts.EclipseContext.dispose(EclipseContext.java:192)
at org.eclipse.e4.core.internal.contexts.EclipseContext.dispose(EclipseContext.java:160)
at com.ibm.openpages.config.ui.logic.ActionExecutionLauncher.run(UnknownSource)
at com.ibm.openpages.config.admin.ui.top.TopologyRichDisplay.doRunBG(Unknown Source)
at com.ibm.openpages.config.admin.ui.top.TopologyRichDisplay$6.run(Unknown Source)
Caused by: org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(SWT.java:4361)
at org.eclipse.swt.SWT.error(SWT.java:4276)
at org.eclipse.swt.SWT.error(SWT.java:4247)
at org.eclipse.swt.widgets.Widget.error(Widget.java:468)
at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:359)
at org.eclipse.swt.widgets.Widget.setData(Widget.java:1220)
at org.eclipse.e4.ui.css.swt.dom.WidgetElement.setCSSClass(WidgetElement.java:65)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$11.setClassnameAndId(PartRenderingEngine.java:1248)
at org.eclipse.e4.ui.workbench.renderers.swt.SWTPartRenderer.setCSSInfo(SWTPartRenderer.java:85)
at org.eclipse.e4.ui.workbench.renderers.swt.WBWRenderer.styleStack(WBWRenderer.java:176)
at org.eclipse.e4.ui.workbench.renderers.swt.WBWRenderer.trackActivePart(WBWRenderer.java:145)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:45)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:599)
at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:56)
... 9 more



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jo Grant, Senior Software Engineer
Admin and Config Console Architect
OpenPages, IBM
Re: Invalid Thread Access on EclipseContext.dispose() [message #1061955 is a reply to message #1061926] Wed, 05 June 2013 06:53 Go to previous messageGo to next message
Andrzej Szczepanski is currently offline Andrzej SzczepanskiFriend
Messages: 16
Registered: May 2013
Junior Member
Looks like, by running your background thread you access some SWT widgets and stuff, and that's only allowed in SWT's main thread. Invalid thread access exception can usually be avoided by using UISynchronize's syncExec() and asyncExec(), see:
http://www.vogella.com/articles/EclipseJobs/article.html#eclipsejobs_uisynchronize

Could it be just that simple?
Re: Invalid Thread Access on EclipseContext.dispose() [message #1062034 is a reply to message #1061955] Wed, 05 June 2013 14:02 Go to previous messageGo to next message
Jo Jaquinta is currently offline Jo JaquintaFriend
Messages: 40
Registered: January 2013
Location: Boston
Member

No, it is not that simple. I'm quite familiar with handing off between the UI thread and background thread. My background thread does many things with the UI. It hands off, waits, resumes, etc, etc. That's not an issue.
If you note, the Invalid Thread Access call stack only goes through Eclipse code. Not my code. For some reason calling dispose on the EclipseContext I made is triggering something that should be on the UI thread. This only happens in some circumstances. As a hack, I catch the invalid thread access and if it occurs, I re-run the dispose on the UI thread.
TrackableComputationExt.update() does something that makes WBWRenderer.trackActivePart() do something. Looks like it is updating the styling of something somewhere.
I just can't work out why disposing a EclipseContext would make an element of the UI want to change its style. O_o


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jo Grant, Senior Software Engineer
Admin and Config Console Architect
OpenPages, IBM
Re: Invalid Thread Access on EclipseContext.dispose() [message #1062150 is a reply to message #1062034] Thu, 06 June 2013 09:07 Go to previous messageGo to next message
Sopot Cela is currently offline Sopot CelaFriend
Messages: 597
Registered: December 2010
Senior Member

I'm supposing the context you mingle with is an MPart context (keep in mind that every part has its own context). If so:

- disposing a context triggers a @PreDestroy (if present) on your POJO (bundleclass://...) which in turn might do some SWT manipulations
- disposing the context of a part tells the framework to find another part to activate. Like when you close an editor in eclipse IDE, the framework will look for another part to activate (e.g. the next editor) and this has to include SWT manipulations. It has to do it otherwise there would be an orphan focus and things would get bad. Since there is trackActivePart() in your stack, this is most likely the case.
Re: Invalid Thread Access on EclipseContext.dispose() [message #1062225 is a reply to message #1062150] Thu, 06 June 2013 14:55 Go to previous messageGo to next message
Jo Jaquinta is currently offline Jo JaquintaFriend
Messages: 40
Registered: January 2013
Location: Boston
Member

I'm not quite sure what you mean by "mingle". I'll explain in more detail below.
However, if your suggestion was right, that I had a @PreDestroy that did some SWT manipulations, I would expect to see that class's code in the Invalid Thread Exception callstack. All I see on that call stack are Eclipse internals. Thus my question: is this an Eclipse bug?

Overall things look like this:
There's a class, ActionExecutionLauncher, which is a helper class for launching a unit of business logic (what we call an action, no relation to Eclipse actions). The visualization used for the running logic is determined by a parameter (and may be none at all).
So, everything starts when a static function is called on this class. It gets passed how to access the business logic, the method to visualize it, and some other stuff, and an IEclipseContext.
The first thing the static functions does is create a new EclipseContext from the context passed in, and populates it with most of the arguments.
Then the static function makes an instance of itself using ContextInjectionFactory and the sub context it just made.
The instantiated class sets a number of internal variables via injection and a @PostConstruct method.
The static function takes the instantiated class (which implements Runnable), wraps it in a thread, and kicks it off (background). It then returns to the caller.
The instantiated class's run function does the business of invoking the business logic specified. The business logic has access to the created sub-context. It may use this to create some UI. If it does, it hands off between the background and UI threads to do so.
Ultimately, the business logic returns.
At that point we try to clean up the sub-context by calling dispose and that is where we get the Invalid Thread Access.


Hmm. So sometimes the business logic will leave up a panel with its results after it "finishes". When we create a perspective/part/dialog does e4 automatically create another sub-context? If so then *that* might have some SWT stuff in it, and when ActionExecutionLauncher disposes it's sub-context the implementation of EclipseContext (according to GrepCode) also disposes all contexts created as children. Could that be what is happening?


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jo Grant, Senior Software Engineer
Admin and Config Console Architect
OpenPages, IBM
Re: Invalid Thread Access on EclipseContext.dispose() [message #1062228 is a reply to message #1062225] Thu, 06 June 2013 15:29 Go to previous messageGo to next message
Sopot Cela is currently offline Sopot CelaFriend
Messages: 597
Registered: December 2010
Senior Member

I followed your description to a certain level of detail but still not to the point of having a suspect.

I'd just go back to your stack trace. Tracing back: SWT Error -> setCssClass -> blablabla -> trackActivePart. From here (going backwards) you see reflections calls. These are made from the DI container. the trackActivePart signature is:

@Inject
void trackActivePart(@Optional @Named(IServiceConstants.ACTIVE_PART) MPart p) {


That means that it will get called by the DI (specifically CIF.invoke which uses those reflection calls) *whenever* the active part (value of the ISC.ACTIVE_PART key in the context) changes. Since we have no more stack I can just speculate from this point. So, your IEclipseContext#dispose causes the active part to change: IEC#dispose -> unknown -> change of active part. To get to the unknown you put a breakpoint in the trackActivePart method. If you don't have the sources just open the .class file, right click the method in the outline view - > Toggle method breakpoint. At that point we can have the call stack and we would be able to see the full sequence of events.
Re: Invalid Thread Access on EclipseContext.dispose() [message #1062240 is a reply to message #1062228] Thu, 06 June 2013 16:18 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas SchindlFriend
Messages: 5487
Registered: July 2009
Senior Member
As a general rule don't interact with the IEclipseContext on a none
UI-Thread.

If you have any information you want to pass around in an async fashion
I'd say you should use the IEventBroker.

Tom

On 06.06.13 17:29, Sopot Cela wrote:
> I followed your description to a certain level of detail but still not
> to the point of having a suspect.
>
> I'd just go back to your stack trace. Tracing back: SWT Error ->
> setCssClass -> blablabla -> trackActivePart. From here (going backwards)
> you see reflections calls. These are made from the DI container. the
> trackActivePart signature is:
>
> @Inject
> void trackActivePart(@Optional @Named(IServiceConstants.ACTIVE_PART)
> MPart p) {
>
>
> That means that it will get called by the DI (specifically CIF.invoke
> which uses those reflection calls) *whenever* the active part (value of
> the ISC.ACTIVE_PART key in the context) changes. Since we have no more
> stack I can just speculate from this point. So, your
> IEclipseContext#dispose causes the active part to change: IEC#dispose ->
> unknown -> change of active part. To get to the unknown you put a
> breakpoint in the trackActivePart method. If you don't have the sources
> just open the .class file, right click the method in the outline view -
> > Toggle method breakpoint. At that point we can have the call stack
> and we would be able to see the full sequence of events.
Re: Invalid Thread Access on EclipseContext.dispose() [message #1062248 is a reply to message #1062240] Thu, 06 June 2013 16:44 Go to previous messageGo to next message
Jo Jaquinta is currently offline Jo JaquintaFriend
Messages: 40
Registered: January 2013
Location: Boston
Member

It seems counterintuitive to say to only use a IEclipseContext on the UI thread. Surely this is specifically for tracking and updating model elements, not UI elements.
I would think it would more be the case that if a model element has to update the UI, that it should make sure it is on the UI thread before doing so.
I'm using an EclipseContext to pass around context. I.e. what is the environment this business logic is operating in. It's all top-down stuff. I'm not trying to alert it to something that has happened, or to broadcast something. It fits a context model, not an event model.


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jo Grant, Senior Software Engineer
Admin and Config Console Architect
OpenPages, IBM
Re: Invalid Thread Access on EclipseContext.dispose() [message #1062348 is a reply to message #1062248] Fri, 07 June 2013 10:37 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas SchindlFriend
Messages: 5487
Registered: July 2009
Senior Member
As long as you modify your own values you are right but at the very
moment you modify those of others (and disposing does that because it
modifies the parent context which potential bubbles up the chain) you
are faced with problems like this.

Protecting all our code to handle this "I want to modify the
IEclipseContext" from any thread is not a going to happen if you ask me.

My suggestion would be to at least execute the dispose using
UISynchronizer which will fix your problem.

Tom

On 06.06.13 18:44, Jo Jaquinta wrote:
> It seems counterintuitive to say to only use a IEclipseContext on the UI
> thread. Surely this is specifically for tracking and updating model
> elements, not UI elements.
> I would think it would more be the case that if a model element has to
> update the UI, that it should make sure it is on the UI thread before
> doing so.
> I'm using an EclipseContext to pass around context. I.e. what is the
> environment this business logic is operating in. It's all top-down
> stuff. I'm not trying to alert it to something that has happened, or to
> broadcast something. It fits a context model, not an event model.
Re: Invalid Thread Access on EclipseContext.dispose() [message #1062389 is a reply to message #1062348] Fri, 07 June 2013 13:58 Go to previous messageGo to next message
Jo Jaquinta is currently offline Jo JaquintaFriend
Messages: 40
Registered: January 2013
Location: Boston
Member

So cleaning up after myself and disposing a resource that I created (as per recommended practice) counts as modifying someone else's code? That just seems bad design.
Similarly, what is the point of having a separate model layer if it is this intimately entwined with the view layer? It's just not MVC as I know it.
I have to be very disciplined in my code, which has quite complex layers, to ensure that as the view layer listens to the model to reflect changes, it makes sure it executes on the right thread. Even so far as having an extra method on my generic bean addUIPropertyChangeListener, which puts and property change notification onto the UI thread. Why should I expect less from Eclipse core code?

This is a small thing, with an easy hack to fix as you have described. But there is nothing intuitive about having to put the disposal of a model element on the UI thread. It makes me a little nervous to think that other problems like this might be lurking in the code.


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jo Grant, Senior Software Engineer
Admin and Config Console Architect
OpenPages, IBM
Re: Invalid Thread Access on EclipseContext.dispose() [message #1064124 is a reply to message #1062389] Mon, 17 June 2013 18:09 Go to previous messageGo to next message
Eric Moffatt is currently offline Eric MoffattFriend
Messages: 118
Registered: July 2009
Senior Member
Jo, note that the model *is* the UI in this case. This is not 'normal' MVC like you see in a TreeViewer (which I believe also requires being on the UI thread in at least some cases). In Eclipse 4 / e4 almost all contexts are 'owned' by some UI Model element that is currently 'live' in the UI (if it hadn't been rendered its context would be 'null'). The idea of having an abstract model to describe the UI was never intended as a way to allow concurrency but still has value.
Re: Invalid Thread Access on EclipseContext.dispose() [message #1064129 is a reply to message #1064124] Mon, 17 June 2013 18:24 Go to previous messageGo to next message
Jo Jaquinta is currently offline Jo JaquintaFriend
Messages: 40
Registered: January 2013
Location: Boston
Member

Hey Eric. That's all fair enough. But what I have difficulty with is that the exception is coming from something somewhere in the Context hierarchy that is completely outside my control. I create a context, I use it, I dispose of it. However, I get this error because out there somewhere a UI object is listening to it. Sometimes it happens, sometimes it doesn't. As a developer I don't have any way of knowing if it's going to happen or not. My fear is that at someone might write their code without putting it on the UI thread because in their testing it never hit the case where whatever mysterious force is at work, requires it to be on the UI thread. Then, out in the field, that happens and, BANG they get this exception.
If this is a knock-on effect of the way EclipseContext.dispose() is implemented, perhaps that function should put its internals on the UI thread. That would save every developer everywhere from having to implicitly know that it is dangerous to dispose of this non-UI object off the UI thread. Right now this is non-intuitive.
Just sayin...


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jo Grant, Senior Software Engineer
Admin and Config Console Architect
OpenPages, IBM
Re: Invalid Thread Access on EclipseContext.dispose() [message #1064250 is a reply to message #1064129] Tue, 18 June 2013 12:06 Go to previous messageGo to next message
Paul Webster is currently offline Paul WebsterFriend
Messages: 6859
Registered: July 2009
Location: Ottawa
Senior Member

On 06/17/2013 02:24 PM, Jo Jaquinta wrote:
> Hey Eric. That's all fair enough. But what I have difficulty with is
> that the exception is coming from something somewhere in the Context
> hierarchy that is completely outside my control.

It is a quirk (flaw?) of how the EclipseContexts are architected:

org.eclipse.e4.core.internal.contexts.TrackableComputationExt.update(
TrackableComputationExt.java:107)
at
org.eclipse.e4.core.internal.contexts.EclipseContext.processScheduled(EclipseContext.java:328)
at
org.eclipse.e4.core.internal.contexts.EclipseContext.set(EclipseContext.java:342)
at
org.eclipse.e4.core.internal.contexts.EclipseContext.dispose(EclipseContext.java:192)
at
org.eclipse.e4.core.internal.contexts.EclipseContext.dispose(EclipseContext.java:160)


Certain actions on the context allow any scheduled work to proceed. The
current implementation runs any scheduled computations, no matter what
EclipseContext they belong to. In the case you hit, some of the pending
work was on the UI thread.

In the 4.x workbench, we expect interaction with any EclipseContext to
be on the workbench (it even effects EclipseContexts not attached to the
hierarchy).

One possibility would be to allow methods to state they only run on the
UI thread, similar to @UIEventTopic (@UIThread @Inject?) ... but this
would require some chicanery as EclipseContexts are pretty low in the
architecture and cannot see anything to do with UI.

It probably needs a bug for further discussion.

Later,
PW



--
Paul Webster
http://wiki.eclipse.org/Platform_Command_Framework
http://wiki.eclipse.org/Command_Core_Expressions
http://wiki.eclipse.org/Platform_Expression_Framework
http://wiki.eclipse.org/Menu_Contributions
http://wiki.eclipse.org/Menus_Extension_Mapping
http://help.eclipse.org/helios/index.jsp?topic=/org.eclipse.platform.doc.isv/guide/workbench.htm


Re: Invalid Thread Access on EclipseContext.dispose() [message #1064308 is a reply to message #1064250] Tue, 18 June 2013 15:27 Go to previous message
Jo Jaquinta is currently offline Jo JaquintaFriend
Messages: 40
Registered: January 2013
Location: Boston
Member

Thanks for the cogent response, Paul. That makes some of the internal code I was looking at make more sense. It does, I think, magnify the potential of the problem. If these scheduled tasks can come from anywhere, then it is harder to predict when they will or won't want to be on the UI thread.
I really like the annotation approach. My own code has many front and back end layers. It bounces on and off the UI thread all the time. I facilitate this by having my primary Bean class support property change propagation with both an addPropertyChangeListener() and addUIPropertyChangeListener() methods. The latter marks that listener as to be notified of the change on the UI thread. It serves. But I think it would be more elegant if the listener itself could mark itself as needing to be on the UI thread with an annotation rather than a special API.
I'll have to read up on annotations now. Smile


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jo Grant, Senior Software Engineer
Admin and Config Console Architect
OpenPages, IBM
Previous Topic:Access Menu at runtime
Next Topic:IEditorPart loses custom icon on detach/move
Goto Forum:
  


Current Time: Wed Dec 17 23:08:47 GMT 2014

Powered by FUDForum. Page generated in 0.02209 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software