Bug 579065 - parallel workspace save

copied from jdt JavaModelManager
https://bugs.eclipse.org/bugs/show_bug.cgi?id=576646#c30

Change-Id: Id33bfe7e94d5a62c967a5dad120aa007ef845b2a
Signed-off-by: Joerg Kubitz <jkubitz-eclipse@gmx.de>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.resources/+/190808
Tested-by: Platform Bot <platform-bot@eclipse.org>
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/SaveManager.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/SaveManager.java
index 5ad0765..83ca93f 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/SaveManager.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/SaveManager.java
@@ -27,6 +27,8 @@
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.*;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
 import java.util.zip.*;
 import org.eclipse.core.filesystem.EFS;
 import org.eclipse.core.filesystem.IFileStore;
@@ -1732,8 +1734,27 @@
 		if (root.getType() == IResource.PROJECT)
 			return;
 		IProject[] projects = ((IWorkspaceRoot) root).getProjects(IContainer.INCLUDE_HIDDEN);
-		for (IProject project : projects)
-			visitAndSave(project);
+		// never use a shared ForkJoinPool.commonPool() as it may be busy with other tasks, which might deadlock:
+		ForkJoinPool forkJoinPool =  new ForkJoinPool(ForkJoinPool.getCommonPoolParallelism());
+		IStatus[] stats;
+		try {
+			stats = forkJoinPool.submit(() -> Arrays.stream(projects).parallel().map(project -> {
+				try {
+					visitAndSave(project);
+				} catch (CoreException e) {
+					return e.getStatus();
+				}
+				return null;
+			}).filter(Objects::nonNull).toArray(IStatus[]::new)).get();
+		} catch (InterruptedException | ExecutionException e) {
+			throw new CoreException(Status.error(Messages.resources_saveProblem, e));
+		} finally {
+			forkJoinPool.shutdown();
+		}
+		if (stats.length > 0) {
+			throw new CoreException(new MultiStatus(ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, stats,
+					Messages.resources_saveProblem, null));
+		}
 	}
 
 	/**