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

Use the parking_lot locking primitives #56410

Open
wants to merge 23 commits into
base: master
from

Conversation

Projects
None yet
@faern
Copy link
Contributor

faern commented Dec 1, 2018

This PR adds the parking_lot code to libstd and uses it for the sys_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

@rust-highfive

This comment was marked as outdated.

Copy link
Collaborator

rust-highfive commented Dec 1, 2018

r? @withoutboats

(rust_highfive has picked a reviewer for you, use r? to override)

@Centril

This comment has been minimized.

Copy link
Contributor

Centril commented Dec 1, 2018

@faern faern force-pushed the faern:add-parking-lot branch from 93093dc to 57526ff Dec 1, 2018

@Amanieu

This comment has been minimized.

Copy link
Contributor

Amanieu commented Dec 1, 2018

Just to be clear, this PR only changes the "back-end" of the mutex implementation. There are no changes to the public Mutex API in libstd. API changes (such as const fn support) can be done in a later PR.

@nagisa

This comment has been minimized.

Copy link
Contributor

nagisa commented Dec 1, 2018

There are no changes to the public Mutex API in libstd.

Isn’t there a difference between fairness of native Mutex and parking_lot’s Mutex?

EDIT: on some of the platforms, that is.

@Amanieu

This comment has been minimized.

Copy link
Contributor

Amanieu commented Dec 1, 2018

Isn’t there a difference between fairness of native Mutex and parking_lot’s Mutex?

Any fairness was "implementation-defined" in the current implementation.

@Centril
Copy link
Contributor

Centril left a comment

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.

@Centril

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.

@Amanieu

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.

Show resolved Hide resolved src/libstd/sys_common/thread_parker.rs Outdated
Show resolved Hide resolved src/libstd/sys_common/thread_parker.rs

#[cold]
#[inline(never)]
unsafe fn unlock_slow(&self) {

This comment has been minimized.

@Centril

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.

@Amanieu

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.

@Centril

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.

@faern

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.

@Centril

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.

@nagisa

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.

Show resolved Hide resolved src/libstd/sys_common/parking_lot_core/spinwait.rs Outdated
key: usize,
filter: &mut dyn FnMut(ParkToken) -> FilterOp,
callback: &mut dyn FnMut(UnparkResult) -> UnparkToken,
) -> UnparkResult {

This comment has been minimized.

@Centril

Centril Dec 1, 2018

Contributor

Also a very long unsafe function.

@faern faern referenced this pull request Dec 1, 2018

Merged

Backport libstd style #106

@faern faern force-pushed the faern:add-parking-lot branch from fb5360f to b4d3471 Dec 1, 2018

@rust-highfive

This comment was marked as outdated.

Copy link
Collaborator

rust-highfive commented Dec 1, 2018

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
travis_time:end:1c3ab440:start=1543686799054107223,finish=1543686801424514854,duration=2370407631
$ git checkout -qf FETCH_HEAD
travis_fold:end:git.checkout

Encrypted environment variables have been removed for security reasons.
See https://docs.travis-ci.com/user/pull-requests/#Pull-Requests-and-Security-Restrictions
$ export SCCACHE_BUCKET=rust-lang-ci-sccache2
$ export SCCACHE_REGION=us-west-1
Setting environment variables from .travis.yml
$ export IMAGE=x86_64-gnu-llvm-5.0
---
travis_time:start:test_codegen
Check compiletest suite=codegen mode=codegen (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
[00:58:14] 
[00:58:14] running 119 tests
[00:58:17] i..ii...iii..iiii.....i...i.........i..iii.............i.....i.....ii...i..i.ii..............i...ii. 100/119
[00:58:18] .ii.i.....iiii.....
[00:58:18] 
[00:58:18]  finished in 3.641
[00:58:18] travis_fold:end:test_codegen

---
travis_time:start:test_debuginfo
Check compiletest suite=debuginfo mode=debuginfo-both (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
[00:58:33] 
[00:58:33] running 118 tests
[00:58:58] .iiiii...i.....i..i...i..i.i..i.i..i.....i..i....i..........iiii.........i.i....i...i.......ii.i.i.i 100/118
[00:59:02] ......iii.i.....ii
[00:59:02] 
[00:59:02]  finished in 29.112
[00:59:02] travis_fold:end:test_debuginfo

---
[01:15:16] travis_fold:start:test_stage1-std
travis_time:start:test_stage1-std
Testing std stage1 (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
[01:15:16]    Compiling std v0.0.0 (/checkout/src/libstd)
[01:15:19] error[E0432]: unresolved import `super::ReentrantMutex`
[01:15:19]   --> src/libstd/sys_common/parking_lot/remutex.rs:93:9
[01:15:19]    |
[01:15:19] 93 |     use super::ReentrantMutex;
[01:15:19]    |         ^^^^^^^^^^^^^^^^^^^^^ no `ReentrantMutex` in `sys_common::parking_lot::remutex`. Did you mean to use `RawReentrantMutex`?
[01:15:19] 
[01:15:19] error[E0432]: unresolved imports `Condvar`, `Mutex`
[01:15:19]    --> src/libstd/sys_common/parking_lot/condvar.rs:402:10
[01:15:19]     |
[01:15:19] 402 |     use {Condvar, Mutex};
[01:15:19]     |          ^^^^^^^  ^^^^^ no `Mutex` in the root
[01:15:19]     |          no `Condvar` in the root
[01:15:19] 
[01:15:19] 
j/cores/core.*; do EXE=$(echo $CORE | sed 's|obj/cores/core\.[0-9]*\.!checkout!\(.*\)|\1|;y|!|/|'); if [ -f "$EXE" ]; then printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE"; gdb --batch -q -c "$CORE" "$EXE" -iex 'set auto-load off' -iex 'dir src/' -iex 'set sysroot .' -ex bt -ex q; echo travis_fold":"end:crashlog; fi; done || true

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 @TimNN. (Feature Requests)

@faern faern force-pushed the faern:add-parking-lot branch from b4d3471 to e230096 Dec 1, 2018

@rust-highfive

This comment was marked as outdated.

Copy link
Collaborator

rust-highfive commented Dec 1, 2018

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
travis_time:end:1f2f2f49:start=1543692321136569642,finish=1543692323399010557,duration=2262440915
$ git checkout -qf FETCH_HEAD
travis_fold:end:git.checkout

Encrypted environment variables have been removed for security reasons.
See https://docs.travis-ci.com/user/pull-requests/#Pull-Requests-and-Security-Restrictions
$ export SCCACHE_BUCKET=rust-lang-ci-sccache2
$ export SCCACHE_REGION=us-west-1
Setting environment variables from .travis.yml
$ export IMAGE=x86_64-gnu-llvm-5.0
---
travis_time:start:test_codegen
Check compiletest suite=codegen mode=codegen (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
[00:56:54] 
[00:56:54] running 119 tests
[00:56:57] i..ii...iii..iiii.....i...i.........i..iii.............i.....i.....ii...i..i.ii..............i...ii. 100/119
[00:56:57] .ii.i.....iiii.....
[00:56:57] 
[00:56:57]  finished in 3.461
[00:56:57] travis_fold:end:test_codegen

---
travis_time:start:test_debuginfo
Check compiletest suite=debuginfo mode=debuginfo-both (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
[00:57:12] 
[00:57:12] running 118 tests
[00:57:36] .iiiii...i.....i..i...i..i.i..i.i..i.....i..i....i..........iiii.........i.i....i...i.......ii.i.i.i 100/118
[00:57:40] ......iii.i.....ii
[00:57:40] 
[00:57:40]  finished in 28.444
[00:57:40] travis_fold:end:test_debuginfo

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 @TimNN. (Feature Requests)

@rust-highfive

This comment has been minimized.

Copy link
Collaborator

rust-highfive commented Dec 2, 2018

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
travis_time:end:13ee08a4:start=1543709531669510421,finish=1543709533977542973,duration=2308032552
$ git checkout -qf FETCH_HEAD
travis_fold:end:git.checkout

Encrypted environment variables have been removed for security reasons.
See https://docs.travis-ci.com/user/pull-requests/#Pull-Requests-and-Security-Restrictions
$ export SCCACHE_BUCKET=rust-lang-ci-sccache2
$ export SCCACHE_REGION=us-west-1
Setting environment variables from .travis.yml
$ export IMAGE=x86_64-gnu-llvm-5.0
---
travis_time:start:test_codegen
Check compiletest suite=codegen mode=codegen (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
[00:59:22] 
[00:59:22] running 119 tests
[00:59:25] i..ii...iii..iiii.....i...i.........i..iii.............i.....i.....ii...i..i.ii..............i...ii. 100/119
[00:59:25] .ii.i.....iiii.....
[00:59:25] 
[00:59:25]  finished in 3.668
[00:59:25] travis_fold:end:test_codegen

---
travis_time:start:test_debuginfo
Check compiletest suite=debuginfo mode=debuginfo-both (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
[00:59:41] 
[00:59:41] running 118 tests
[01:00:07] .iiiii...i.....i..i...i..i.i..i.i..i.....i..i....i..........iiii.........i.i....i...i.......ii.i.i.i 100/118
[01:00:11] ......iii.i.....ii
[01:00:11] 
[01:00:11]  finished in 30.123
[01:00:11] travis_fold:end:test_debuginfo

---
[01:17:03] travis_fold:start:test_stage1-std
travis_time:start:test_stage1-std
Testing std stage1 (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
[01:17:03]    Compiling std v0.0.0 (/checkout/src/libstd)
[01:17:06] error[E0432]: unresolved imports `Condvar`, `Mutex`
[01:17:06]    --> src/libstd/sys_common/parking_lot/condvar.rs:399:10
[01:17:06]     |
[01:17:06] 399 |     use {Condvar, Mutex};
[01:17:06]     |          ^^^^^^^  ^^^^^ no `Mutex` in the root
[01:17:06]     |          no `Condvar` in the root
[01:17:06] 
[01:17:19] error: aborting due to previous error
[01:17:19] 
[01:17:19] 
[01:17:19] For more information about this error, try `rustc --explain E0432`.
[01:17:19] error: Could not compile `std`.
[01:17:19] 
[01:17:19] To learn more, run the command again with --verbose.
[01:17:19] 
[01:17:19] 
[01:17:19] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "test" "--target" "x86_64-unknown-linux-gnu" "-j" "4" "--release" "--locked" "--color" "always" "--features" "panic-unwind backtrace" "--manifest-path" "/checkout/src/libstd/Cargo.toml" "-p" "std" "--" "--quiet"
[01:17:19] 
[01:17:19] 
[01:17:19] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test
[01:17:19] Build completed unsuccessfully in 0:29:07
[01:17:19] Build completed unsuccessfully in 0:29:07
[01:17:19] make: *** [check] Error 1
[01:17:19] Makefile:58: recipe for target 'check' failed
The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:00ae4529
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)
Sun Dec  2 01:29:43 UTC 2018

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 @TimNN. (Feature Requests)

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Dec 2, 2018

☔️ The latest upstream changes (presumably #56275) made this pull request unmergeable. Please resolve the merge conflicts.

@RalfJung

This comment has been minimized.

Copy link
Member

RalfJung commented Dec 4, 2018

r? @RalfJung

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

@faern

This comment has been minimized.

Copy link
Contributor

faern commented Dec 4, 2018

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 parking_lot and have managed to, at least slightly, reduce the amount of unsafe. As soon as I have reached some good state and my tests pass I will push things here.

@faern faern force-pushed the faern:add-parking-lot branch from c62d50d to 910670f Dec 4, 2018

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Dec 7, 2018

☔️ The latest upstream changes (presumably #56066) made this pull request unmergeable. Please resolve the merge conflicts.

@faern faern force-pushed the faern:add-parking-lot branch 2 times, most recently from 2f15904 to abc062b Dec 9, 2018

@faern

This comment has been minimized.

Copy link
Contributor

faern commented Dec 9, 2018

I was able to remove the boxing of the inner locking type in the std::sync locking types. Since it's no longer important to keep the locks fixed at one memory address we don't need the box. For std::sync::Mutex this reduced indirection resulted in approximately 5% speedup in micro benchmarks on Linux, when there is contention. Compared to the performance std::sync::Mutex had with the code in this PR just before removing the boxing (the benchmarks posted above).

EDIT: Worth noting that this also affects the size of the synchronization structs. Mutex<()> went from 16 to 2 bytes.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Dec 11, 2018

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 parking_lot crate as well. Depending on external crates.io crates isn't easy, but is being pioneered in another PR. Additionally this won't be as trivial a task as pulling in anything from crates.io, but we can work through the details.

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!

@faern

This comment has been minimized.

Copy link
Contributor

faern commented Dec 11, 2018

Depending on the real parking_lot crate would of course be awesome for maintainability. I have been following the other PR you link to see the progress of that. So far most work I have put into this has been backported into parking_lot itself, so that does not set anything back.

The biggest problem is probably that parking_lot depend on a lot of libstd types. it uses Instant, Duration, thread::yield_now and maybe a few more things.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Dec 11, 2018

Oh dear, that could indeed be a problem! I think wrappers like thread::yield_now are probably thin enough (and libstd could call into parking_lot though? While Instant wouldn't be easily usable I think Duration is in core nowadays as well. Perhaps that would be enough to build a bare-bones API?

@Centril Centril requested a review from alexcrichton Dec 11, 2018

@Centril

This comment has been minimized.

Copy link
Contributor

Centril commented Dec 11, 2018

@alexcrichton

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.

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 ?

At a high-level I would ideally prefer that this uses parking_lot directly from crates.io rather than being bundled into std.

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?

@faern

This comment has been minimized.

Copy link
Contributor

faern commented Dec 11, 2018

While Instant wouldn't be easily usable I think Duration is in core nowadays as well. Perhaps that would be enough to build a bare-bones API?

Ah, I missed that we had Duration in core. That's something. A problem I see is that the underlying ThreadParker implementations need a way to measure elapsed time. The function signature that uses Instant looks like: park_until(&self, timeout: Instant). While I think it would be possible to make the user specify the timeout as a Duration, the algorithms still needs a way to measure elapsed time internally.

@Amanieu

This comment has been minimized.

Copy link
Contributor

Amanieu commented Dec 11, 2018

The problem with specifying timeouts as a Duration is that it is subject to drift if there are spurious wakeups (the thread is woken up but somebody else has already grabbed the lock in the meantime). This is why I chose to convert all timeouts to Instant as soon as possible.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Dec 12, 2018

Oh sorry for replacing Instant I meant moreso a possibility of considering all Duration instances as a "duration from a fixed point in time" rather than a relative "so many seconds from now". That may be difficult to work internally though?

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 #[path]. One downside of that though is that it makes the crate itself a bit more difficult to develop

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Dec 14, 2018

☔️ The latest upstream changes (presumably #56490) made this pull request unmergeable. Please resolve the merge conflicts.

@faern

This comment has been minimized.

Copy link
Contributor

faern commented Dec 14, 2018

It feels like it would be hard to avoid Instant? Not that I have really tried, but no one seems to have a good suggestion on how to do it. Even if we were to see Duration as a fixed point in time instead of a duration, we need a way to know the current point in time in many places, in order to know if our given deadline has passed or not.

I will experiment with adding it as a git submodule and see how that goes.

@faern

This comment has been minimized.

Copy link
Contributor

faern commented Dec 17, 2018

There are a number of things that have to change in parking_lot for it to be usable as a submodule it seems. Sharing my findings so far to see if anyone have ideas that can make it simpler.

One obvious thing is that the path to std types are different if it's being compiled as a normal crate or if it's actually inside libstd. Another thing is trying to maintain 1.24.0 compatibility while still also working as Rust 2018 edition code like the rest of libstd. Both of these problems seems solvable by adding a feature to libstd: i-am-libstd. And then conditionally compile a lot of stuff inside parking_lot on this feature. This feature is not added to parking_lot's own Cargo.toml since it's of no use there really.

Another problem is the tidy format check. Is there any way to make tidy ignore a given directory/submodule? parking_lot contains a lot of platform conditional compilation, and tidy does not like that inside src/parking_lot/:

tidy error: /build/rust/src/parking_lot/benchmark/src/rwlock.rs:15: platform-specific cfg: cfg(unix)
tidy error: /build/rust/src/parking_lot/benchmark/src/rwlock.rs:96: platform-specific cfg: cfg(not(unix))
...

Here is the work in progress state of what I change in parking_lot to make this work: https://github.com/faern/parking_lot/compare/master...faern:as-libstd-submodule?expand=1

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 std 🤷‍♂️ That way parking_lot can use use std::whatever even when it's part of libstd.

One more still unsolved problem is the documentation tests in parking_lot. They also have the wrong use statements (use parking_lot::Condvar is not a valid path when compiled inside libstd). But I'm not sure we could conditionally compile that. And even if we could it would likely end up very ugly.

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;
@faern

This comment has been minimized.

Copy link
Contributor

faern commented Dec 17, 2018

Small update on last post: Adding

mod std {
    pub use super::*;
}

to libstd/lib.rs is a bit awkward, but it allows code inside libstd to use the same paths to everything as if they were not inside libstd. This allows us to make way fewer changes to parking_lot itself. And possibly other crates we might want to include in a similar manner. 🤷‍♂️

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Dec 18, 2018

One obvious thing is that the path to std types are different if it's being compiled as a normal crate or if it's actually inside libstd

FWIW stdsimd ran into the same issue, and local development uses a bit of a hack to get core-looking paths working everywhere. I don't think this would work well in parking_lot though which is otherwise intended to compile on stable and also be more maintainable outside of std. The workaround you mentioned with pub use super::* if it works is probably the way to go.

Another problem is the tidy format check

Oh it's fine to ignore this submodule, the whitelist to ignore is here

As you can see, it's quite hacky and quite a lot of conditional compilation going on.

That part of the change I think is good to keep @Amanieu in the loop, as that's what'd ideally go upstream into parking_lot itself!

One more still unsolved problem is the documentation tests in parking_lot

This is a bummer indeed! We have tons of pain with this in stdsimd. The end goal I think is to skip all of parking_lot's tests, including doctests, when included into the Rust repo. As to how to get there I'm not entirely certain...


FWIW I think all of these problems would be largely solved if parking_lot were a crate. I feel like that's still the best solution here if we can stomach it.

Would it be possible for parking_lot to have a no_std mode that has internal wrappers for types that libstd otherwise provides like Instant?

@Amanieu

This comment has been minimized.

Copy link
Contributor

Amanieu commented Dec 18, 2018

As you can see, it's quite hacky and quite a lot of conditional compilation going on.

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.

Would it be possible for parking_lot to have a no_std mode that has internal wrappers for types that libstd otherwise provides like Instant?

It's not just Instant, parking_lot also depends on thread_local! and thread::yield. We could just copy these types and functions into parking_lot, but then we're creating more maintenance problems than we are solving.

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

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Dec 18, 2018

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 HashMap would be a thin wrapper around hashbrown hash maps). With stdsimd it's an "odd one out" because it's adding thousands of functions to libstd where it's totally infeasible to wrap each and every one with a wrapper in this repository.

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 HashMap-like problem where we want to put it in liballoc but liballoc doesn't have the OS-based randomness... I'm hopefuly though that type parameters and/or traits could solve this issue!

I personally feel that hashbrown (#56241) is better candidate for making libstd depend on an external crate

I'd love to see that happen!

@Ericson2314

This comment has been minimized.

Copy link
Contributor

Ericson2314 commented Dec 25, 2018

Small plug, but I'm still interested in the Cargo + re-facading changes that would make these sort or things a lot more seemless.

@retep998

This comment has been minimized.

Copy link
Member

retep998 commented Jan 2, 2019

This PR would fix #35836

@bstrie

This comment has been minimized.

Copy link
Contributor

bstrie commented Jan 6, 2019

@Ericson2314 , can you link to the re-facading discussion, for those of us who haven't been following along?

@Ericson2314

This comment has been minimized.

Copy link
Contributor

Ericson2314 commented Jan 6, 2019

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

  • After my Cargo RFC (rust-lang/rfcs#1133) died of old age, I opened some issues to track the underlying issues

    Even though we aren't "blocked" on this, per the early parts of this thread, I still think it's quite important. Once it's far easier to create crates that could live behind the facade, I hope a larger ecosystem of crates for lower-level work would develop, after which we'll have many more contenders. People should feel comfortable ripping out bits of the std in a crate on their own for their own itch, and have that crate become a backing crate behind the facade rather than an albatross they have to continuously re-extract.

  • "re-facading"

    • I wrote rust-lang-nursery/portability-wg#1 (comment) with 3 independent tracks of library work.
    • People were wary of even temporarily making the alloc and std collections not unify, so I opened rust-lang/rfcs#2492 to add a language feature to allow moving collections (and other things referring to global/singletons) into upstream creates without that compromise.
    • @glandium and I have some PRs for alloc to add allocator parameters (closed due to being blocked on LLVM min version issues and lib team bandwidth). This isn't strictly speaking re-facading, but I bring it up since hashbrown is the best candidate to stay out of tree, and I've long wanted all of the collections to also live out of tree since they many are so close to being stable code. (Unstable features that just gate an unstable API don't count!)

    So I think the next steps are shepherding that RFC, rebooting the core::io stuff (which thankfully isn't blocked on any language change!), and the allocator stuff once LLVM is out of the way (or we figure out how to make some unstable feature whose existence is gated on the LLVM provided).

@RalfJung

This comment has been minimized.

Copy link
Member

RalfJung commented Jan 12, 2019

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?
EDIT: Ah I see others have already raised similar concerns, thank you :)

@Ericson2314

This comment has been minimized.

Copy link
Contributor

Ericson2314 commented Jan 12, 2019

To be clear I don't mean to propose blocking anything, just making the process of including something like a hashbrown or parking_lot easier in the future.

@faern

This comment has been minimized.

Copy link
Contributor

faern commented Jan 14, 2019

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:

  1. Copy the code into this repository. This is what this PR does right now. But it's not fully done yet as I paused while alternatives were discussed. Has the downside that we create a lot of duplicated code to maintain.
  2. Include parking_lot as a git submodule. I experimented with this. This looks doable, but requires some hacks to be merged into parking_lot. My understanding was that @Amanieu was not too happy about them.
  3. Make parking_lot into #[no_std] and make libstd depend on it from crates.io. Seems almost impossible. parking_lot really needs some types from the standard library, for example Instant.
@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Jan 14, 2019

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

@KodrAus

This comment has been minimized.

Copy link

KodrAus commented Jan 14, 2019

Over the longer term, what do we expect the relationship between std and parking_lot to be? Do we expect more of parking_lot to make its way into std in a publicly visible way (effectively deprecating the external crate) or do we always expect there to be a case for using parking_lot as an external library?

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Jan 15, 2019

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 std::sync if we move over to parking_lot and everything goes well, there's likely some very useful functionality to expose that we just can't right now (const initialization might be one...)

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.

@Ericson2314

This comment has been minimized.

Copy link
Contributor

Ericson2314 commented Jan 15, 2019

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.

@Ericson2314

This comment has been minimized.

Copy link
Contributor

Ericson2314 commented Jan 15, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment