-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Relax promises about condition variable. #76932
Relax promises about condition variable. #76932
Conversation
This allows for futex or thread parking based implementations in the future.
r? @sfackler (rust_highfive has picked a reviewer for you, use r? to override) |
I agree that this is the best option - I can't imagine that anyone is actually depending on this exact behavior. I'm going to run this through libs FCP though just in case! @rfcbot fcp merge |
Team member @sfackler has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
@bors r+ rollup |
📌 Commit 26d6081 has been approved by |
…as-schievink Rollup of 15 pull requests Successful merges: - rust-lang#76932 (Relax promises about condition variable.) - rust-lang#76973 (Unstably allow assume intrinsic in const contexts) - rust-lang#77005 (BtreeMap: refactoring around edges) - rust-lang#77066 (Fix dest prop miscompilation around references) - rust-lang#77073 (dead_code: look at trait impls even if they don't contain items) - rust-lang#77086 (Include libunwind in the rust-src component.) - rust-lang#77097 (Make [].as_[mut_]ptr_range() (unstably) const.) - rust-lang#77106 (clarify that `changelog-seen = 1` goes to the beginning of config.toml) - rust-lang#77120 (Add `--keep-stage-std` to `x.py` for keeping only standard library artifacts) - rust-lang#77126 (Invalidate local LLVM cache less often) - rust-lang#77146 (Install std for non-host targets) - rust-lang#77155 (remove enum name from ImplSource variants) - rust-lang#77176 (Removing erroneous semicolon in transmute documentation) - rust-lang#77183 (Allow multiple allow_internal_unstable attributes) - rust-lang#77189 (Remove extra space from vec drawing) Failed merges: r? `@ghost`
…ex, r=dtolnay Split sys_common::Mutex in StaticMutex and MovableMutex. The (unsafe) `Mutex` from `sys_common` had a rather complicated interface. You were supposed to call `init()` manually, unless you could guarantee it was neither moved nor used reentrantly. Calling `destroy()` was also optional, although it was unclear if 1) resources might be leaked or not, and 2) if `destroy()` should only be called when `init()` was called. This allowed for a number of interesting (confusing?) different ways to use this `Mutex`, all captured in a single type. In practice, this type was only ever used in two ways: 1. As a static variable. In this case, neither `init()` nor `destroy()` are called. The variable is never moved, and it is never used reentrantly. It is only ever locked using the `LockGuard`, never with `raw_lock`. 2. As a `Box`ed variable. In this case, both `init()` and `destroy()` are called, it will be moved and possibly used reentrantly. No other combinations are used anywhere in `std`. This change simplifies things by splitting this `Mutex` type into two types matching the two use cases: `StaticMutex` and `MovableMutex`. The interface of both new types is now both safer and simpler. The first one does not call nor expose `init`/`destroy`, and the second one calls those automatically in its `new()` and `Drop` functions. Also, the locking functions of `MovableMutex` are no longer unsafe. --- This will also make it easier to conditionally box mutexes later, by moving that decision into sys/sys_common. Some of the mutex implementations (at least those of Wasm and 'sys/unsupported') are safe to move, so wouldn't need a box. ~~(But that's blocked on rust-lang#76932 for now.)~~ (See rust-lang#77380.)
…ex, r=dtolnay Split sys_common::Mutex in StaticMutex and MovableMutex. The (unsafe) `Mutex` from `sys_common` had a rather complicated interface. You were supposed to call `init()` manually, unless you could guarantee it was neither moved nor used reentrantly. Calling `destroy()` was also optional, although it was unclear if 1) resources might be leaked or not, and 2) if `destroy()` should only be called when `init()` was called. This allowed for a number of interesting (confusing?) different ways to use this `Mutex`, all captured in a single type. In practice, this type was only ever used in two ways: 1. As a static variable. In this case, neither `init()` nor `destroy()` are called. The variable is never moved, and it is never used reentrantly. It is only ever locked using the `LockGuard`, never with `raw_lock`. 2. As a `Box`ed variable. In this case, both `init()` and `destroy()` are called, it will be moved and possibly used reentrantly. No other combinations are used anywhere in `std`. This change simplifies things by splitting this `Mutex` type into two types matching the two use cases: `StaticMutex` and `MovableMutex`. The interface of both new types is now both safer and simpler. The first one does not call nor expose `init`/`destroy`, and the second one calls those automatically in its `new()` and `Drop` functions. Also, the locking functions of `MovableMutex` are no longer unsafe. --- This will also make it easier to conditionally box mutexes later, by moving that decision into sys/sys_common. Some of the mutex implementations (at least those of Wasm and 'sys/unsupported') are safe to move, so wouldn't need a box. ~~(But that's blocked on rust-lang#76932 for now.)~~ (See rust-lang#77380.)
So all these other condvar implementations still guarantee safety even when used with different mutexes over time?
This means at least for pthread condvars, we have to do this check. |
Nope! But some do, and those can have their mutexes unboxed.
Indeed! Pthread mutexes/condvars cannot be unboxed in Rust, and this check should stay for those. That's why it still says "may panic". (The check could be slightly relaxed. Pthread and friends do allow using different mutexes with a single condvar, only not at the same time.) |
Thanks for clarifying @m-ou-se :) |
…tex, r=dtolnay Unbox mutexes and condvars on some platforms Both mutexes and condition variables contained a Box containing the actual os-specific object. This was done because moving these objects may cause undefined behaviour on some platforms. However, this is not needed on Windows[1], Wasm[2], cloudabi[2], and 'unsupported'[3], were the box was only needlessly making them less efficient. This change gets rid of the box on those platforms. On those platforms, `Condvar` can no longer verify it is only used with one `Mutex`, as mutexes no longer have a stable address. This was addressed and considered acceptable in rust-lang#76932. [1]\: https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-initializesrwlock [2]\: These are just a single atomic integer together with futex wait/wake calls/instructions. [3]\: The `unsupported` platform doesn't support multiple threads at all.
For quite a while now, there have been plans to at some point use parking_lot or some other more efficient implementation of mutexes and condition variables. Right now, Mutex and CondVar both Box the 'real' mutex/condvar inside, to give it a stable address. This was done because implementations like pthread and Windows critical sections may not be moved. More efficient implementations based on futexes, WaitOnAddress, Windows SRW locks, parking_lot, etc. may be moved (while not borrowed), so wouldn't need boxing.
However, not boxing them (which would be great goal to achieve), breaks a promise std currently makes about CondVar. CondVar promises to panic when used with different mutexes, to ensure consistent behaviour on all platforms. To this check, a mutex is considered 'the same' if the address of the 'real mutex' in the Box is the same. This address doesn't change when moving a
std::mutex::Mutex
object, effectively giving it an identity that survives moves of the Mutex object. If we ever switch to a non-boxed version, they no longer carry such an identity, and this check can no longer be made.Four options:
MutexId
similar toThreadId
. Making mutexes bigger, and making it hard to ever have aconst fn new
for them.1, 2, and 3 seem like bad options. This PR updates the documentation for 4.