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

Unbox mutexes and condvars on some platforms #77380

Merged
merged 12 commits into from
Oct 4, 2020

Conversation

m-ou-se
Copy link
Member

@m-ou-se m-ou-se commented Sep 30, 2020

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

@rust-highfive
Copy link
Collaborator

r? @joshtriplett

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

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 30, 2020
JohnTitor added a commit to JohnTitor/rust that referenced this pull request Oct 1, 2020
…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.)
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Oct 1, 2020
…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.)
@bors
Copy link
Contributor

bors commented Oct 2, 2020

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

Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:

@rustbot modify labels: +S-waiting-on-review -S-waiting-on-author

Copy link
Member

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

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

r=me on the diff from #77147 to this (74237e9...dc67bde).

This commit keeps all mutexes boxed on all platforms, but makes it
trivial to remove the box on some platforms later.
Cloudabi mutexes may be moved safely.
These mutexes are just a bool (in a cell), so can be moved without
problems.
These mutexes are just an AtomicUsize, so can be moved without
problems.
Windows SRW locks are movable (while not borrowed) according to their
documentation.
This commit keeps all condvars boxed on all platforms, but makes it
trivial to remove the box on some platforms later.
Cloudabi condvars may be moved safely.
These condvars are unsupported and implemented as a ZST, so can be moved
without problems.
These condvars are just an AtomicUsize, so can be moved without
problems.
Windows condition variables are movable (while not borrowed) according
to their documentation.
Condvars are no longer guaranteed to panic in this case on all
platforms. At least the unix implementation still does.
@m-ou-se
Copy link
Member Author

m-ou-se commented Oct 2, 2020

Thanks!

Rebased to include #77147.

@m-ou-se m-ou-se marked this pull request as ready for review October 2, 2020 08:24
@dtolnay
Copy link
Member

dtolnay commented Oct 2, 2020

@bors r+

@bors
Copy link
Contributor

bors commented Oct 2, 2020

📌 Commit b1ce7a3 has been approved by dtolnay

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 2, 2020
@dtolnay dtolnay assigned dtolnay and unassigned joshtriplett Oct 2, 2020
@m-ou-se
Copy link
Member Author

m-ou-se commented Oct 2, 2020

Thanks!

Might be good to mark this as rollup=never, considering this changes platform-specific things. ^^

@dtolnay
Copy link
Member

dtolnay commented Oct 2, 2020

@bors rollup=iffy

@bors
Copy link
Contributor

bors commented Oct 3, 2020

⌛ Testing commit b1ce7a3 with merge 84e18dd511d49cc9dcb9a3e2b6fefb7eed27be77...

@bors
Copy link
Contributor

bors commented Oct 3, 2020

💥 Test timed out

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Oct 3, 2020
@m-ou-se
Copy link
Member Author

m-ou-se commented Oct 3, 2020

💥 Test timed out

This seems unrelated. The tests passed on all platforms except the dist-x86_64-apple-alt test, which timed out. This PR shouldn't affect anything on mac. That test was still running (it didn't deadlock), but it was running at 20%-50% of the usual speed: it was outputting [RUSTC-TIMING] messages with values 2 to 4 times higher than the last few runs.

@dtolnay
Copy link
Member

dtolnay commented Oct 3, 2020

@bors retry

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 3, 2020
@bors
Copy link
Contributor

bors commented Oct 4, 2020

⌛ Testing commit b1ce7a3 with merge 32cbc65...

@bors
Copy link
Contributor

bors commented Oct 4, 2020

☀️ Test successful - checks-actions, checks-azure
Approved by: dtolnay
Pushing 32cbc65 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Oct 4, 2020
@bors bors merged commit 32cbc65 into rust-lang:master Oct 4, 2020
@rustbot rustbot added this to the 1.49.0 milestone Oct 4, 2020
@m-ou-se m-ou-se deleted the unbox-the-mutex branch November 19, 2020 15:47
@jethrogb
Copy link
Contributor

@m-ou-se do you have any guidance for target maintainers that may want to get rid of the box?

@m-ou-se
Copy link
Member Author

m-ou-se commented Apr 22, 2021

@jethrogb The reason for the Box is that many mutex and condvar implementations are not trivially movable. If you can just 'memcpy' a mutex and forget about the old one, only then it can be used without a Box in Rust. This is often not possible because of things like internal pointers. Feel free to ping me in the #t-libs channel on Zulip if I can help with anything.

JohnTitor added a commit to JohnTitor/rust that referenced this pull request Jun 10, 2021
Multiple improvements to RwLocks

This PR replicates rust-lang#77147, rust-lang#77380 and rust-lang#84650 on RWLocks :
- Split `sys_common::RWLock` in `StaticRWLock` and `MovableRWLock`
- Unbox rwlocks on some platforms (Windows, Wasm and unsupported)
- Simplify `RwLock::into_inner`

Notes to reviewers :
- For each target, I copied `MovableMutex` to guess if `MovableRWLock` should be boxed.
- ~A comment says that `StaticMutex` is not re-entrant, I don't understand why and I don't know whether it applies to `StaticRWLock`.~

r? `@m-ou-se`
bors added a commit to rust-lang-ci/rust that referenced this pull request Jun 19, 2022
Make {Mutex, Condvar, RwLock}::new() const.

This makes it possible to have `static M: Mutex<_> = Mutex::new(..);` 🎉

Our implementations [on Linux](rust-lang#95035), [on Windows](rust-lang#77380), and various BSDs and some tier 3 platforms have already been using a non-allocating const-constructible implementation. As of rust-lang#97647, the remaining platforms (most notably macOS) now have a const-constructible implementation as well. This means we can finally make these functions publicly const.

Tracking issue: rust-lang#93740
workingjubilee pushed a commit to tcdi/postgrestd that referenced this pull request Sep 15, 2022
Make {Mutex, Condvar, RwLock}::new() const.

This makes it possible to have `static M: Mutex<_> = Mutex::new(..);` 🎉

Our implementations [on Linux](rust-lang/rust#95035), [on Windows](rust-lang/rust#77380), and various BSDs and some tier 3 platforms have already been using a non-allocating const-constructible implementation. As of rust-lang/rust#97647, the remaining platforms (most notably macOS) now have a const-constructible implementation as well. This means we can finally make these functions publicly const.

Tracking issue: rust-lang/rust#93740
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants