Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF "Technology" (Ecore Tools, EMFatic, etc)  » [EMF Forms] EMFFormsSWTLayoutDelayed: invalid thread accsess(Multiple Ui Sessions with emf)
[EMF Forms] EMFFormsSWTLayoutDelayed: invalid thread accsess [message #1799701] Wed, 12 December 2018 16:08 Go to next message
Sebastian Fey is currently offline Sebastian FeyFriend
Messages: 4
Registered: December 2018
Junior Member
We have a memory leak in our Rap web application caused by an exception killed thread

this is the exeption:

org.eclipse.swt.SWTException: Invalid thread access
	at org.eclipse.swt.SWT.error(SWT.java:3708)
	at org.eclipse.swt.SWT.error(SWT.java:3631)
	at org.eclipse.swt.SWT.error(SWT.java:3602)
	at org.eclipse.swt.widgets.Widget.error(Widget.java:1018)
	at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:956)
	at org.eclipse.swt.widgets.Composite.layout(Composite.java:367)
	at org.eclipse.emfforms.spi.swt.core.layout.EMFFormsSWTLayoutDelayed$1$1.run(EMFFormsSWTLayoutDelayed.java:73)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:38)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:193)
	at org.eclipse.swt.widgets.Display.runPendingMessages(Display.java:1201)
	at org.eclipse.swt.widgets.Display.safeReadAndDispatch(Display.java:1181)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:1173)
	at org.eclipse.rap.rwt.internal.lifecycle.ProcessAction.execute(ProcessAction.java:29)
	at org.eclipse.rap.rwt.internal.lifecycle.PhaseExecutor.execute(PhaseExecutor.java:38)
	at org.eclipse.rap.rwt.internal.lifecycle.SimpleLifeCycle.execute(SimpleLifeCycle.java:46)
	at org.eclipse.rap.rwt.internal.service.RWTMessageHandler.executeLifeCycle(RWTMessageHandler.java:57)
	at org.eclipse.rap.rwt.internal.service.RWTMessageHandler.handleMessage(RWTMessageHandler.java:41)
	at org.eclipse.rap.rwt.internal.remote.MessageChainElement.handleMessage(MessageChainElement.java:29)
	at org.eclipse.rap.rwt.internal.service.LifeCycleServiceHandler.processMessage(LifeCycleServiceHandler.java:128)
	at org.eclipse.rap.rwt.internal.service.LifeCycleServiceHandler.processUIRequest(LifeCycleServiceHandler.java:100)
	at org.eclipse.rap.rwt.internal.service.LifeCycleServiceHandler.synchronizedService(LifeCycleServiceHandler.java:75)
	at org.eclipse.rap.rwt.internal.service.LifeCycleServiceHandler.service(LifeCycleServiceHandler.java:66)
	at org.eclipse.rap.rwt.engine.RWTServlet.handleValidRequest(RWTServlet.java:135)
	at org.eclipse.rap.rwt.engine.RWTServlet.handleRequest(RWTServlet.java:117)
	at org.eclipse.rap.rwt.engine.RWTServlet.doPost(RWTServlet.java:107)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
	at org.eclipse.rap.rwt.osgi.internal.CutOffContextPathWrapper.service(CutOffContextPathWrapper.java:106)
	at org.eclipse.equinox.http.servlet.internal.HttpServiceRuntimeImpl$LegacyServlet.service(HttpServiceRuntimeImpl.java:1223)
	at org.eclipse.equinox.http.servlet.internal.registration.EndpointRegistration.service(EndpointRegistration.java:148)
	at org.eclipse.equinox.http.servlet.internal.servlet.FilterChainImpl.doFilter(FilterChainImpl.java:50)
	at logging.UserInfoServletFilter.doFilter(UserInfoServletFilter.java:41)
	at org.eclipse.equinox.http.registry.internal.FilterManager$FilterWrapper.doFilter(FilterManager.java:173)
	at org.eclipse.equinox.http.servlet.internal.HttpServiceRuntimeImpl$LegacyFilterFactory$LegacyFilter.doFilter(HttpServiceRuntimeImpl.java:1182)
	at org.eclipse.equinox.http.servlet.internal.registration.FilterRegistration.doFilter(FilterRegistration.java:121)
	at org.eclipse.equinox.http.servlet.internal.servlet.FilterChainImpl.doFilter(FilterChainImpl.java:45)
	at org.eclipse.equinox.http.servlet.internal.servlet.ResponseStateHandler.processRequest(ResponseStateHandler.java:70)
	at org.eclipse.equinox.http.servlet.internal.context.DispatchTargets.doDispatch(DispatchTargets.java:131)
	at org.eclipse.equinox.http.servlet.internal.servlet.ProxyServlet.service(ProxyServlet.java:74)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
	at org.eclipse.equinox.http.jetty.internal.HttpServerManager$InternalHttpServiceServlet.service(HttpServerManager.java:284)
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:841)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:535)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1253)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1155)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
	at org.eclipse.jetty.server.Server.handle(Server.java:561)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:334)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:104)
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:247)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:140)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:243)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:679)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:597)
	at java.lang.Thread.run(Thread.java:748)


Its somethimes, (not always) happens when multiple users open the same Vview or, after opening the VView, clicking concurrently on elements in it.

After the exception, opening any Vview fills the linked hashmap "requestedLayouts" of the class EMFFormsSWTLayoutDelayed, which also contains thread killed by the exception.

this is how we create the view:

  private ViewModelContext createViewModelContext(PackingItem(implements Eobject) packingItem) {
VViewModelLoadingProperties loadingProperties = VViewFactory.eINSTANCE.createViewModelLoadingProperties();

        if (ViewSearchUtils.isViewSearchEnabled()) { //  true or false , makes no memleak difference 
            viewSearchSuggestionProvider = new ViewSearchSuggestionProvider();
            loadingProperties.addInheritableProperty(VIEW_SEARCH_SUGGESTION_PROVIDER, viewSearchSuggestionProvider);
            loadingProperties.addInheritableProperty(ViewSearchUtils.CATEGORY_SELECTION_MODEL,
                    new CategorySelectionModel());
        }
        VView view = ViewProviderHelper.getView(packingItem, loadingProperties);
        return ViewModelContextFactory.INSTANCE.createViewModelContext(view, packingItem);


Later, we render it this way:
 try {
            ECPSWTView ecpView = ECPSWTViewRenderer.INSTANCE.render(parent, context);
            GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(ecpView.getSWTControl());
        } catch (ECPRendererException exception) {
            LOG.error("Could not load article view"); //$NON-NLS-1$
        }


I found this issue: https://www.eclipse.org/forums/index.php?t=msg&th=1087116&goto=1766928&
So I put the render method to in an async class we already use:

public abstract class AsyncUiUpdater {

    private Thread bgThread;
    private ServerPushSession pushSession;
    private Exception exception;

    public void start() {

        // init
        pushSession = new ServerPushSession();
        bgThread = new Thread(this::runInBackground);
        bgThread.setDaemon(false);

        // start async session/thread
        pushSession.start();
        bgThread.start();

    }

    private void runInBackground() {

        try (AutoCloseable c = pushSession::stop) {

            doAsyncWork();

            updateUiSafely(this::onCompletion);

        } catch (Exception e) {

            this.exception = e;

            updateUiSafely(this::onError);

        }

    }

    private void updateUiSafely(Runnable r) {

        Widget widget = getUpdateableWidget();

        if (widget != null && !widget.isDisposed()) {
            widget.getDisplay().asyncExec(r);
        }

    }

    /**
     * @return returns exception, if an error occurred
     */
    public Exception getException() {
        return exception;
    }

    /**
     * @return UI-Widget, thats need to be updated after work is done
     */
    protected abstract Widget getUpdateableWidget();

    /**
     * long work that needs to be done asynchronously, not in the UI-Thread
     */
    protected abstract void doAsyncWork();

    /**
     * UI-Updates, after work is done successfully
     */
    protected abstract void onCompletion();

    /**
     * UI-Updates, in case of an error in the asynchronous thread
     */
    protected abstract void onError();

}


public class AsyncRenderer extends AsyncUiUpdater {

    private static final Logger LOG = LoggerFactory.getLogger(AsyncRenderer.class);

    Composite parent;
    ViewModelContext context;


    public AsyncRenderer(Composite parent, ViewModelContext context){
        this.parent = parent;
        this.context = context;
    }

    @Override
    protected Widget getUpdateableWidget() {
        return parent;
    }

    @Override
    protected void doAsyncWork() {
        return;
    }

    @Override
    protected void onCompletion() {
        try {
            ECPSWTView ecpView = ECPSWTViewRenderer.INSTANCE.render(parent, context);
            GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(ecpView.getSWTControl());
        } catch (ECPRendererException exception) {
            LOG.error("Could not load article view"); //$NON-NLS-1$
        }
    }

    @Override
    protected void onError() {
        // TODO Auto-generated method stub

    }
}


Now, with the async rendering, the view is rendered only once and only in one session, the other sessions won't be able to render it anymore with the async rendering.
Wierd:
Its possible to get the view for some others too if you load the same view/browser tab at the same time.
-> then you are able to get the exeption from above again.
Also, having the auto suggest enabled, searching with it will show the view again.

Refering to the topic https://www.eclipse.org/forums/index.php?t=msg&th=1087116&goto=1766928& I mentioned before, there
has to be some static content shared between the sessions causing the problem.

I'm not that deep in the code of the application, so the static content might be in our code.
But at least, it would be nice if the dead thread in EMF wouldn't cause a leak in this constellation.

Versions:
Ecore 2.13
Rap rwt 3.4

I just hope someone knows what we might do wrong.

[Updated on: Wed, 12 December 2018 16:11]

Report message to a moderator

Re: [EMF Forms] EMFFormsSWTLayoutDelayed: invalid thread accsess [message #1799791 is a reply to message #1799701] Thu, 13 December 2018 14:26 Go to previous messageGo to next message
Sebastian Fey is currently offline Sebastian FeyFriend
Messages: 4
Registered: December 2018
Junior Member
Figured out that it is a framework bug in the class EMFFormsSWTLayoutDelayed, dev is informed.

[Updated on: Thu, 13 December 2018 14:28]

Report message to a moderator

Re: [EMF Forms] EMFFormsSWTLayoutDelayed: invalid thread accsess [message #1799821 is a reply to message #1799701] Fri, 14 December 2018 09:03 Go to previous message
Eugen Neufeld is currently offline Eugen NeufeldFriend
Messages: 174
Registered: May 2015
Senior Member
Hi Sebastian,

we checked our code.
There is a RAP specific service available: org.eclipse.emf.ecp.view.internal.util.swt.rap.EMFFormsSWTLayoutDirect
It is part of the org.eclipse.emf.ecp.view.util.swt.rap bundle.

The EMFFormsSWTLayoutDelayed is not meant to be used in a RAP environment.

You can also provide your own OSGi Service which implements EMFFormsSWTLayoutOptimizer to override the default behavior (the EMFFormsSWTLayoutDelayed).

Best,
Eugen


--
Eugen Neufeld

Get professional Eclipse developer support:
http://eclipsesource.com/en/services/developer-support/
Previous Topic:[EMF FORMS] TableControl WithDialog
Next Topic:sub metamodel detection
Goto Forum:
  


Current Time: Thu Mar 28 12:01:13 GMT 2024

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

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

Back to the top