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

src: prepare platform for upstream V8 changes #15428

Closed
wants to merge 4 commits into from

Conversation

addaleax
Copy link
Member

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().
Checklist
  • make -j4 test (UNIX), or vcbuild 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)
  • commit message follows commit guidelines
Affected core subsystem(s)

src/node_platform

/cc @nodejs/v8 @matthewloring @gahaas @natorion

@nodejs-github-bot nodejs-github-bot added the c++ Issues and PRs that require attention from people who are familiar with C++. label Sep 15, 2017
@addaleax addaleax added the v8 engine Issues and PRs related to the V8 dependency. label Sep 15, 2017
@jasnell
Copy link
Member

jasnell commented Sep 15, 2017

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);
Copy link
Member

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);

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?

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member Author

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 Isolates but looking up the proper Environment for a task is not trivial.

Copy link
Member

@fhinkel fhinkel left a comment

Choose a reason for hiding this comment

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

Nice!

@addaleax
Copy link
Member Author

@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.

CI: https://ci.nodejs.org/job/node-test-commit/12441/

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();
}
Copy link
Member

Choose a reason for hiding this comment

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

Unnecessary scoping?

Copy link
Member Author

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.

bool TaskQueue<T>::HasPending() {
Mutex::ScopedLock scoped_lock(lock_);
return !task_queue_.empty();
}
Copy link
Member

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();

Copy link
Member Author

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.

Copy link
Member

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.

@addaleax addaleax force-pushed the fix-node-platform branch 3 times, most recently from a60d5ee to f311ed9 Compare September 19, 2017 18:16
@@ -294,8 +294,35 @@ v8::MaybeLocal<v8::Value> InternalMakeCallback(
v8::Local<v8::Value> argv[],
async_context asyncContext);

class InternalCallbackScope {
public:
enum ResourceExpectation { kRequireResource, kAllowEmptyResource };
Copy link
Member

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

Copy link
Member Author

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()`.
@@ -39,7 +39,8 @@ class NodePlatform : public v8::Platform {
virtual ~NodePlatform() {}

void DrainBackgroundTasks();
void FlushForegroundTasksInternal();
// returns true iff work was dispatched or executed
Copy link
Member

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?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure, done!

@addaleax
Copy link
Member Author

@addaleax
Copy link
Member Author

Landed in f27b5e4

@addaleax addaleax closed this Sep 21, 2017
@addaleax addaleax deleted the fix-node-platform branch September 21, 2017 00:04
addaleax added a commit that referenced this pull request Sep 21, 2017
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]>
Qard pushed a commit to Qard/ayo that referenced this pull request Sep 21, 2017
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]>
Qard pushed a commit to Qard/ayo that referenced this pull request Sep 21, 2017
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]>
lukaszewczak pushed a commit to lukaszewczak/node that referenced this pull request Sep 23, 2017
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]>
@addaleax addaleax mentioned this pull request Sep 28, 2017
@addaleax
Copy link
Member Author

@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.

@addaleax
Copy link
Member Author

Same for #15691 as well – it still makes sense to me to backport all of these 3 together.

BridgeAR pushed a commit to BridgeAR/node that referenced this pull request Oct 1, 2017
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]>
addaleax added a commit to addaleax/node that referenced this pull request Oct 2, 2017
Make the context check in `MakeCallback` match what the comment says
(and what actually makes sense).

Fixes: nodejs#15672
Ref: nodejs#15428
Ref: f27b5e4
addaleax added a commit to addaleax/ayo that referenced this pull request Oct 4, 2017
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]>
addaleax added a commit that referenced this pull request Oct 8, 2017
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]>
addaleax added a commit to addaleax/ayo that referenced this pull request Oct 12, 2017
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]>
addaleax added a commit to addaleax/node that referenced this pull request Oct 14, 2017
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]>
addaleax added a commit to addaleax/node that referenced this pull request Oct 14, 2017
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]>
addaleax added a commit to addaleax/node that referenced this pull request Oct 14, 2017
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]>
targos pushed a commit that referenced this pull request Oct 18, 2017
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]>
targos pushed a commit that referenced this pull request Oct 18, 2017
#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]>
targos pushed a commit that referenced this pull request Oct 18, 2017
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]>
targos pushed a commit that referenced this pull request Oct 18, 2017
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]>
targos pushed a commit that referenced this pull request Oct 18, 2017
#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]>
targos pushed a commit that referenced this pull request Oct 18, 2017
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]>
@MylesBorins
Copy link
Contributor

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

@addaleax addaleax added the v8 platform Issues and PRs related to Node's v8::Platform implementation. label Feb 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. v8 engine Issues and PRs related to the V8 dependency. v8 platform Issues and PRs related to Node's v8::Platform implementation.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants