Skip to content

Commit 54f5b6d

Browse files
authored
User-interruptible evaluator jobs (#674)
* User-interruptible evaluator futures for Rascal. * Only allow cancelling interruptible futures. * Remove progress bars with nested jobs properly. * Replace generic wildcard. * User-interruptible evaluator futures for DSLs. * Document new methods. * Factor out `cancelProgress` to the monitor. * Use intermediate variable for thread-safety.
1 parent 6f968ef commit 54f5b6d

12 files changed

+115
-11
lines changed

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/BaseLanguageServer.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import org.eclipse.lsp4j.InitializeResult;
5252
import org.eclipse.lsp4j.ServerCapabilities;
5353
import org.eclipse.lsp4j.SetTraceParams;
54+
import org.eclipse.lsp4j.WorkDoneProgressCancelParams;
5455
import org.eclipse.lsp4j.jsonrpc.Launcher;
5556
import org.eclipse.lsp4j.jsonrpc.messages.Tuple.Two;
5657
import org.eclipse.lsp4j.services.LanguageClient;
@@ -366,5 +367,10 @@ public void connect(LanguageClient client) {
366367
public void registerVFS(VFSRegister registration) {
367368
VSCodeVFSClient.buildAndRegister(registration.getPort());
368369
}
370+
371+
@Override
372+
public void cancelProgress(WorkDoneProgressCancelParams params) {
373+
lspDocumentService.cancelProgress(params.getToken().getLeft());
374+
}
369375
}
370376
}

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/IBaseTextDocumentService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,5 @@ public interface IBaseTextDocumentService extends TextDocumentService {
5757
boolean isManagingFile(ISourceLocation file);
5858

5959
default void didRenameFiles(RenameFilesParams params, Set<ISourceLocation> workspaceFolders) {}
60+
void cancelProgress(String progressId);
6061
}

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/LSPIDEServices.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
*/
2727
package org.rascalmpl.vscode.lsp;
2828

29-
import java.io.IOException;
3029
import java.io.PrintWriter;
3130
import java.net.URI;
3231
import java.net.URISyntaxException;
@@ -196,4 +195,8 @@ public void warning(String message, ISourceLocation src) {
196195
monitor.warning(message, src);
197196
}
198197

198+
public IRascalMonitor getMonitor() {
199+
return monitor;
200+
}
201+
199202
}

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/RascalLSPMonitor.java

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,13 @@
2626
*/
2727
package org.rascalmpl.vscode.lsp;
2828

29+
import java.util.Map;
2930
import java.util.concurrent.CompletableFuture;
31+
import java.util.concurrent.ConcurrentHashMap;
3032
import java.util.function.Function;
33+
3134
import org.apache.logging.log4j.Logger;
35+
import org.checkerframework.checker.nullness.qual.Nullable;
3236
import org.eclipse.lsp4j.ProgressParams;
3337
import org.eclipse.lsp4j.WorkDoneProgressBegin;
3438
import org.eclipse.lsp4j.WorkDoneProgressCreateParams;
@@ -37,6 +41,8 @@
3741
import org.eclipse.lsp4j.WorkDoneProgressReport;
3842
import org.eclipse.lsp4j.jsonrpc.messages.Either;
3943
import org.rascalmpl.debug.IRascalMonitor;
44+
import org.rascalmpl.vscode.lsp.util.concurrent.InterruptibleFuture;
45+
4046
import io.usethesource.vallang.ISourceLocation;
4147

4248
/**
@@ -78,7 +84,7 @@ public LSPProgressBar(String rootName, String progressId) {
7884

7985
var msg = new WorkDoneProgressBegin();
8086
msg.setTitle(progressPrefix + rootName);
81-
msg.setCancellable(false);
87+
msg.setCancellable(activeFutures.containsKey(progressId));
8288
notifyProgress(msg);
8389
}
8490

@@ -90,7 +96,7 @@ private void notifyProgress(WorkDoneProgressNotification value) {
9096
public void progress(String message) {
9197
var msg = new WorkDoneProgressReport();
9298
msg.setMessage(message);
93-
msg.setCancellable(false);
99+
msg.setCancellable(activeFutures.containsKey(progressId));
94100
notifyProgress(msg);
95101
}
96102

@@ -126,6 +132,26 @@ private CompletableFuture<Void> retry(Throwable first, int retry, String id) {
126132
}
127133

128134
private final ThreadLocal<LSPProgressBar> activeProgress = new ThreadLocal<>();
135+
private final Map<String, InterruptibleFuture<? extends Object>> activeFutures = new ConcurrentHashMap<>();
136+
137+
/**
138+
* Register a running {@link InterruptibleFuture}, so it can be interrupted later.
139+
* Must be called from the same thread as the corresponding {@link jobStarted}.
140+
* @param name The task name, equal to the one used for {@link jobStarted}.
141+
* @param future The future doing the work.
142+
*/
143+
public void registerActiveFuture(String name, InterruptibleFuture<?> future) {
144+
activeFutures.put(generateProgressId(name), future);
145+
}
146+
147+
/**
148+
* Unregister an {@link InterruptibleFuture} that has finished.
149+
* Must be called from the same thread as the corresponding {@link jobEnded}.
150+
* @param name The task name, equal to the one used for {@link jobEnded}.
151+
*/
152+
public void unregisterActiveFuture(String name) {
153+
activeFutures.remove(generateProgressId(name));
154+
}
129155

130156
@Override
131157
public void jobStart(String name, int workShare, int totalWork) {
@@ -147,7 +173,6 @@ public void jobStart(String name, int workShare, int totalWork) {
147173
private static String generateProgressId(String topLevelName) {
148174
Thread t = Thread.currentThread();
149175
return "T" + Integer.toHexString(t.hashCode()) + "" + Long.toHexString(t.getId()) + "" + Integer.toHexString(System.identityHashCode(topLevelName));
150-
151176
}
152177

153178

@@ -206,4 +231,15 @@ public boolean jobIsCanceled(String name) {
206231
public void warning(String message, ISourceLocation src) {
207232
logger.warn("{} : {}", src, message);
208233
}
234+
235+
/**
236+
* Cancel the running {@link InterruptibleFuture} corresponding to a specific progress bar.
237+
* @param progressId The identifier of the progress bar.
238+
*/
239+
public void cancelProgress(String progressId) {
240+
var future = activeFutures.get(progressId);
241+
if (future != null) {
242+
future.interrupt();
243+
}
244+
}
209245
}

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ILanguageContributions.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ public static interface ScheduledCalculator extends BiFunction<ISourceLocation,
117117
* `references`, and `implementations` as parameter.
118118
*/
119119
public static interface OnDemandFocusToSetCalculator extends Function<IList, InterruptibleFuture<ISet>> { }
120+
121+
public void cancelProgress(String progressId);
120122
}
121123

122124
/*package*/ class EmptySummary {

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/InterpretedLanguageContributions.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ public class InterpretedLanguageContributions implements ILanguageContributions
107107
private final CompletableFuture<SummaryConfig> builderSummaryConfig;
108108
private final CompletableFuture<SummaryConfig> ondemandSummaryConfig;
109109
private final IBaseLanguageClient client;
110+
private final RascalLSPMonitor monitor;
110111

111112
public InterpretedLanguageContributions(LanguageParameter lang, IBaseTextDocumentService docService, BaseWorkspaceService workspaceService, IBaseLanguageClient client, ExecutorService exec) {
112113
this.client = client;
@@ -118,7 +119,7 @@ public InterpretedLanguageContributions(LanguageParameter lang, IBaseTextDocumen
118119
var pcfg = new PathConfig().parse(lang.getPathConfig());
119120
pcfg = EvaluatorUtil.addLSPSources(pcfg, false);
120121

121-
var monitor = new RascalLSPMonitor(client, LogManager.getLogger(logger.getName() + "[" + lang.getName() + "]"), lang.getName() + ": ");
122+
monitor = new RascalLSPMonitor(client, LogManager.getLogger(logger.getName() + "[" + lang.getName() + "]"), lang.getName() + ": ");
122123

123124
this.eval = EvaluatorUtil.makeFutureEvaluator(new LSPContext(exec, docService, workspaceService, client),
124125
"evaluator for " + lang.getName(), monitor, pcfg, lang.getMainModule());
@@ -460,4 +461,9 @@ private <T> InterruptibleFuture<T> execFunction(String name, CompletableFuture<@
460461
}),
461462
exec);
462463
}
464+
465+
@Override
466+
public void cancelProgress(String progressId) {
467+
monitor.cancelProgress(progressId);
468+
}
463469
}

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/LanguageContributionsMultiplexer.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,4 +369,9 @@ public CompletableFuture<SummaryConfig> getBuilderSummaryConfig() {
369369
public CompletableFuture<SummaryConfig> getOndemandSummaryConfig() {
370370
return ondemandSummaryConfig;
371371
}
372+
373+
@Override
374+
public void cancelProgress(String progressId) {
375+
contributions.forEach(klc -> klc.contrib.cancelProgress(progressId));
376+
}
372377
}

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ParametricTextDocumentService.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,4 +671,11 @@ public boolean isManagingFile(ISourceLocation file) {
671671
public TextDocumentState getDocumentState(ISourceLocation file) {
672672
return files.get(file.top());
673673
}
674+
675+
@Override
676+
public void cancelProgress(String progressId) {
677+
contributions.values().forEach(plex -> {
678+
plex.cancelProgress(progressId);
679+
});
680+
}
674681
}

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ParserOnlyContribution.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,4 +251,9 @@ public CompletableFuture<SummaryConfig> getOndemandSummaryConfig() {
251251
return CompletableFuture.completedFuture(SummaryConfig.FALSY);
252252
}
253253

254+
@Override
255+
public void cancelProgress(String progressId) {
256+
// empty, since this contribution does not have any running tasks nor a monitor
257+
}
258+
254259
}

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalLanguageServices.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,13 @@ public class RascalLanguageServices {
112112
private final IBaseLanguageClient client;
113113
private final RascalTextDocumentService rascalTextDocumentService;
114114
private final BaseWorkspaceService workspaceService;
115+
private final RascalLSPMonitor monitor;
115116

116117
public RascalLanguageServices(RascalTextDocumentService docService, BaseWorkspaceService workspaceService, IBaseLanguageClient client, ExecutorService exec) {
117118
this.client = client;
118119
this.exec = exec;
119120

120-
var monitor = new RascalLSPMonitor(client, logger);
121+
monitor = new RascalLSPMonitor(client, logger);
121122

122123
var pcfg = EvaluatorUtil.addLSPSources(new PathConfig(URIUtil.rootLocation("cwd")), true);
123124
var compilerPcfg = EvaluatorUtil.addRascalCompilerSources(pcfg);
@@ -411,4 +412,8 @@ public InterruptibleFuture<IList> codeActions(IList focus, PathConfig pcfg) {
411412
},
412413
VF.list(), exec, false, client);
413414
}
415+
416+
public void cancelProgress(String progressId) {
417+
monitor.cancelProgress(progressId);
418+
}
414419
}

0 commit comments

Comments
 (0)