Community
Participate
Working Groups
Build Identifier: M20120208-0800 Plugins should cancel during shutdown the Jobs they scheduled. If not, this may result in several errors depending on scheduling, one being: Job found still running after platform shutdown. Jobs should be canceled by the plugin that scheduled them during shutdown: org.eclipse.xtext.ui.editor.validation.ValidationJob or Job found still running after platform shutdown. Jobs should be canceled by the plugin that scheduled them during shutdown: org.eclipse.xtext.ui.editor.occurrences.OccurrenceMarker$MarkOccurrenceJob It also happened with BuildScheduler$BuildJob. Another error may occur. As most other plugins have been stopped, the getDefault() or getInstance() methods implemented in subclasses of AbstractUiPlugin usually returns null. This may for example lead to the following error. !ENTRY org.apache.log4j 4 0 2012-07-06 17:57:55.968 !MESSAGE org.eclipse.xtext.linking.lazy.LazyLinkingResource - resolution of uriFragment 'xtextLink_::0.2.19.6.0.0.0::0::/0' failed. !STACK 0 com.google.inject.ProvisionException: Guice provision errors: 1) Error in custom provider, java.lang.IllegalStateException: The bundle has not been started! at org.eclipse.xtext.service.MethodBasedModule.configure(MethodBasedModule.java:73) while locating org.eclipse.xtext.resource.IResourceDescriptions 1 error at com.google.inject.internal.InjectorImpl$4.get(InjectorImpl.java:987) at org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider.createResourceDescriptions(ResourceDescriptionsProvider.java:72) ... at org.eclipse.core.internal.resources.Project.build(Project.java:124) at org.eclipse.xtext.builder.impl.BuildScheduler$BuildJob.run(BuildScheduler.java:163) at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54) Caused by: java.lang.IllegalStateException: The bundle has not been started! at org.eclipse.xtext.ui.shared.Access$InternalProvider.get(Access.java:38) at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:40) ... This error happens because BuildScheduler$BuildJob is still running whereas org.eclipse.xtext.builder.internal.Activator.getDefault() (called at org.eclipse.xtext.ui.shared.Access$InternalProvider.get(Access.java:38)) returns null because the plugin org.eclipse.xtext.builder has already been stopped. To fix this issue, it is either possible to register all jobs scheduled by a plugin in the plugin's Activator class, or all Jobs may override the Job#belongsTo(Object) to state that they belong to the family of their plugin and the Activator should try to cancel the jobs that belongs to its family. Reproducible: Sometimes Steps to Reproduce: To reproduce the first error, put a break point in a job, do the necessary step to trigger this job and shutdown Eclipse. To reproduce the second error launch Eclipse, put a breakpoint in BuildScheduler.scheduleBuildIfNecessary, close a project (a worker thread should be paused on your breakpoint), then try to shutdown Eclipse, then unpause your breakpoint.
Created attachment 218485 [details] Makes the xtext.ui plugin's Activator cancel and wait for its plugins
Created attachment 218486 [details] Define families for xtext.ui's jobs
Created attachment 218487 [details] Define families for xtext.builder's jobs
Created attachment 218488 [details] Makes the xtext.builder plugin's Activator cancel and wait for its jobs
I made 4 patches. builderFamilies.patch and xtextuiFamilies.patch define a family for each subclass of Job I have found in xtext.ui and xtext.builder plugins. As proposed in the bug report, I have used the plugin's Activator instance as a family. Therefore, jobs defined and scheduled in org.eclipse.xtext.builder belongs to org.eclipse.xtext.builder.internal.Activator.getDefault(), and jobs defined and scheduled in org.eclipse.xtext.ui belongs to org.eclipse.xtext.ui.internal.Activator.getDefault(). If a Job already had a family, it now belongs to 2 families at the same time. builderActivator.patch cancels the jobs that belongs to the current plugin and then shows 3 possible implementations to wait for the jobs to terminate. The first one is a simple call to IJobManager#join(Object,IProgressMonitor). It is efficient and "safe" (as it will never terminate if a job is still running, therefore it fully fixes the bug reported), but if a job is stuck then Eclipse will not terminate "in a timely fashion" (as required by the specification of BunderActivator#stop() ). The second one is used in JobManager#doSutdown(). It is a bit less efficient (as it may wait up to 0.1 second even if all Jobs have terminated), it less safe as this method may exit even if some jobs have still not terminated (in less than .3 second), but this method always exit in a timely fashion. The third one uses a second thread to wait for the other jobs, and wait this thread at most TIMEOUT (here 600 ms, but it can be changed). This implementation is efficient and it will always exit in a timely fashion, but, as for the second solution, it may also exit even if some jobs have not terminated yet. Note that a job that has been requested to cancel its operation should terminate in a timely fashion, and if not it should have some good reason to do so (or it is a bug). Therefore it is probably a good idea to wait for it for a few seconds.
MarkOccurrenceJob has changed since 2.3.0, so it cannot be reproduced with this Job, but it can still be reproduced with the ValidationJob, the UpdateEditorStateJob, DirtyStateEditorSupport$UpdateEditorStateJob, OutlineRefreshJob, and the XtextReconciler. I have not been able to reproduce the second error with BuildScheduler.
Sorry, we didn't come around to look at this for 2.8. Postponing to 2.9.