-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
worker: add Locks API #22719
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
worker: add Locks API #22719
Conversation
30f95f6 to
7c06fe4
Compare
src/env.h
Outdated
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 we make the spacing the same as before on all of these lines so that the diff will be much easier to view?
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.
make format-cpp just kinda... did that. i'm not sure how to undo it.
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.
They would have to be done manually. +1 on reverting this particular change.
src/node_internals.h
Outdated
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.
Ditto here about the spacing
7c06fe4 to
6099150
Compare
TimothyGu
left a 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.
Some preliminary comments. /cc @addaleax as the go-to C++ person :)
src/node_locks.cc
Outdated
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 is not thread-safe. What if multiple threads calls GetCurrent at the same time? I'd rather just initialize it for once in the main thread Environment's init method.
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.
It doesn’t even have to be initialized with new (and if it is, we should use smart pointers for that) – it can be a LockManager LockManager::current_;, no pointers or anything involved
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.
The alternative would be double locking this.
src/node_locks.cc
Outdated
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.
Use explicit types and references. This applies to most usage of auto in this PR.
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.
In particular, use references if that is what you are going for – these lines here actually create copies of pending_requests_ and held_locks_, but it’s not clear whether that’s intended?
src/node_locks.cc
Outdated
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.
emplace_front(this)
src/node_locks.h
Outdated
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 has unclear data ownership. Use std::string instead.
src/node_locks.h
Outdated
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.
As discussed offline, there is no benefit to making this a v8::Task versus just a regular libuv-backed object as used elsewhere in Core.
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.
I think there's a benefit of simplicity... I would still need a class to store this all and still need to insert it into the foreground queue somehow. Might as well use the API we have specifically for that right?
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.
I agree with @TimothyGu here, this should ideally be a libuv task (see ThreadPoolWork in node_internals.h)
src/node_locks.h
Outdated
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.
Ditto about strings.
|
I edited the OP to add the reference links provided by @inexorabletash in #22702 (comment). |
lib/internal/worker.js
Outdated
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.
Nit, to differentiate this from a callback API can we call this ‘disposer’ and not ‘callback’
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.
It's called "callback" in the spec.
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.
I would prefer this to be consistent with Node.js terminology. A callback for Node.js is an error-back. This would be confusing. This would also apply to our docs.
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.
I agree. While I generally prefer to keep naming the same or as same as possible to specs, in this case not calling this callback makes sense. Also, on the off chance that someone decided to try to wrap this in util.promisify() because it looks like a callback, it may make sense to have a custom promisify implementation for this.
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.
util.promisify makes no sense here, it already returns a promise. i will rename the variable.
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.
Yes, I know that util.promisify() makes no sense here, but that doesn't mean users won't try. Being defensive by providing a custom promisify implementation that skips wrapping and returns the actual promise makes sense... or, throw within the custom promisify to indicate that it doesn't make sense.
lib/internal/worker.js
Outdated
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.
To guard against cases where we throw by accident can this be an async function and throw instead of reject here?
We can still do the new promise dance below
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.
Also, not sure we should reject with a DOMException?
src/node_locks.cc
Outdated
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.
The alternative would be double locking this.
src/node_locks.h
Outdated
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.
const std::string& (to avoid extra copies)
src/node_locks.h
Outdated
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.
The node:: namespacing can be dropped
src/node_locks.h
Outdated
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.
ditto about std::string here and in name() below
src/node_locks.h
Outdated
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.
const std::string& (to avoid extra copies)
src/node_locks.cc
Outdated
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 seems odd, if you’re after std::move the header would be <utility>
src/node_locks.cc
Outdated
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 seems to share a bunch of code with the block below … can we merge that to some degree?
src/node_locks.cc
Outdated
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.
I don’t think FIXED_ONE_BYTE_STRING would work properly when the argument is not a fixed string
src/node_locks.cc
Outdated
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.
Use static_cast whenever possible
src/node_locks.h
Outdated
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.
I agree with @TimothyGu here, this should ideally be a libuv task (see ThreadPoolWork in node_internals.h)
src/node_locks.h
Outdated
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.
I think both the method and the LockRequest* parameter can be marked const?
mcollina
left a 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.
Good work so far
lib/internal/worker.js
Outdated
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.
I would prefer this to be consistent with Node.js terminology. A callback for Node.js is an error-back. This would be confusing. This would also apply to our docs.
48a1307 to
37ec99d
Compare
src/node_locks.cc
Outdated
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.
Likely better to push it to a separate follow up PR, but it would likely be helpful to emit trace events to track lock requests, grants, and releases to make them easier to debug.
src/node_locks.cc
Outdated
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.
@addaleax ... just thinking out loud here... would an std::unordered_map<std::string,std::deque<std::unique_ptr<Lock>> work better here to avoid having to loop through all locks and perform a string comparison on each?
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.
That’s very much possible – I haven’t really looked at the PR on that level, but it sounds like something that makes sense to me.
src/node_locks.cc
Outdated
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.
@addaleax ... does this function need to include an InternalCallbackScope?
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.
I would say so, yes… That would also mean that this class should inherit from AsyncWrap as well (but that makes sense, since it does run JS code asynchronously), and ditto for the other place you just commented
src/node_locks.cc
Outdated
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.
@addaleax ... in this function too... is InternalCallbackScope required?
3aed3ef to
81eba51
Compare
81eba51 to
44532ff
Compare
|
@jasnell is this the correct usage of the trace api? // When lock lock's waiting promise settles (fulfills or rejects),
// enqueue the following steps on the lock task queue:
waitingPromise
.finally(() => undefined)
.then(() => {
// Release the lock lock.
release();
trace('e'.charCodeAt(0), 'node.locks', 'LOCK_RELEASE', 0, { name });
// Resolve lock's released promise with lock's waiting promise.
resolve(waitingPromise);
}); |
|
|
||
| // Remove request from queue. | ||
| pending_requests_.erase( | ||
| std::remove( |
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.
std::remove is C++17, which we can't use.
|
@devsnek What’s the status here? |
|
@addaleax currently rewriting this to fix some issues... timeline unknown |
|
@devsnek Any updates? It looks to be bitrotting pretty bad. |
|
I'd like to get back to this eventually unless someone else wants to take it up. I'll close this pr for now since it's pretty much useless at this point. |
This is based upon nodejs#22719 and exposes the same API. Instead of a C++-backed approach, this variant implements the API mostly in JS. Refs: nodejs#22719 Co-authored-by: Gus Caplan <[email protected]>
This is based upon nodejs#22719 and exposes the same API. Instead of a C++-backed approach, this variant implements the API mostly in JS. Refs: nodejs#22719 Co-authored-by: Gus Caplan <[email protected]>
Closes #22702
References:
https://wicg.github.io/web-locks/
https://github.com/WICG/web-locks
https://github.com/WICG/web-locks/blob/master/EXPLAINER.md
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passes