Skip to content

Commit 47cfa96

Browse files
committed
fix: refactor engine creation in JSPlugin to use a dedicated createEngine method in PolyglotThreadUtils to avoid deadlock issues
See #663
1 parent 3cd96de commit 47cfa96

2 files changed

Lines changed: 23 additions & 3 deletions

File tree

polyglot/src/main/java/org/restheart/polyglot/JSPlugin.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,12 @@ public abstract class JSPlugin {
3939

4040
static {
4141
try {
42-
// Engine.create() touches Truffle thread locals, must run on a platform thread (see PolyglotThreadUtils)
43-
// and needs PluginsClassloader so ServiceLoader can find js-language's TruffleLanguageProvider
44-
engine = PolyglotThreadUtils.onPlatformThread(() -> PolyglotClassloaderHelper.withPluginsClassloaderResult(Engine::create));
42+
// Must be a plain method reference to a method NOT declared here: a lambda
43+
// body written inside this static initializer would become a private
44+
// synthetic method of JSPlugin, and invoking it from the platform thread
45+
// would then require JSPlugin's own <clinit> to finish -- which is exactly
46+
// what's blocked waiting for this platform thread, causing a deadlock.
47+
engine = PolyglotThreadUtils.onPlatformThread(PolyglotThreadUtils::createEngine);
4548
} catch (Exception e) {
4649
throw new IllegalStateException("Error creating polyglot Engine", e);
4750
}

polyglot/src/main/java/org/restheart/polyglot/PolyglotThreadUtils.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@
2020
*/
2121
package org.restheart.polyglot;
2222

23+
import java.io.IOException;
2324
import java.util.concurrent.Callable;
2425
import java.util.concurrent.ExecutionException;
2526
import java.util.concurrent.ExecutorService;
2627
import java.util.concurrent.Executors;
2728

29+
import org.graalvm.polyglot.Engine;
30+
2831
/**
2932
* Runs GraalVM polyglot Context creation, enter/leave and eval on a platform thread.
3033
*
@@ -47,6 +50,20 @@ private PolyglotThreadUtils() {}
4750
* @return the result of the task
4851
* @throws Exception if the task throws an exception
4952
*/
53+
/**
54+
* Creates a polyglot Engine with the PluginsClassloader as context classloader.
55+
*
56+
* <p>Declared here (not as a lambda body inside JSPlugin's static initializer)
57+
* so that invoking it from a platform thread never needs to wait on JSPlugin's
58+
* own class-initialization monitor, which would deadlock since JSPlugin's
59+
* &lt;clinit&gt; is the one submitting this task and blocking on its result.</p>
60+
*
61+
* @return a newly created Engine
62+
*/
63+
public static Engine createEngine() throws IOException {
64+
return PolyglotClassloaderHelper.withPluginsClassloaderResult(Engine::create);
65+
}
66+
5067
public static <T> T onPlatformThread(Callable<T> task) throws Exception {
5168
try {
5269
return PLATFORM_EXECUTOR.submit(task).get();

0 commit comments

Comments
 (0)