Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upUse the parking_lot locking primitives #56410
Conversation
rust-highfive
assigned
withoutboats
Dec 1, 2018
This comment was marked as outdated.
This comment was marked as outdated.
|
(rust_highfive has picked a reviewer for you, use r? to override) |
rust-highfive
added
the
S-waiting-on-review
label
Dec 1, 2018
This comment has been minimized.
This comment has been minimized.
|
r? @RalfJung |
rust-highfive
assigned
RalfJung
and unassigned
withoutboats
Dec 1, 2018
faern
force-pushed the
faern:add-parking-lot
branch
from
93093dc
to
57526ff
Dec 1, 2018
This comment has been minimized.
This comment has been minimized.
|
Just to be clear, this PR only changes the "back-end" of the mutex implementation. There are no changes to the public |
This comment has been minimized.
This comment has been minimized.
Isn’t there a difference between fairness of native EDIT: on some of the platforms, that is. |
This comment has been minimized.
This comment has been minimized.
Any fairness was "implementation-defined" in the current implementation. |
Centril
reviewed
Dec 1, 2018
|
Some observations; applies generally throughout the PR but I picked a few spots to illustrate. :) |
| pub struct UnparkHandle; | ||
|
|
||
| impl UnparkHandle { | ||
| // Wakes up the parked thread. This should be called after the queue lock is |
This comment has been minimized.
This comment has been minimized.
Centril
Dec 1, 2018
Contributor
Documentation is a bit unclear re. when this is UB and not; do you mean "must" by "should"?
(Do a review of the PR in general to make the safety invariants clearer and more definitive... For example "Behavior is undefined if X")
This comment has been minimized.
This comment has been minimized.
Amanieu
Dec 1, 2018
Contributor
This is an internal API which is only used in the internals of parking_lot_core. Regarding your question: I used "should" here because you don't want to issue a system call while holding a lock, to keep lock durations short.
|
|
||
| #[cold] | ||
| #[inline(never)] | ||
| unsafe fn unlock_slow(&self) { |
This comment has been minimized.
This comment has been minimized.
Centril
Dec 1, 2018
Contributor
This is a lot of logic for an unsafe function and the invariants aren't stated;
It would be more readable to split it up into smaller chunks imo and also state the invariants required.
(Applies also to the function before this one).
This comment has been minimized.
This comment has been minimized.
Amanieu
Dec 1, 2018
Contributor
In this case the invariants are pretty simple: don't lock if the current thread already owns the lock and don't unlock if the current thread doesn't own the lock.
This comment has been minimized.
This comment has been minimized.
Centril
Dec 1, 2018
•
Contributor
@Amanieu Sure; but it should be stated in the code explicitly. :) and long unsafe fns are more risky imo; if you break it down a bit things can be reasoned about better.
This comment has been minimized.
This comment has been minimized.
faern
Dec 4, 2018
Contributor
I have now managed to make three methods in this type not fully unsafe. And the only unsafe one left states why it is: unlock() must not be called on an already unlocked WordLock.
| unreachable!(); | ||
| } else { | ||
| enum Void {} | ||
| match *(1 as *const Void) {} |
This comment has been minimized.
This comment has been minimized.
Centril
Dec 1, 2018
Contributor
Isn't there a cleaner way to do this? Dereferencing *const Void should be UB...?
This comment has been minimized.
This comment has been minimized.
nagisa
Dec 1, 2018
•
Contributor
This is the stable pattern to get std::hint::unreachable_unchecked while unreachable was unstable. Should always use unreachable_unchecked now.
| key: usize, | ||
| filter: &mut dyn FnMut(ParkToken) -> FilterOp, | ||
| callback: &mut dyn FnMut(UnparkResult) -> UnparkToken, | ||
| ) -> UnparkResult { |
This comment has been minimized.
This comment has been minimized.
faern
force-pushed the
faern:add-parking-lot
branch
from
fb5360f
to
b4d3471
Dec 1, 2018
This comment was marked as outdated.
This comment was marked as outdated.
|
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
faern
force-pushed the
faern:add-parking-lot
branch
from
b4d3471
to
e230096
Dec 1, 2018
This comment was marked as outdated.
This comment was marked as outdated.
|
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
This comment has been minimized.
This comment has been minimized.
|
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
FYI, I will not have time to look at this "+4168 −2426" PR this week. I should be able to get to it next week though. I also feel slightly overwhelmed by the importance of this and would appreciate a co-reviewer -- maybe someone who actually has reviewed libstd code before :D |
This comment has been minimized.
This comment has been minimized.
|
I should add that I'm currently working on improving this code. Will likely push changes in a day or two. I have already backported some of the feedback here directly to |
faern
force-pushed the
faern:add-parking-lot
branch
from
c62d50d
to
910670f
Dec 4, 2018
This comment has been minimized.
This comment has been minimized.
|
|
faern
force-pushed the
faern:add-parking-lot
branch
2 times, most recently
from
2f15904
to
abc062b
Dec 9, 2018
faern
added some commits
Nov 26, 2018
faern
added some commits
Dec 9, 2018
This comment has been minimized.
This comment has been minimized.
|
I was able to remove the boxing of the inner locking type in the EDIT: Worth noting that this also affects the size of the synchronization structs. |
This comment has been minimized.
This comment has been minimized.
|
I haven't had a ton of time to dig into this yet, but I'd ideally prefer that I get a chance to review/approve this before it lands as well. At a high-level I would ideally prefer that this uses parking_lot directly from crates.io rather than being bundled into std. That would make it far easier I think to run more comprehensive CI tests, make it easier to maintain/contribute to, and also share the core implementation with the external Otherwise taking a strategy here of maintaining API parity and getting everything landed in an initial pass I think is a great way to start! |
This comment has been minimized.
This comment has been minimized.
|
Depending on the real The biggest problem is probably that |
This comment has been minimized.
This comment has been minimized.
|
Oh dear, that could indeed be a problem! I think wrappers like |
Centril
requested a review
from
alexcrichton
Dec 11, 2018
This comment has been minimized.
This comment has been minimized.
I think that's a good idea; in fact, given the importance of this API it would be good for 2 more people to review this besides yourself and @RalfJung. Maybe someone from lang could review it? perhaps @aturon (tho they are on PTO...) or @eddyb ?
Hmm... one drawback with this is that it becomes difficult to use new unstable language features for asorted benefits... and is there some use for specialization that could be beneficial for perf that isn't exposed to users? |
This comment has been minimized.
This comment has been minimized.
Ah, I missed that we had |
This comment has been minimized.
This comment has been minimized.
|
The problem with specifying timeouts as a |
This comment has been minimized.
This comment has been minimized.
|
Oh sorry for replacing Another option to use an external source of truth is to take a stdsimd-like approach where it's a submodule and not depended on via crates.io, just included directly into the crate via |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
|
It feels like it would be hard to avoid I will experiment with adding it as a git submodule and see how that goes. |
This comment has been minimized.
This comment has been minimized.
|
There are a number of things that have to change in One obvious thing is that the path to Another problem is the tidy format check. Is there any way to make tidy ignore a given directory/submodule?
Here is the work in progress state of what I change in As you can see, it's quite hacky and quite a lot of conditional compilation going on. One way to reduce it might be to make libstd re-export itself under a module named One more still unsolved problem is the documentation tests in The way I'm bringing the code into libstd goes something like this at the moment: #[path = "../parking_lot/core/src/lib.rs"]
#[allow(missing_debug_implementations, missing_docs, dead_code, unused_imports)]
mod parking_lot_core; |
This comment has been minimized.
This comment has been minimized.
|
Small update on last post: Adding mod std {
pub use super::*;
}to |
This comment has been minimized.
This comment has been minimized.
FWIW stdsimd ran into the same issue, and local development uses a bit of a hack to get
Oh it's fine to ignore this submodule, the whitelist to ignore is here
That part of the change I think is good to keep @Amanieu in the loop, as that's what'd ideally go upstream into
This is a bummer indeed! We have tons of pain with this in FWIW I think all of these problems would be largely solved if Would it be possible for |
This comment has been minimized.
This comment has been minimized.
I don't think that shoehorning the existing parking_lot crate into compiling directly as part of libstd is a good idea. Unlike stdsimd, which is explicitly designed to work as part of the standard library, parking_lot is intended to be used as a normal crate. This is particularly noticeable when you look at stdsimd: there is a stability attribute on every function.
It's not just I personally feel that hashbrown (#56241) is better candidate for making libstd depend on an external crate, but even then, there are several obstacles to overcome (in particular API stability and stability attributes). |
This comment has been minimized.
This comment has been minimized.
|
Oh so in terms of stability stdsimd is an odd-one-out. I think we'll want to always implement and document the stable interface in this repository, so even if we pull in implementation details from elsewhere we'll want the actual stable shims to be in this repository itself (aka Is it possible for parking_lot to have some sort of configuration mode where it doesn't bake in those features and we can provide an implementation in libstd? This is also sort of a
I'd love to see that happen! |
This comment has been minimized.
This comment has been minimized.
|
Small plug, but I'm still interested in the Cargo + re-facading changes that would make these sort or things a lot more seemless. |
This comment has been minimized.
This comment has been minimized.
|
This PR would fix #35836 |
This comment has been minimized.
This comment has been minimized.
|
@Ericson2314 , can you link to the re-facading discussion, for those of us who haven't been following along? |
This comment has been minimized.
This comment has been minimized.
|
@bstrie it's been many discussions since before 1.0, haha; in hindsight I do wish I bumped the same thread rather than bringing it up wherever it was relevant and discussing piecemeal.
|
This comment has been minimized.
This comment has been minimized.
|
So, what is the current status of this? @alexcrichton, @faern, @Amanieu is there a path forward without being blocked on the big refactorings mentioned by @Ericson2314? I have to admit I feel a bit overwhelmed reviewing this PR. I can certainly lend my expertise in concurrent algorithms, and review the "high-level bits", like how to implement locks and condvars and whatnot in terms of the low-level "parking" mechanism. But I know very little about futexes or the other low-level platform-specific primitives that form the foundation of this PR, and I do not feel confident enough to r+ the entire PR on my own. Anyone up for sharing this PR, preferably someone with expertise to review the part below the "parking" abstraction? |
This comment has been minimized.
This comment has been minimized.
|
To be clear I don't mean to propose blocking anything, just making the process of including something like a |
This comment has been minimized.
This comment has been minimized.
|
I have not had the time to work on this for quite some time now. I also feel it's kind of blocked on deciding how to get the code into libstd. My interpretation is that different people want different solutions. The options we have discussed are:
|
This comment has been minimized.
This comment has been minimized.
|
@faern's comment is what I believe the current status to be, and we can poll other @rust-lang/libs folks if they have opinions on this as well. I personally feel that we really want to avoid duplication here. I think there's also some policy-ish issues to work through in terms of reviewing code. In any case I think reviewing this is certainly much broader than "this technically looks good as is". |
This comment has been minimized.
This comment has been minimized.
KodrAus
commented
Jan 14, 2019
|
Over the longer term, what do we expect the relationship between |
This comment has been minimized.
This comment has been minimized.
|
I suspect that we'll forever want to be more conservative in the exposed surface area of libstd than in the crates.io crate. The crates.io crate can be far more ambitious and having breaking changes whereas libstd basically can't. I do suspect, though, that we'll want to grow the APIs of the types in Relationship-wise we currently have a pretty high degree of review of any code going into libstd in this repository. We don't do a great job, however, for submodules. Submodules like libc/stdsimd aren't too high-risk because their APIs are defined by someone else and the implementations are pretty rigorously tested too. Submodules like compiler-rt, however, probably receive far less review on implementation than they should. I'd be a little worried that we'd be expanding this to the synchronization system in libstd, which seems like it's naturally full of tricky code that would benefit from a higher-than-average level of scrutiny. This is something I'm not entirely sure how we'd solve just yet. |
This comment has been minimized.
This comment has been minimized.
|
std types definitely shouldn't be duplicated into parking_lot, but maybe we could create a crate (or crates) between core and parking_lot + std to create them. I've thought more about "bottom up" breaking up libraries than "top down" breaking up libraries, so I have no idea how easy this would be. |
This comment has been minimized.
This comment has been minimized.
|
@KodrAus yes std we are very tied up with stability guarantees. It would be great if anyone could import parking_lot and then get access to additional methods on the same types that |
faern commentedDec 1, 2018
•
edited by RalfJung
This PR adds the
parking_lotcode to libstd and uses it for thesys_common::{mutex,rwlock,condvar,remutex}implementations.This has been discussed in https://internals.rust-lang.org/t/standard-library-synchronization-primitives-and-undefined-behavior/8439/9
Thanks @Amanieu for mentoring when doing this, and basically all the code is his as well of course.
Fixes #35836
Fixes #53127