-
Notifications
You must be signed in to change notification settings - Fork 29.9k
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
src: prepare platform for upstream V8 changes #15428
Conversation
Oooo big +1.... still have to review but this is definitely good to see. |
src/node.cc
Outdated
@@ -1352,7 +1352,8 @@ class InternalCallbackScope { | |||
public: | |||
InternalCallbackScope(Environment* env, | |||
Local<Object> object, | |||
const async_context& asyncContext); | |||
const async_context& asyncContext, | |||
bool allow_empty_object = false); |
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.
Perhaps make this a flag rather than a bool so it's more self-describing in line... e.g.
InternalCallbackScope cb_scope(&env, Local<Object>(), { 0, 0 }, kAllowEmpty);
Or some such...
src/node.cc
Outdated
@@ -4747,9 +4754,17 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data, | |||
do { | |||
uv_run(env.event_loop(), UV_RUN_DEFAULT); | |||
|
|||
{ | |||
InternalCallbackScope cb_scope(&env, Local<Object>(), { 0, 0 }, true); |
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.
What exactly does this scope provide? Should it also be added to the places in node_platform.cc
that invoke foreground tasks?
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.
What exactly does this scope provide?
Calling async_hooks hooks + running the microtask queue and/or nextTicks
Should it also be added to the places in
node_platform.cc
that invoke foreground tasks?
Hm – I think so, yes. Thanks for pointing that out.
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.
FWIW, it would be exceedingly helpful if we had actual documentation for how and when things like InternalCallbackScope
are to be used.
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.
@jasnell I agree
@matthewloring I will add this to the other places but that gets a bit tricky, because the platform only sees Isolate
s but looking up the proper Environment
for a task is not trivial.
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.
Nice!
a7e7fff
to
f078c66
Compare
@jasnell @matthewloring Done, updated! @fhinkel This has changed a bit, do you want to take another look? What we probably ought to get implemented on top of this change is actual async_hooks trackability for platform tasks, but I think that’s out of the scope of this PR + might require a bit more deliberation and/or chatting with the V8 team. |
src/node.cc
Outdated
@@ -4747,9 +4729,16 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data, | |||
do { | |||
uv_run(env.event_loop(), UV_RUN_DEFAULT); | |||
|
|||
{ | |||
v8_platform.DrainVMTasks(); | |||
} |
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.
Unnecessary scoping?
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.
Thanks, yes, it’s an editing leftover.
src/node_platform.cc
Outdated
bool TaskQueue<T>::HasPending() { | ||
Mutex::ScopedLock scoped_lock(lock_); | ||
return !task_queue_.empty(); | ||
} |
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.
This method is intrinsically race-y. Maybe change FlushForegroundTasksInternal()
to return true
when foreground tasks were dispatched and update the loop in DrainBackgroundTasks()
to something like this?
while (FlushForegroundTasksInternal())
background_tasks_.BlockingDrain();
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.
@bnoordhuis Fwiw, I don’t think the current code is actually race-y since, at least currently, only background tasks would enqueue new foreground tasks from another thread.
I like your suggestion, and d5bd7c55c19d0d4aee5a9511b9e6df1374d0644d should implement it correctly, but I think it doesn’t actually change the semantics here.
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.
If you mean it's not race-y now because it's always called from the right thread, yes, you're right. What I mean is that the method itself is race-y by design.
a60d5ee
to
f311ed9
Compare
src/node_internals.h
Outdated
@@ -294,8 +294,35 @@ v8::MaybeLocal<v8::Value> InternalMakeCallback( | |||
v8::Local<v8::Value> argv[], | |||
async_context asyncContext); | |||
|
|||
class InternalCallbackScope { | |||
public: | |||
enum ResourceExpectation { kRequireResource, kAllowEmptyResource }; |
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.
Can you add some code comments here that describe briefly the difference between these flags
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.
@jasnell done + rebased
V8 platform tasks may schedule other tasks (both background and foreground), and may perform asynchronous operations like resolving Promises. To address that: - Run the task queue drain call inside a callback scope. This makes sure asynchronous operations inside it, like resolving promises, lead to the microtask queue and any subsequent operations not being silently forgotten. - Move the task queue drain call before `EmitBeforeExit()` and only run `EmitBeforeExit()` if there is no new event loop work. - Account for possible new foreground tasks scheduled by background tasks in `DrainBackgroundTasks()`.
f311ed9
to
83c3e74
Compare
src/node_platform.h
Outdated
@@ -39,7 +39,8 @@ class NodePlatform : public v8::Platform { | |||
virtual ~NodePlatform() {} | |||
|
|||
void DrainBackgroundTasks(); | |||
void FlushForegroundTasksInternal(); | |||
// returns true iff work was dispatched or executed |
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.
Can you capitalize and punctuate the comment?
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.
Sure, done!
Landed in f27b5e4 |
V8 platform tasks may schedule other tasks (both background and foreground), and may perform asynchronous operations like resolving Promises. To address that: - Run the task queue drain call inside a callback scope. This makes sure asynchronous operations inside it, like resolving promises, lead to the microtask queue and any subsequent operations not being silently forgotten. - Move the task queue drain call before `EmitBeforeExit()` and only run `EmitBeforeExit()` if there is no new event loop work. - Account for possible new foreground tasks scheduled by background tasks in `DrainBackgroundTasks()`. PR-URL: #15428 Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Matthew Loring <[email protected]>
V8 platform tasks may schedule other tasks (both background and foreground), and may perform asynchronous operations like resolving Promises. To address that: - Run the task queue drain call inside a callback scope. This makes sure asynchronous operations inside it, like resolving promises, lead to the microtask queue and any subsequent operations not being silently forgotten. - Move the task queue drain call before `EmitBeforeExit()` and only run `EmitBeforeExit()` if there is no new event loop work. - Account for possible new foreground tasks scheduled by background tasks in `DrainBackgroundTasks()`. PR-URL: nodejs/node#15428 Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Matthew Loring <[email protected]>
V8 platform tasks may schedule other tasks (both background and foreground), and may perform asynchronous operations like resolving Promises. To address that: - Run the task queue drain call inside a callback scope. This makes sure asynchronous operations inside it, like resolving promises, lead to the microtask queue and any subsequent operations not being silently forgotten. - Move the task queue drain call before `EmitBeforeExit()` and only run `EmitBeforeExit()` if there is no new event loop work. - Account for possible new foreground tasks scheduled by background tasks in `DrainBackgroundTasks()`. PR-URL: nodejs/node#15428 Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Matthew Loring <[email protected]>
V8 platform tasks may schedule other tasks (both background and foreground), and may perform asynchronous operations like resolving Promises. To address that: - Run the task queue drain call inside a callback scope. This makes sure asynchronous operations inside it, like resolving promises, lead to the microtask queue and any subsequent operations not being silently forgotten. - Move the task queue drain call before `EmitBeforeExit()` and only run `EmitBeforeExit()` if there is no new event loop work. - Account for possible new foreground tasks scheduled by background tasks in `DrainBackgroundTasks()`. PR-URL: nodejs#15428 Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Matthew Loring <[email protected]>
@MylesBorins I think we should backport this, yes. Like @TimothyGu said, it should come with #15639 – I’ll open a backport PR once both have landed. |
Same for #15691 as well – it still makes sense to me to backport all of these 3 together. |
nodejs#15428 was supposed to account for upcoming changes in V8 upstream, but while addressing review comments a bug was introduced; `DrainBackgroundTasks()` should always at least perform one blocking drain on the background task queue. PR-URL: nodejs#15639 Refs: nodejs#15428 Refs: f27b5e4 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
Make the context check in `MakeCallback` match what the comment says (and what actually makes sense). Fixes: nodejs#15672 Ref: nodejs#15428 Ref: f27b5e4
nodejs/node#15428 was supposed to account for upcoming changes in V8 upstream, but while addressing review comments a bug was introduced; `DrainBackgroundTasks()` should always at least perform one blocking drain on the background task queue. PR-URL: nodejs/node#15639 Refs: nodejs/node#15428 Refs: f27b5e4bdaafc73a830a0451ee3c641b8bcd08fe Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
Make the context check in `MakeCallback` match what the comment says (and what actually makes sense). PR-URL: #15691 Fixes: #15672 Ref: #15428 Ref: f27b5e4 Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Eugene Ostroukhov <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Timothy Gu <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
Make the context check in `MakeCallback` match what the comment says (and what actually makes sense). PR-URL: nodejs/node#15691 Fixes: nodejs/node#15672 Ref: nodejs/node#15428 Ref: f27b5e4bdaafc73a830a0451ee3c641b8bcd08fe Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Eugene Ostroukhov <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Timothy Gu <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
V8 platform tasks may schedule other tasks (both background and foreground), and may perform asynchronous operations like resolving Promises. To address that: - Run the task queue drain call inside a callback scope. This makes sure asynchronous operations inside it, like resolving promises, lead to the microtask queue and any subsequent operations not being silently forgotten. - Move the task queue drain call before `EmitBeforeExit()` and only run `EmitBeforeExit()` if there is no new event loop work. - Account for possible new foreground tasks scheduled by background tasks in `DrainBackgroundTasks()`. PR-URL: nodejs#15428 Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Matthew Loring <[email protected]>
nodejs#15428 was supposed to account for upcoming changes in V8 upstream, but while addressing review comments a bug was introduced; `DrainBackgroundTasks()` should always at least perform one blocking drain on the background task queue. PR-URL: nodejs#15639 Refs: nodejs#15428 Refs: f27b5e4 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
Make the context check in `MakeCallback` match what the comment says (and what actually makes sense). PR-URL: nodejs#15691 Fixes: nodejs#15672 Ref: nodejs#15428 Ref: f27b5e4 Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Eugene Ostroukhov <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Timothy Gu <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
V8 platform tasks may schedule other tasks (both background and foreground), and may perform asynchronous operations like resolving Promises. To address that: - Run the task queue drain call inside a callback scope. This makes sure asynchronous operations inside it, like resolving promises, lead to the microtask queue and any subsequent operations not being silently forgotten. - Move the task queue drain call before `EmitBeforeExit()` and only run `EmitBeforeExit()` if there is no new event loop work. - Account for possible new foreground tasks scheduled by background tasks in `DrainBackgroundTasks()`. PR-URL: #15428 Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Matthew Loring <[email protected]>
#15428 was supposed to account for upcoming changes in V8 upstream, but while addressing review comments a bug was introduced; `DrainBackgroundTasks()` should always at least perform one blocking drain on the background task queue. PR-URL: #15639 Refs: #15428 Refs: f27b5e4 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
Make the context check in `MakeCallback` match what the comment says (and what actually makes sense). PR-URL: #15691 Fixes: #15672 Ref: #15428 Ref: f27b5e4 Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Eugene Ostroukhov <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Timothy Gu <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
V8 platform tasks may schedule other tasks (both background and foreground), and may perform asynchronous operations like resolving Promises. To address that: - Run the task queue drain call inside a callback scope. This makes sure asynchronous operations inside it, like resolving promises, lead to the microtask queue and any subsequent operations not being silently forgotten. - Move the task queue drain call before `EmitBeforeExit()` and only run `EmitBeforeExit()` if there is no new event loop work. - Account for possible new foreground tasks scheduled by background tasks in `DrainBackgroundTasks()`. PR-URL: #15428 Reviewed-By: Franziska Hinkelmann <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Matthew Loring <[email protected]>
#15428 was supposed to account for upcoming changes in V8 upstream, but while addressing review comments a bug was introduced; `DrainBackgroundTasks()` should always at least perform one blocking drain on the background task queue. PR-URL: #15639 Refs: #15428 Refs: f27b5e4 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
Make the context check in `MakeCallback` match what the comment says (and what actually makes sense). PR-URL: #15691 Fixes: #15672 Ref: #15428 Ref: f27b5e4 Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Eugene Ostroukhov <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Timothy Gu <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
This does not land cleanly in v6.x LTS. Please feel free to manually backport by following the guide. Please also feel free to replace do-not-land if it is being backported |
V8 platform tasks may schedule other tasks (both background and foreground), and may perform asynchronous operations like resolving Promises.
To address that:
EmitBeforeExit()
and only runEmitBeforeExit()
if there is no new event loop work.DrainBackgroundTasks()
.Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes- [ ] tests and/or benchmarks are included(no, because right now everything still works without this – in the future, some things like WASM would fail otherwise)Affected core subsystem(s)
src/node_platform
/cc @nodejs/v8 @matthewloring @gahaas @natorion