diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/ThreadManager.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/ThreadManager.java index 1753299bf0d..e1c426ff04c 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/ThreadManager.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/ThreadManager.java @@ -6,6 +6,7 @@ import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.nodes.InvalidAssumptionException; import org.enso.interpreter.runtime.control.ThreadInterruptedException; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Phaser; import java.util.concurrent.locks.ReentrantLock; @@ -23,6 +24,7 @@ public class ThreadManager { private final ReentrantLock lock = new ReentrantLock(); private volatile boolean safepoint = false; + private final ConcurrentHashMap interruptFlags = new ConcurrentHashMap<>(); /** * Registers the current thread as running guest code. @@ -35,6 +37,7 @@ public class ThreadManager { */ public void enter() { safepointPhaser.register(); + interruptFlags.put(Thread.currentThread(), false); } /** @@ -44,6 +47,7 @@ public class ThreadManager { */ public void leave() { safepointPhaser.arriveAndDeregister(); + interruptFlags.remove(Thread.currentThread()); } /** Called from the interpreter to periodically perform a safepoint check. */ @@ -51,7 +55,8 @@ public class ThreadManager { if (safepoint) { CompilerDirectives.transferToInterpreter(); safepointPhaser.arriveAndAwaitAdvance(); - if (Thread.interrupted()) { + if (interruptFlags.get(Thread.currentThread())) { + interruptFlags.put(Thread.currentThread(), false); throw new ThreadInterruptedException(); } } @@ -59,7 +64,7 @@ public class ThreadManager { /** * Forces all threads managed by this system to halt at the next safepoint (i.e. a {@link #poll()} - * call) and throw an exception if they were interrupted. + * call) and throw a {@link ThreadInterruptedException}. * *

This method is blocking, does not return until the last managed thread reports at a * safepoint. @@ -67,9 +72,10 @@ public class ThreadManager { *

This method may not be called from a thread that is itself managed by this system, as doing * so may result in a deadlock. */ - public void checkInterrupts() { + public void interruptThreads() { lock.lock(); try { + interruptFlags.replaceAll((t, b) -> true); enter(); try { safepoint = true; diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/execution/JobExecutionEngine.scala b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/execution/JobExecutionEngine.scala index 7f4adc56134..94a3dfbc6d3 100644 --- a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/execution/JobExecutionEngine.scala +++ b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/execution/JobExecutionEngine.scala @@ -91,7 +91,7 @@ class JobExecutionEngine( runningJob.future.cancel(runningJob.job.mayInterruptIfRunning) } runtimeContext.executionService.getContext.getThreadManager - .checkInterrupts() + .interruptThreads() } /** @inheritdoc */ @@ -104,7 +104,7 @@ class JobExecutionEngine( } } runtimeContext.executionService.getContext.getThreadManager - .checkInterrupts() + .interruptThreads() } /** @inheritdoc */ @@ -112,7 +112,7 @@ class JobExecutionEngine( val allJobs = runningJobsRef.get() allJobs.foreach(_.future.cancel(true)) runtimeContext.executionService.getContext.getThreadManager - .checkInterrupts() + .interruptThreads() jobExecutor.shutdownNow() } diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/ExecuteJob.scala b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/ExecuteJob.scala index c233019a34f..1ec437e511d 100644 --- a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/ExecuteJob.scala +++ b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/ExecuteJob.scala @@ -19,7 +19,13 @@ class ExecuteJob( stack: List[InstrumentFrame], updatedVisualisations: Seq[UUID], sendMethodCallUpdates: Boolean -) extends Job[Unit](List(contextId), true, true) +) extends Job[Unit]( + List(contextId), + isCancellable = true, + // TODO[MK]: make this interruptible when https://github.com/oracle/graal/issues/3273 + // is resolved + mayInterruptIfRunning = false + ) with ProgramExecutionSupport { def this(exe: Executable) = diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/RuntimeManagementTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/RuntimeManagementTest.scala index ccae3beecd7..36873e8a1e1 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/RuntimeManagementTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/RuntimeManagementTest.scala @@ -51,8 +51,7 @@ class RuntimeManagementTest extends InterpreterTest { reportedCount += consumeOut.length } val expectedOut = List.fill(n)("Interrupted.") - threads.foreach(_.interrupt()) - langCtx.getThreadManager.checkInterrupts() + langCtx.getThreadManager.interruptThreads() threads.foreach(_.join()) consumeOut shouldEqual expectedOut threads.forall(!_.isAlive) shouldBe true diff --git a/table/src/main/java/org/enso/table/data/index/HashIndex.java b/table/src/main/java/org/enso/table/data/index/HashIndex.java index 8f8d709e516..4bba30a25ef 100644 --- a/table/src/main/java/org/enso/table/data/index/HashIndex.java +++ b/table/src/main/java/org/enso/table/data/index/HashIndex.java @@ -44,7 +44,7 @@ public class HashIndex extends Index { @Override public String ilocString(int loc) { - return iloc(loc).toString(); + return String.valueOf(iloc(loc)); } @Override