Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removing need for asynchronous thread to execute ResourceManager finalizers #6335

Merged
merged 8 commits into from
Apr 20, 2023

Conversation

JaroslavTulach
Copy link
Member

@JaroslavTulach JaroslavTulach commented Apr 18, 2023

Pull Request Description

While Enso runs single-threaded, its ResourceManager required additional asynchronous thread to execute its "finalizers". What has been necessary back then is no longer needed since GraalVM 21.1. GraalVM now provides support for submitting ThreadLocalAction that gets then picked and executed via TruffleSafepoint locations. This PR uses such mechanism to "inject" finalizer execution into already running Enso evaluation thread.

Requiring more than one thread has complicated Enso's co-existence with other Truffle language. For example Graal.js is strictly singlethreaded and used to refuse (simple) co-existence with Enso. By allowing Enso to perform all its actions in a single thread, the synergy with Graal.js becomes better.

Checklist

Please ensure that the following checklist has been satisfied before submitting the PR:

  • All code follows the
    Scala,
    Java,
    style guides
  • Finalize on Context closing
  • All code has been tested:
    • Unit tests continue to pass

Copy link
Member Author

@JaroslavTulach JaroslavTulach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Being able to run Enso without the allowCreateThread permission was something I always wanted to fix. I am glad I got it working.

@@ -9,7 +9,7 @@
final class InliningBuiltinsOutNode extends Node {

long execute(VirtualFrame frame, long a, long b) {
Assert.assertNotNull("VirtualFrame is always provided " + frame);
Assert.assertNotNull("VirtualFrame is always provided", frame);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unreleated. Addresses #6304 (comment)

@@ -124,7 +129,7 @@ public ManagedResource register(Object object, Object function) {
}
if (workerThread == null || !workerThread.isAlive()) {
worker.setKilled(false);
workerThread = context.getEnvironment().createThread(worker);
workerThread = context.getEnvironment().createSystemThread(worker);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need thread to read "finalizable" references from ReferenceQueue - however it can be "system thread" - a thread that is not allowed to execute any guest language code.

@Override
protected void perform(ThreadLocalAction.Access access) {
var tmp = futureToCancel.getAndSet(null);
if (tmp == null) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than directly executing the finalizer we schedule a "safe point action". As soon as it is picked up by some Enso executing thread, we cancel any further executions of the action and execute the "finalizer".

@@ -113,6 +113,7 @@ class InterpreterContext(
.newBuilder(LanguageInfo.ID)
.allowExperimentalOptions(true)
.allowAllAccess(true)
.allowCreateThread(false)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes in this PR remove the need for multiple thread. All runtime project tests can now run with single thread access only.

if (round % 10 == 0) {
forceGC();
val res = eval("main a b = a * b").execute(7, 6)
assertResult(42)(res.asInt)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, to execute the "finalizer" some Truffle code must be executing. It wasn't in case of RuntimeManagementTest. To mitigate that, I am submitting some simple computation here. As soon as the computation reaches TruffleSafepoint, the "finalizers" are executed and the test can finish.

@JaroslavTulach JaroslavTulach force-pushed the wip/jtulach/SynchronousResourceManager branch from 378a5f5 to 4128784 Compare April 18, 2023 13:37
Copy link
Contributor

@kustosz kustosz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice change! I left one question/comment inline, because this code makes an assumption I'm not 100% sure is correct.

@JaroslavTulach JaroslavTulach added the CI: Ready to merge This PR is eligible for automatic merge label Apr 19, 2023
@mwu-tow mwu-tow merged commit e47eb49 into develop Apr 20, 2023
@mwu-tow mwu-tow deleted the wip/jtulach/SynchronousResourceManager branch April 20, 2023 11:33
@enso-bot
Copy link

enso-bot bot commented Apr 21, 2023

Jaroslav Tulach reports a new STANDUP for yesterday (2023-04-20):

Progress: - finalizers: #6335

  • meetings It should be finished by 2023-04-21.

Next Day: <| functions

@hubertp hubertp mentioned this pull request Apr 27, 2023
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: Ready to merge This PR is eligible for automatic merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants