Eliminated potential source of deadlocks in ResourceProblemHandler by
making delegation of handling of changed and saved files to
ResourceProblemMarkerService asynchronous
diff --git a/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/messages/Messages.java b/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/messages/Messages.java
index 5984d35..201e1d8 100644
--- a/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/messages/Messages.java
+++ b/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/messages/Messages.java
@@ -1,7 +1,7 @@
/**
* <copyright>
*
- * Copyright (c) 2008-2013 See4sys, itemis and others.
+ * Copyright (c) 2008-2019 See4sys, itemis and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -58,6 +58,8 @@
public static String job_removingModelDescriptors;
public static String job_clearingOldMetaModelDescriptors;
public static String job_initializingModelDescriptorRegistry;
+ public static String job_addingProblemMarkers;
+ public static String job_removingProblemMarkers;
public static String task_analyzingProjects;
public static String subtask_analyzingFile;
public static String task_validatingResourceScopes;
diff --git a/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/messages/Messages.properties b/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/messages/Messages.properties
index ce9adeb..b0c8d33 100644
--- a/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/messages/Messages.properties
+++ b/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/messages/Messages.properties
@@ -1,6 +1,6 @@
# <copyright>
#
-# Copyright (c) 2008-2013 See4sys, itemis and others.
+# Copyright (c) 2008-2019 See4sys, itemis and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
@@ -52,6 +52,8 @@
job_removingModelDescriptors=Removing Model Descriptors
job_clearingOldMetaModelDescriptors=Clearing Old Meta-model Descriptors
job_initializingModelDescriptorRegistry= Initializing Model Descriptor Registry
+job_addingProblemMarkers=Adding Problem Markers
+job_removingProblemMarkers=Removing Problem Markers
task_analyzingProjects=Analyzing projects
subtask_analyzingFile=Analyzing file \"{0}\"
task_validatingResourceScopes=Validating Resource Scopes
diff --git a/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/resource/ResourceProblemHandler.java b/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/resource/ResourceProblemHandler.java
index 7320809..b69f3d0 100644
--- a/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/resource/ResourceProblemHandler.java
+++ b/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/resource/ResourceProblemHandler.java
@@ -1,7 +1,7 @@
/**
* <copyright>
*
- * Copyright (c) 2008-2013 See4sys, BMW Car IT, itemis and others.
+ * Copyright (c) 2008-2019 See4sys, BMW Car IT, itemis and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -30,6 +30,11 @@
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EcorePackage;
@@ -41,12 +46,16 @@
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.sphinx.emf.Activator;
import org.eclipse.sphinx.emf.domain.factory.AbstractResourceSetListenerInstaller;
+import org.eclipse.sphinx.emf.internal.messages.Messages;
import org.eclipse.sphinx.emf.saving.SaveIndicatorUtil;
import org.eclipse.sphinx.emf.util.EcorePlatformUtil;
import org.eclipse.sphinx.emf.util.WorkspaceEditingDomainUtil;
+import org.eclipse.sphinx.platform.IExtendedPlatformConstants;
import org.eclipse.sphinx.platform.resources.DefaultResourceChangeHandler;
import org.eclipse.sphinx.platform.resources.ResourceDeltaVisitor;
+import org.eclipse.sphinx.platform.util.ExtendedPlatform;
import org.eclipse.sphinx.platform.util.PlatformLogUtil;
+import org.eclipse.sphinx.platform.util.StatusUtil;
/**
* Listens for {@link Resource resource}s that have been loaded or saved and requests the problem markers of underlying
@@ -68,8 +77,8 @@
* Default constructor.
*/
public ResourceProblemHandler() {
- super(NotificationFilter.createFeatureFilter(EcorePackage.eINSTANCE.getEResource(), Resource.RESOURCE__IS_LOADED).or(
- NotificationFilter.createFeatureFilter(EcorePackage.eINSTANCE.getEResourceSet(), ResourceSet.RESOURCE_SET__RESOURCES)));
+ super(NotificationFilter.createFeatureFilter(EcorePackage.eINSTANCE.getEResource(), Resource.RESOURCE__IS_LOADED)
+ .or(NotificationFilter.createFeatureFilter(EcorePackage.eINSTANCE.getEResourceSet(), ResourceSet.RESOURCE_SET__RESOURCES)));
}
@Override
@@ -187,24 +196,80 @@
protected void handleChangedFiles(Collection<IFile> files) {
Assert.isNotNull(files);
- ResourceProblemMarkerService.INSTANCE.removeProblemMarkers(files, null);
+ if (files.size() > 0) {
+ /*
+ * !! Important Note !! Perform as asynchronous operation with exclusive access to the affected files in
+ * order to avoid deadlocks. The workspace is locked while IResourceChangeListeners are processed (exclusive
+ * workspace access) and updating a resource's problem markers may involve creating transactions (exclusive
+ * model access). In cases where another thread is around while we are called here which already has
+ * exclusive model access but waits for exclusive workspace access we would end up in a deadlock otherwise.
+ */
+ Job job = new Job(Messages.job_removingProblemMarkers) {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ ResourceProblemMarkerService.INSTANCE.removeProblemMarkers(files, monitor);
+ return Status.OK_STATUS;
+ } catch (OperationCanceledException ex) {
+ return Status.CANCEL_STATUS;
+ } catch (Exception ex) {
+ return StatusUtil.createErrorStatus(Activator.getPlugin(), ex);
+ }
+ }
+
+ @Override
+ public boolean belongsTo(Object family) {
+ return IExtendedPlatformConstants.FAMILY_LONG_RUNNING.equals(family);
+ }
+ };
+ job.setPriority(Job.SHORT);
+ job.setRule(ExtendedPlatform.createModifySchedulingRule(files));
+ job.setSystem(true);
+ job.schedule();
+ }
}
protected void handleSavedFiles(Collection<IFile> files) {
Assert.isNotNull(files);
- Set<Resource> resources = new HashSet<Resource>();
- for (IFile file : files) {
- Resource resource = EcorePlatformUtil.getResource(file);
- if (resource != null) {
- resources.add(resource);
- }
+ if (files.size() > 0) {
+ /*
+ * !! Important Note !! Perform as asynchronous operation with exclusive access to the affected files in
+ * order to avoid deadlocks. The workspace is locked while IResourceChangeListeners are processed (exclusive
+ * workspace access) and updating a resource's problem markers may involve creating transactions (exclusive
+ * model access). In cases where another thread is around while we are called here which already has
+ * exclusive model access but waits for exclusive workspace access we would end up in a deadlock otherwise.
+ */
+ Job job = new Job(Messages.job_addingProblemMarkers) {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ Set<Resource> resources = new HashSet<Resource>();
+ for (IFile file : files) {
+ Resource resource = EcorePlatformUtil.getResource(file);
+ if (resource != null) {
+ resources.add(resource);
+ }
+ }
+
+ ResourceProblemMarkerService.INSTANCE.addProblemMarkers(resources, monitor);
+ return Status.OK_STATUS;
+ } catch (OperationCanceledException ex) {
+ return Status.CANCEL_STATUS;
+ } catch (Exception ex) {
+ return StatusUtil.createErrorStatus(Activator.getPlugin(), ex);
+ }
+ }
+
+ @Override
+ public boolean belongsTo(Object family) {
+ return IExtendedPlatformConstants.FAMILY_LONG_RUNNING.equals(family);
+ }
+ };
+ job.setPriority(Job.SHORT);
+ job.setRule(ExtendedPlatform.createModifySchedulingRule(files));
+ job.setSystem(true);
+ job.schedule();
}
-
- handleSavedResources(resources);
- }
-
- protected void handleSavedResources(Collection<Resource> resources) {
- ResourceProblemMarkerService.INSTANCE.addProblemMarkers(resources, null);
}
}
\ No newline at end of file
diff --git a/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/resource/ResourceProblemMarkerService.java b/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/resource/ResourceProblemMarkerService.java
index 619cec7..2aca172 100644
--- a/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/resource/ResourceProblemMarkerService.java
+++ b/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/internal/resource/ResourceProblemMarkerService.java
@@ -1,7 +1,7 @@
/**
* <copyright>
*
- * Copyright (c) 2008-2014 See4sys, BMW Car IT, itemis and others.
+ * Copyright (c) 2008-2019 See4sys, BMW Car IT, itemis and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -86,8 +86,8 @@
}
/**
- * Analyzes {@link Resource#getErrors() errors} and {@link Resource#getWarnings() warnings} of given
- * {@link Resource resource} and creates corresponding problem markers on underlying {@link IFile file}.
+ * Analyzes {@link Resource#getErrors() errors} and {@link Resource#getWarnings() warnings} of given {@link Resource
+ * resource} and creates corresponding problem markers on underlying {@link IFile file}.
* <p>
* The type of the problem marker being created depends on the type of {@link Resource#getErrors() error} or
* {@link Resource#getWarnings() warning} of given {@link Resource resource} and can be one of the following:
@@ -257,10 +257,16 @@
* desired.
*/
public void removeProblemMarkers(final Collection<IFile> files, final IProgressMonitor monitor) {
+ SubMonitor progress = SubMonitor.convert(monitor, files.size());
for (IFile file : files) {
if (file.isAccessible()) {
getResourceProblemMarkerFactory(file).deleteMarkers(file);
}
+
+ progress.worked(1);
+ if (progress.isCanceled()) {
+ throw new OperationCanceledException();
+ }
}
}