Skip to content

Commit 4f0f5f6

Browse files
Share getThreadManager pool among RuntimeServerInstrument and Websocket emulation (#12528)
1 parent d090080 commit 4f0f5f6

File tree

14 files changed

+279
-79
lines changed

14 files changed

+279
-79
lines changed

MODULE.bazel.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.enso.interpreter.instrument;
2+
3+
import com.oracle.truffle.api.TruffleContext;
4+
import org.enso.interpreter.service.ExecutionService;
5+
6+
/**
7+
* Contains suppliers of services that provide interpreter specific functionality.
8+
*
9+
* @param executionService a service allowing externally-triggered code execution
10+
* @param contextManager a storage for active execution contexts
11+
* @param endpoint a message endpoint
12+
* @param truffleContext a context of a set of Truffle languages
13+
*/
14+
public record InterpreterContext(
15+
ExecutionService executionService,
16+
ExecutionContextManager contextManager,
17+
Endpoint endpoint,
18+
TruffleContext truffleContext) {}

engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/Handler.scala

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,12 @@ abstract class Handler {
3838
executionService: ExecutionService,
3939
truffleContext: TruffleContext
4040
): Unit = {
41-
val interpreterCtx =
42-
InterpreterContext(
43-
executionService,
44-
contextManager,
45-
endpoint,
46-
truffleContext
47-
)
41+
val interpreterCtx = new InterpreterContext(
42+
executionService,
43+
contextManager,
44+
endpoint,
45+
truffleContext
46+
)
4847
val commandProcessor = new CommandExecutionEngine(interpreterCtx)
4948
ctx = HandlersContext(
5049
executionService,

engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/InterpreterContext.scala

Lines changed: 0 additions & 20 deletions
This file was deleted.

engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/EpbContext.java

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
import com.oracle.truffle.api.source.Source;
99
import java.io.IOException;
1010
import java.net.URL;
11-
import java.util.concurrent.Executors;
11+
import java.util.Random;
12+
import java.util.concurrent.ScheduledExecutorService;
1213
import java.util.function.Function;
1314
import java.util.logging.Level;
1415
import org.enso.ydoc.polyfill.web.WebEnvironment;
@@ -28,6 +29,7 @@ final class EpbContext {
2829
private final TruffleLanguage.Env env;
2930
private @CompilationFinal TruffleContext innerContext;
3031
private final TruffleLogger log;
32+
private final Random delayer = new Random();
3133
private boolean polyfillInitialized;
3234

3335
/**
@@ -54,6 +56,7 @@ public void initialize(String preInitializeLanguages) {
5456
env.newInnerContextBuilder()
5557
.initializeCreatorContext(true)
5658
.inheritAllAccess(true)
59+
.threadAccessDeniedHandler(this::handleMultiAccess)
5760
.config(INNER_OPTION, "yes")
5861
.build();
5962
}
@@ -87,7 +90,9 @@ public void log(Level level, String msg, Object... args) {
8790
final void initializePolyfill(Node node, TruffleContext ctx) {
8891
if (!polyfillInitialized) {
8992
polyfillInitialized = true;
90-
var exec = Executors.newSingleThreadScheduledExecutor();
93+
var ensoLanguage = getEnv().getInternalLanguages().get("enso");
94+
var exec = getEnv().lookup(ensoLanguage, ScheduledExecutorService.class);
95+
assert exec != null : "Need executor from " + ensoLanguage;
9196
Function<URL, Value> eval =
9297
(url) -> {
9398
try {
@@ -101,4 +106,43 @@ final void initializePolyfill(Node node, TruffleContext ctx) {
101106
WebEnvironment.initialize(eval, exec);
102107
}
103108
}
109+
110+
final void handleMultiAccess(String msg) {
111+
try {
112+
var ms = delayer.nextInt(10, 1000);
113+
// dump stack when assertions on
114+
assert dumpStack(ms);
115+
Thread.sleep(ms);
116+
} catch (InterruptedException ex) {
117+
Thread.currentThread().interrupt();
118+
}
119+
}
120+
121+
private boolean dumpStack(int ms) {
122+
var sb = new StringBuilder("Polyglot access failed. Waiting " + ms + " ms. Threaddump:\n");
123+
var traces = Thread.getAllStackTraces();
124+
for (var entry : traces.entrySet()) {
125+
var thread = new StringBuilder();
126+
thread.append(entry.getKey().getName()).append("\n");
127+
var keep = false;
128+
for (var e : entry.getValue()) {
129+
keep |= e.getClassName().contains("com.oracle.truffle");
130+
thread
131+
.append(" ")
132+
.append(e.getClassName())
133+
.append(".")
134+
.append(e.getMethodName())
135+
.append("(")
136+
.append(e.getFileName())
137+
.append(":")
138+
.append(e.getLineNumber())
139+
.append(")\n");
140+
}
141+
if (keep) {
142+
sb.append(thread.toString());
143+
}
144+
}
145+
log(Level.WARNING, sb.toString());
146+
return true;
147+
}
104148
}

engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.time.ZoneId;
2121
import java.util.List;
2222
import java.util.Objects;
23+
import java.util.concurrent.ScheduledExecutorService;
2324
import java.util.logging.Level;
2425
import org.enso.common.LanguageInfo;
2526
import org.enso.common.RuntimeOptions;
@@ -94,7 +95,12 @@
9495
contextPolicy = TruffleLanguage.ContextPolicy.EXCLUSIVE,
9596
dependentLanguages = {"epb"},
9697
fileTypeDetectors = FileDetector.class,
97-
services = {Timer.class, NotificationHandler.Forwarder.class, LockManager.class})
98+
services = {
99+
Timer.class,
100+
NotificationHandler.Forwarder.class,
101+
LockManager.class,
102+
ScheduledExecutorService.class
103+
})
98104
@ProvidedTags({
99105
DebuggerTags.AlwaysHalt.class,
100106
StandardTags.CallTag.class,
@@ -170,6 +176,7 @@ protected EnsoContext createContext(Env env) {
170176
new EnsoContext(
171177
this, getLanguageHome(), env, notificationHandler, lockManager, distributionManager);
172178

179+
env.registerService(context.getThreadManager());
173180
return context;
174181
}
175182

engine/runtime/src/main/java/org/enso/interpreter/node/EnsoRootNode.java

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
package org.enso.interpreter.node;
22

3-
import com.oracle.truffle.api.TruffleLogger;
43
import com.oracle.truffle.api.frame.FrameDescriptor;
54
import com.oracle.truffle.api.frame.FrameSlotKind;
65
import com.oracle.truffle.api.nodes.NodeInfo;
76
import com.oracle.truffle.api.nodes.RootNode;
87
import com.oracle.truffle.api.source.Source;
98
import com.oracle.truffle.api.source.SourceSection;
109
import java.util.Objects;
11-
import java.util.function.BiFunction;
12-
import java.util.logging.Level;
13-
import org.enso.common.LanguageInfo;
1410
import org.enso.compiler.context.LocalScope;
1511
import org.enso.interpreter.EnsoLanguage;
1612
import org.enso.interpreter.runtime.EnsoContext;
@@ -20,8 +16,6 @@
2016
/** A common base class for all kinds of root node in Enso. */
2117
@NodeInfo(shortName = "Root", description = "A root node for Enso computations")
2218
public abstract class EnsoRootNode extends RootNode {
23-
private static final TruffleLogger LOGGER = TruffleLogger.getLogger(LanguageInfo.ID);
24-
2519
private final String name;
2620
private final int sourceStartIndex;
2721
private final int sourceLength;
@@ -44,7 +38,7 @@ protected EnsoRootNode(
4438
ModuleScope moduleScope,
4539
String name,
4640
SourceSection sourceSection) {
47-
super(language, buildFrameDescriptor(name, localScope, LOGGER));
41+
super(language, buildFrameDescriptor(name, localScope));
4842
Objects.requireNonNull(language);
4943
Objects.requireNonNull(localScope);
5044
Objects.requireNonNull(moduleScope);
@@ -67,19 +61,11 @@ protected EnsoRootNode(
6761
*
6862
* @return {@link FrameDescriptor} built from the variable definitions in the local localScope.
6963
*/
70-
private static FrameDescriptor buildFrameDescriptor(
71-
String name, LocalScope localScope, TruffleLogger log) {
64+
private static FrameDescriptor buildFrameDescriptor(String name, LocalScope localScope) {
7265
var descriptorBuilder = FrameDescriptor.newBuilder();
7366
descriptorBuilder.addSlot(FrameSlotKind.Object, LocalScope.monadicStateSlotName(), null);
7467

75-
BiFunction<String, Object[], Void> logFnOrNull =
76-
log.isLoggable(Level.FINE)
77-
? (msg, args) -> {
78-
log.log(Level.FINE, msg, args);
79-
return null;
80-
}
81-
: null;
82-
var allDefs = localScope.allSymbols(name, logFnOrNull);
68+
var allDefs = localScope.allSymbols(name, null);
8369
for (var definition : allDefs) {
8470
descriptorBuilder.addSlot(FrameSlotKind.Illegal, definition, null);
8571
}

engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ public boolean isGlobalSuggestionsEnabled() {
792792

793793
/** The job parallelism or 1 */
794794
public int getJobParallelism() {
795-
int n = getOption(RuntimeOptions.JOB_PARALLELISM_KEY);
795+
var n = getOption(RuntimeOptions.JOB_PARALLELISM_KEY);
796796
return Math.max(1, n);
797797
}
798798

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package org.enso.interpreter.runtime;
2+
3+
import java.util.Collection;
4+
import java.util.List;
5+
import java.util.concurrent.Callable;
6+
import java.util.concurrent.ExecutionException;
7+
import java.util.concurrent.Future;
8+
import java.util.concurrent.ScheduledExecutorService;
9+
import java.util.concurrent.ScheduledFuture;
10+
import java.util.concurrent.TimeUnit;
11+
import java.util.concurrent.TimeoutException;
12+
13+
abstract class GuestCodeExecutor implements ScheduledExecutorService {
14+
final ScheduledExecutorService guestCode;
15+
16+
GuestCodeExecutor(ScheduledExecutorService delegate) {
17+
this.guestCode = delegate;
18+
}
19+
20+
protected abstract Runnable wrap(Runnable r);
21+
22+
protected abstract <V> Callable<V> wrap(Callable<V> c);
23+
24+
private <T> List<Callable<T>> wrap(Collection<? extends Callable<T>> tasks) {
25+
return tasks.stream().map(this::wrap).toList();
26+
}
27+
28+
@Override
29+
public final ScheduledFuture<?> schedule(Runnable r, long l, TimeUnit tu) {
30+
return guestCode.schedule(wrap(r), l, tu);
31+
}
32+
33+
@Override
34+
public final <V> ScheduledFuture<V> schedule(Callable<V> clbl, long l, TimeUnit tu) {
35+
return guestCode.schedule(wrap(clbl), l, tu);
36+
}
37+
38+
@Override
39+
public final ScheduledFuture<?> scheduleAtFixedRate(Runnable r, long l, long l1, TimeUnit tu) {
40+
return guestCode.scheduleAtFixedRate(wrap(r), l, l1, tu);
41+
}
42+
43+
@Override
44+
public final ScheduledFuture<?> scheduleWithFixedDelay(Runnable r, long l, long l1, TimeUnit tu) {
45+
return guestCode.scheduleWithFixedDelay(wrap(r), l, l1, tu);
46+
}
47+
48+
@Override
49+
public final List<Runnable> shutdownNow() {
50+
return guestCode.shutdownNow();
51+
}
52+
53+
@Override
54+
public final boolean isShutdown() {
55+
return guestCode.isShutdown();
56+
}
57+
58+
@Override
59+
public final boolean isTerminated() {
60+
return guestCode.isTerminated();
61+
}
62+
63+
@Override
64+
public final boolean awaitTermination(long l, TimeUnit tu) throws InterruptedException {
65+
return guestCode.awaitTermination(l, tu);
66+
}
67+
68+
@Override
69+
public final <T> Future<T> submit(Callable<T> clbl) {
70+
return guestCode.submit(wrap(clbl));
71+
}
72+
73+
@Override
74+
public final <T> Future<T> submit(Runnable r, T t) {
75+
return guestCode.submit(wrap(r), t);
76+
}
77+
78+
@Override
79+
public final Future<?> submit(Runnable r) {
80+
return guestCode.submit(r);
81+
}
82+
83+
@Override
84+
public final <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
85+
throws InterruptedException {
86+
return guestCode.invokeAll(wrap(tasks));
87+
}
88+
89+
@Override
90+
public final <T> List<Future<T>> invokeAll(
91+
Collection<? extends Callable<T>> clctn, long l, TimeUnit tu) throws InterruptedException {
92+
return guestCode.invokeAll(wrap(clctn), l, tu);
93+
}
94+
95+
@Override
96+
public final <T> T invokeAny(Collection<? extends Callable<T>> tasks)
97+
throws InterruptedException, ExecutionException {
98+
return guestCode.invokeAny(wrap(tasks));
99+
}
100+
101+
@Override
102+
public final <T> T invokeAny(Collection<? extends Callable<T>> clctn, long l, TimeUnit tu)
103+
throws InterruptedException, ExecutionException, TimeoutException {
104+
return guestCode.invokeAny(wrap(clctn), l, tu);
105+
}
106+
107+
@Override
108+
public final void execute(Runnable command) {
109+
guestCode.execute(wrap(command));
110+
}
111+
}

engine/runtime/src/main/java/org/enso/interpreter/runtime/ThreadExecutors.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ ExecutorService newCachedThreadPool(
3939
return s;
4040
}
4141

42-
ExecutorService newFixedThreadPool(int cnt, String name, boolean systemThread) {
43-
var s = Executors.newFixedThreadPool(cnt, new Factory(name, systemThread));
42+
ScheduledExecutorService newScheduledThreadPool(int cnt, String name, boolean systemThread) {
43+
var s = Executors.newScheduledThreadPool(cnt, new Factory(name, systemThread));
4444
pools.put(s, name);
4545
return s;
4646
}

0 commit comments

Comments
 (0)