From a6c93c750c5403bd07727b2cb1de9d7126c47f4e Mon Sep 17 00:00:00 2001 From: tcornerstone Date: Tue, 21 Oct 2025 16:25:07 +0200 Subject: [PATCH 1/2] Use progress estimation for waiting for async background tasks. --- .../org/eclipse/tea/core/BackgroundTask.java | 85 +++++++++++++++++-- 1 file changed, 80 insertions(+), 5 deletions(-) diff --git a/bundles/org.eclipse.tea.core/src/org/eclipse/tea/core/BackgroundTask.java b/bundles/org.eclipse.tea.core/src/org/eclipse/tea/core/BackgroundTask.java index 62203a4..f900cef 100644 --- a/bundles/org.eclipse.tea.core/src/org/eclipse/tea/core/BackgroundTask.java +++ b/bundles/org.eclipse.tea.core/src/org/eclipse/tea/core/BackgroundTask.java @@ -16,10 +16,16 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; import org.eclipse.e4.core.contexts.ContextInjectionFactory; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.tea.core.internal.TaskProgressEstimationService; +import org.eclipse.tea.core.internal.TaskingEngineActivator; import org.eclipse.tea.core.internal.model.TaskingModel; +import org.eclipse.tea.core.services.TaskProgressTracker; +import org.eclipse.tea.core.services.TaskProgressTracker.TaskProgressProvider; public class BackgroundTask { @@ -27,7 +33,7 @@ public class BackgroundTask { .newFixedThreadPool(Runtime.getRuntime().availableProcessors()); private final Object task; - private Future future; + private Future future; public BackgroundTask(Object task) { Object actualTask; @@ -44,52 +50,121 @@ public BackgroundTask(Object task) { this.task = actualTask; } + private static final TaskProgressTracker EMPTY_PROGRESS_TRACKER = new TaskProgressTracker() { + + @Override + public void worked(int amount) { + + } + + @Override + public boolean isCanceled() { + return false; + } + + @Override + public void setTaskName(String name) { + + } + }; + @Execute public void run(IEclipseContext context) throws Exception { future = backgroundTasks.submit(() -> { + IEclipseContext taskCtx = context.createChild(); ContextInjectionFactory.invoke(task, Execute.class, context); + return taskCtx.get(IStatus.class); }); } public Object barrier() { return new Object() { @Execute - public Object doWait() throws Exception { - return future.get(); + public Object doWait(TaskProgressEstimationService progressService, TaskProgressTracker rootTracker) + throws Exception { + String estimationId = progressService.calculateId(task); + if (estimationId != null) { + progressService.begin(estimationId, EMPTY_PROGRESS_TRACKER); + } + Future ticker = tickProgressTracker(rootTracker, getWork(progressService)); + IStatus taskStatus = future.get(); + if (estimationId != null) { + progressService.finish(estimationId, taskStatus); + } + ticker.cancel(true); + return taskStatus; } @Override public String toString() { return "Wait for: " + BackgroundTask.this.toString(); } + + @TaskProgressProvider + public int getWork(TaskProgressEstimationService progressService) { + String estimationId = progressService.calculateId(task); + return estimationId == null ? 1 : progressService.getEstimatedTicks(estimationId); + } }; } public static Object allBarrier(List tasks) { List toAwait = new ArrayList<>(); + int hash = 0; for (Object task : tasks) { if (task instanceof BackgroundTask) { toAwait.add((BackgroundTask) task); + hash ^= ((BackgroundTask) task).task.getClass().getName().hashCode(); } } if (toAwait.isEmpty()) { return null; } + String estimationId = "await_async_" + tasks.size() + "_" + hash; + return new Object() { @Execute - public void doWaitAll(IEclipseContext context) throws Exception { + public void doWaitAll(IEclipseContext context, TaskProgressTracker tracker, + TaskProgressEstimationService progressService) throws Exception { + Future ticker = tickProgressTracker(tracker, getWork(progressService)); + progressService.begin(estimationId, EMPTY_PROGRESS_TRACKER); + int severity = 0; for (BackgroundTask bt : toAwait) { - bt.future.get(); + severity |= bt.future.get().getSeverity(); } + progressService.finish(estimationId, new Status(severity, TaskingEngineActivator.PLUGIN_ID, + "Finished waiting for background tasks.")); + ticker.cancel(true); } @Override public String toString() { return "Await unfinished background tasks."; } + + @TaskProgressProvider + public int getWork(TaskProgressEstimationService progressService) { + return progressService.getEstimatedTicks(estimationId); + } }; } + private static Future tickProgressTracker(TaskProgressTracker rootTracker, long estimationTicks) { + int resolution = 100; + return backgroundTasks.submit(() -> { + long remaining = estimationTicks; + while (remaining > 0) { + try { + Thread.sleep(resolution); + } catch (InterruptedException e) { + return; // expected if task completes earlier + } + rootTracker.worked(1); + remaining--; + } + }); + } + @Override public String toString() { return TaskingModel.getTaskName(task) + " (parallel)"; From a6416c87535b70967a11129a973cfb53a9a1f2d2 Mon Sep 17 00:00:00 2001 From: tcornerstone Date: Tue, 21 Oct 2025 16:25:53 +0200 Subject: [PATCH 2/2] Properly provide maximum progress in TaskCleanWorkspace. --- .../eclipse/tea/library/build/tasks/TaskCleanWorkspace.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bundles/org.eclipse.tea.library.build/src/org/eclipse/tea/library/build/tasks/TaskCleanWorkspace.java b/bundles/org.eclipse.tea.library.build/src/org/eclipse/tea/library/build/tasks/TaskCleanWorkspace.java index ae5590c..5f39a3c 100644 --- a/bundles/org.eclipse.tea.library.build/src/org/eclipse/tea/library/build/tasks/TaskCleanWorkspace.java +++ b/bundles/org.eclipse.tea.library.build/src/org/eclipse/tea/library/build/tasks/TaskCleanWorkspace.java @@ -21,6 +21,7 @@ import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.e4.core.di.annotations.Execute; import org.eclipse.tea.core.services.TaskProgressTracker; +import org.eclipse.tea.core.services.TaskProgressTracker.TaskProgressProvider; import org.eclipse.tea.library.build.model.WorkspaceData; /** @@ -29,6 +30,11 @@ @Named("Clean and refresh all projects") // Progress Monitor shows & as _ public class TaskCleanWorkspace { + @TaskProgressProvider + public int getWork() { + return ResourcesPlugin.getWorkspace().getRoot().getProjects().length; + } + @Execute public void run(TaskProgressTracker tracker) throws Exception { // refresh all projects