Community
Participate
Working Groups
Build Identifier: Eclipse SDK 3.6GA I20100608-0911 We have an RCP application that dynamically loads plugins with extensions. The RCP application also dynamically unloads these plugins right before shutting down. We get these exceptions in the <workspace>/.metadata/.log during shutdown: !ENTRY org.eclipse.equinox.registry 4 2 2010-07-28 10:07:45.309 !MESSAGE Problems occurred when invoking code from plug-in: "org.eclipse.equinox.registry". !STACK 0 org.eclipse.swt.SWTException: Device is disposed at org.eclipse.swt.SWT.error(SWT.java:4083) at org.eclipse.swt.SWT.error(SWT.java:3998) at org.eclipse.swt.SWT.error(SWT.java:3969) at org.eclipse.swt.widgets.Display.error(Display.java:1204) at org.eclipse.swt.widgets.Display.syncExec(Display.java:4285) at org.eclipse.ui.internal.registry.UIExtensionTracker.applyRemove(UIExtensionTracker.java:42) at org.eclipse.core.runtime.dynamichelpers.ExtensionTracker.notify(ExtensionTracker.java:153) at org.eclipse.core.runtime.dynamichelpers.ExtensionTracker.doRemove(ExtensionTracker.java:179) at org.eclipse.core.runtime.dynamichelpers.ExtensionTracker.registryChanged(ExtensionTracker.java:119) at org.eclipse.core.internal.registry.ExtensionRegistry$2.run(ExtensionRegistry.java:921) at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42) at org.eclipse.core.internal.registry.ExtensionRegistry.processChangeEvent(ExtensionRegistry.java:919) at org.eclipse.core.runtime.spi.RegistryStrategy.processChangeEvent(RegistryStrategy.java:260) at org.eclipse.core.internal.registry.osgi.ExtensionEventDispatcherJob.run(ExtensionEventDispatcherJob.java:50) at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54) !ENTRY org.eclipse.equinox.registry 4 0 2010-07-28 10:07:45.320 !MESSAGE Error notifying registry change listener. !SUBENTRY 1 org.eclipse.equinox.registry 4 0 2010-07-28 10:07:45.320 !MESSAGE Error notifying registry change listener. !STACK 0 org.eclipse.swt.SWTException: Device is disposed at org.eclipse.swt.SWT.error(SWT.java:4083) at org.eclipse.swt.SWT.error(SWT.java:3998) at org.eclipse.swt.SWT.error(SWT.java:3969) at org.eclipse.swt.widgets.Display.error(Display.java:1204) at org.eclipse.swt.widgets.Display.syncExec(Display.java:4285) at org.eclipse.ui.internal.registry.UIExtensionTracker.applyRemove(UIExtensionTracker.java:42) at org.eclipse.core.runtime.dynamichelpers.ExtensionTracker.notify(ExtensionTracker.java:153) at org.eclipse.core.runtime.dynamichelpers.ExtensionTracker.doRemove(ExtensionTracker.java:179) at org.eclipse.core.runtime.dynamichelpers.ExtensionTracker.registryChanged(ExtensionTracker.java:119) at org.eclipse.core.internal.registry.ExtensionRegistry$2.run(ExtensionRegistry.java:921) at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42) at org.eclipse.core.internal.registry.ExtensionRegistry.processChangeEvent(ExtensionRegistry.java:919) at org.eclipse.core.runtime.spi.RegistryStrategy.processChangeEvent(RegistryStrategy.java:260) at org.eclipse.core.internal.registry.osgi.ExtensionEventDispatcherJob.run(ExtensionEventDispatcherJob.java:50) at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54) This happens because there is a race condition between the main UI thread and the ExtensionEventDispatcherJob worker thread during shutdown such that registry change events are being handled after the display has been disposed during shutdown. The registry change events that are fired are due to the dynamic unloading of plugins with extensions. Either UIExtensionTracker should be written to handle the case when the display is disposed (i.e. handle the exception and quietly ignore it) or the extension registry should provide an API that the UI can call during shutdown that waits for these ExtensionEventDispatcherJob jobs to complete (e.g. calls IJobManager.join() on a job family for these jobs). Reproducible: Always
Created attachment 180786 [details] Check if the Display is disposed
Paul / Boris, could you please take a look at this (very simple) patch and vote ?
Tom, where are you in the shutdown cycle that you are removing extensions? PW
(In reply to comment #1) > Created an attachment (id=180786) [details] > Check if the Display is disposed Eric, it looks good. I'd add the same thing to the applyAdd(*) method as well. PW
Re: comment 3 Paul, as I stated in the description. The app dynamically unloads plugins with extensions (that were dynamically loaded earlier in the app's execution)immediately before the shutdown cycle. Since the extension registry uses jobs (i.e. ExtensionEventDispatcherJob) to fire registry events (i.e. the "remove" events caused by the dynamic unloading of plugins with extensions), there is a race condition between the worker thread that is running the ExtensionEventDispatcherJob and the main UI thread which is subsequently shutdown. The patch looks good to me (and I agree with Paul that the same change should be made to applyAdd()).
(In reply to comment #5) > Re: comment 3 > > Paul, as I stated in the description. The app dynamically unloads plugins with > extensions (that were dynamically loaded earlier in the app's I'm asking about the trigger: WorkbenchAdvisor#preShutdown()? What event causes the dynamic unloading to begin? Is it related to the workbench shutdown cycle at all, or an external stimulus? PW
Looks good to me (and yes, please add the same check to the add method as well)
Re: comment 6 The trigger is not related to the workbench shutdown cycle. The trigger occurs before the workbench is shutdown. The RCP application programmatically makes the necessary calls to unload the bundles that it had dynamically loaded earlier in its execution and then explicitly calls PlatformUI.getWorkbench().close() to shutdown the app. To dynamically install plugins, we use org.osgi.framework.BundleContext.installBundle(String) followed by org.osgi.service.packageadmin.PackageAdmin.refreshPackages(Bundle[]). To dynamically uninstall plugins, we use org.osgi.framework.Bundle.stop(), followed by org.osgi.framework.Bundle.uninstall(), followed by org.osgi.service.packageadmin.PackageAdmin.refreshPackages(Bundle[]). The RCP app is presenting a wizard dialog. On the wizard pages, there is a Cancel button. The user clicks on Cancel. This triggers code that unloads the bundles and then calls PlatformUI.getWorkbench().close().
(In reply to comment #8) > The trigger is not related to the workbench shutdown cycle. The trigger occurs > before the workbench is shutdown. The RCP application programmatically makes > the necessary calls to unload the bundles that it had dynamically loaded > earlier in its execution and then explicitly calls > PlatformUI.getWorkbench().close() to shutdown the app. Thanx Tom, That seems reasonable behaviour. PW
Created attachment 180887 [details] Patch that checks for 'isDisposed' in both methods
Committed in >20101014. Applied the patch to the maintenance branch.
In M20110119-0834 PW