-
Notifications
You must be signed in to change notification settings - Fork 5.2k
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
fix(ext/ffi): Avoid keeping JsRuntimeState RefCell borrowed for event loop middleware calls #15116
fix(ext/ffi): Avoid keeping JsRuntimeState RefCell borrowed for event loop middleware calls #15116
Conversation
Is there some kind of test you can add, the change to borrows of op state is fine, but adding change to microtask policy seems sus |
I could add a test that shows the inversion in logging without the policy change. Is that the kind of test you're looking for? I guess the same test could also be done for synchronous callbacks (arguably it already exists but an explicit one is always explicit) to show that this change does not affect them as claimed. |
Sure, anything that exercises this code path is good 👍 |
I added two tests that verify that, with the current changes, the order of logging is as one might expect. Once the current round of tests is done I'll push a change to remove the microtask execution order to show that the order of logging becomes unexpected, and revert it later. EDIT: Here's the unexpected logging order failure:
So, as can be teased out from the output, we expect (right) the order of logs to be:
but it's actually (left)
So we can indeed see that the |
Hmmm... Seems like we get the unexpected logging order on ubuntu-20.04-xl... Gotta check tomorrow. |
Hmm... There's something odd with the release profile Linux build. I can reproduce the issue locally as well. It's as if the microtask policy setting wasn't working. I'll remove that part from this PR and introduce a separate PR to enable the panic fix to move forward. |
7528a37
to
1b3a91b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks
… loop middleware calls (#15116)
JsRuntimeState was mistakenly kept borrowed during event loop middleware calls for the purpose of getting a clone of the
Rc<RefCell<OpState>>
even though the cloning removes the need for the borrow to be kept. With this change thread safe FFI callbacks can now safely call ops that themselves access theJsRuntimeState
such as ops that create Promises etc.At the same time, FFI callbacks are changed to set the Isolate's MicrotasksPolicy to
Explicit
. This is done in order to allow thread safe callbacks to return before any microtasks queued by it get executed.As an example, imagine a thread safe callback using this JavaScript callback:
If any JS code were to call the
callback()
and immediately log "Called 'callback'" on return, the output would beFor an equivalent FFI library call to the C callback that is
callback
wrapped in anUnsafeCallback
the order of the two last lines would be reversed. The reason this is that the callback gets called from an empty stack, and as it finishes Deno would automatically run any pending microtasks. This is not how we want callbacks, especially thread safe callbacks, to work.Thread safe callbacks are already being polled from inside the
event_loop_middleware
, which probably (I honestly am not exactly sure) already run microtasks after it is done, or at least on the next event loop tick. Thus, having these callbacks themselves run microtasks is a bit redundant and most importantly it makes it hard for these callbacks to schedule asynchronous work without themselves being blocked by said "asynchronous work". We want thread safe callbacks to have the ability to call "synchronously" into Deno JS code and after that synchronous work is done to immediately return control (unblock) to the calling thread.Setting the MicrotasksPolicy could also be done only for thread safe callbacks. However, interrupt handlers being called on the main thread also suffer this same issue. They also suffer from other occasionally panic-inducing issues which make them quite inadvisable, but still this change is relevant for those as well. Normal synchronous callbacks are only affected this in the sense that they're now doing an unnecessary check on the policy value. Their scopes are not built on an empty stack, and as such they would not run pending microtasks anyway.