[EMF Forms] EMFFormsSWTLayoutDelayed: invalid thread accsess [message #1799701] |
Wed, 12 December 2018 16:08 |
Sebastian Fey 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
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.02239 seconds