Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ac470e9

Browse files
committedJun 1, 2021
Multiple improvements to RwLocks
- Split `sys_common::RWLock` between `StaticRWLock` and `MovableRWLock` - Unbox `RwLock` on some platforms (Windows, Wasm and unsupported) - Simplify `RwLock::into_inner`
1 parent 4127806 commit ac470e9

File tree

10 files changed

+111
-133
lines changed

10 files changed

+111
-133
lines changed
 

‎library/std/src/panicking.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::process;
1919
use crate::sync::atomic::{AtomicBool, Ordering};
2020
use crate::sys::stdio::panic_output;
2121
use crate::sys_common::backtrace::{self, RustBacktrace};
22-
use crate::sys_common::rwlock::RWLock;
22+
use crate::sys_common::rwlock::StaticRWLock;
2323
use crate::sys_common::thread_info;
2424
use crate::thread;
2525

@@ -74,7 +74,7 @@ enum Hook {
7474
Custom(*mut (dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send)),
7575
}
7676

77-
static HOOK_LOCK: RWLock = RWLock::new();
77+
static HOOK_LOCK: StaticRWLock = StaticRWLock::new();
7878
static mut HOOK: Hook = Hook::Default;
7979

8080
/// Registers a custom panic hook, replacing any that was previously registered.
@@ -117,10 +117,10 @@ pub fn set_hook(hook: Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>) {
117117
}
118118

119119
unsafe {
120-
HOOK_LOCK.write();
120+
let guard = HOOK_LOCK.write();
121121
let old_hook = HOOK;
122122
HOOK = Hook::Custom(Box::into_raw(hook));
123-
HOOK_LOCK.write_unlock();
123+
drop(guard);
124124

125125
if let Hook::Custom(ptr) = old_hook {
126126
#[allow(unused_must_use)]
@@ -165,10 +165,10 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
165165
}
166166

167167
unsafe {
168-
HOOK_LOCK.write();
168+
let guard = HOOK_LOCK.write();
169169
let hook = HOOK;
170170
HOOK = Hook::Default;
171-
HOOK_LOCK.write_unlock();
171+
drop(guard);
172172

173173
match hook {
174174
Hook::Default => Box::new(default_hook),
@@ -608,7 +608,7 @@ fn rust_panic_with_hook(
608608

609609
unsafe {
610610
let mut info = PanicInfo::internal_constructor(message, location);
611-
HOOK_LOCK.read();
611+
let _guard = HOOK_LOCK.read();
612612
match HOOK {
613613
// Some platforms (like wasm) know that printing to stderr won't ever actually
614614
// print anything, and if that's the case we can skip the default
@@ -626,7 +626,6 @@ fn rust_panic_with_hook(
626626
(*ptr)(&info);
627627
}
628628
};
629-
HOOK_LOCK.read_unlock();
630629
}
631630

632631
if panics > 1 {

‎library/std/src/sync/rwlock.rs

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ mod tests;
33

44
use crate::cell::UnsafeCell;
55
use crate::fmt;
6-
use crate::mem;
76
use crate::ops::{Deref, DerefMut};
8-
use crate::ptr;
97
use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
108
use crate::sys_common::rwlock as sys;
119

@@ -66,7 +64,7 @@ use crate::sys_common::rwlock as sys;
6664
/// [`Mutex`]: super::Mutex
6765
#[stable(feature = "rust1", since = "1.0.0")]
6866
pub struct RwLock<T: ?Sized> {
69-
inner: Box<sys::RWLock>,
67+
inner: sys::MovableRWLock,
7068
poison: poison::Flag,
7169
data: UnsafeCell<T>,
7270
}
@@ -130,7 +128,7 @@ impl<T> RwLock<T> {
130128
#[stable(feature = "rust1", since = "1.0.0")]
131129
pub fn new(t: T) -> RwLock<T> {
132130
RwLock {
133-
inner: box sys::RWLock::new(),
131+
inner: sys::MovableRWLock::new(),
134132
poison: poison::Flag::new(),
135133
data: UnsafeCell::new(t),
136134
}
@@ -376,24 +374,8 @@ impl<T: ?Sized> RwLock<T> {
376374
where
377375
T: Sized,
378376
{
379-
// We know statically that there are no outstanding references to
380-
// `self` so there's no need to lock the inner lock.
381-
//
382-
// To get the inner value, we'd like to call `data.into_inner()`,
383-
// but because `RwLock` impl-s `Drop`, we can't move out of it, so
384-
// we'll have to destructure it manually instead.
385-
unsafe {
386-
// Like `let RwLock { inner, poison, data } = self`.
387-
let (inner, poison, data) = {
388-
let RwLock { ref inner, ref poison, ref data } = self;
389-
(ptr::read(inner), ptr::read(poison), ptr::read(data))
390-
};
391-
mem::forget(self);
392-
inner.destroy(); // Keep in sync with the `Drop` impl.
393-
drop(inner);
394-
395-
poison::map_result(poison.borrow(), |_| data.into_inner())
396-
}
377+
let data = self.data.into_inner();
378+
poison::map_result(self.poison.borrow(), |_| data)
397379
}
398380

399381
/// Returns a mutable reference to the underlying data.
@@ -424,14 +406,6 @@ impl<T: ?Sized> RwLock<T> {
424406
}
425407
}
426408

427-
#[stable(feature = "rust1", since = "1.0.0")]
428-
unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock<T> {
429-
fn drop(&mut self) {
430-
// IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`.
431-
unsafe { self.inner.destroy() }
432-
}
433-
}
434-
435409
#[stable(feature = "rust1", since = "1.0.0")]
436410
impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
437411
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

‎library/std/src/sys/hermit/rwlock.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ pub struct RWLock {
88
state: UnsafeCell<State>,
99
}
1010

11+
pub type MovableRWLock = Box<RWLock>;
12+
1113
enum State {
1214
Unlocked,
1315
Reading(usize),

‎library/std/src/sys/sgx/rwlock.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pub struct RWLock {
1313
writer: SpinMutex<WaitVariable<bool>>,
1414
}
1515

16+
pub type MovableRWLock = Box<RWLock>;
17+
1618
// Check at compile time that RWLock size matches C definition (see test_c_rwlock_initializer below)
1719
//
1820
// # Safety

‎library/std/src/sys/unix/os.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ use crate::str;
2020
use crate::sys::cvt;
2121
use crate::sys::fd;
2222
use crate::sys::memchr;
23-
use crate::sys::rwlock::{RWLockReadGuard, StaticRWLock};
24-
use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
23+
use crate::sys_common::rwlock::{StaticRWLock, StaticRWLockReadGuard};
2524
use crate::vec;
2625

2726
use libc::{c_char, c_int, c_void};
@@ -490,8 +489,8 @@ pub unsafe fn environ() -> *mut *const *const c_char {
490489

491490
static ENV_LOCK: StaticRWLock = StaticRWLock::new();
492491

493-
pub fn env_read_lock() -> RWLockReadGuard {
494-
ENV_LOCK.read_with_guard()
492+
pub fn env_read_lock() -> StaticRWLockReadGuard {
493+
ENV_LOCK.read()
495494
}
496495

497496
/// Returns a vector of (variable, value) byte-vector pairs for all the
@@ -551,7 +550,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
551550
let v = CString::new(v.as_bytes())?;
552551

553552
unsafe {
554-
let _guard = ENV_LOCK.write_with_guard();
553+
let _guard = ENV_LOCK.write();
555554
cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop)
556555
}
557556
}
@@ -560,7 +559,7 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
560559
let nbuf = CString::new(n.as_bytes())?;
561560

562561
unsafe {
563-
let _guard = ENV_LOCK.write_with_guard();
562+
let _guard = ENV_LOCK.write();
564563
cvt(libc::unsetenv(nbuf.as_ptr())).map(drop)
565564
}
566565
}

‎library/std/src/sys/unix/rwlock.rs

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ pub struct RWLock {
77
num_readers: AtomicUsize,
88
}
99

10+
pub type MovableRWLock = Box<RWLock>;
11+
1012
unsafe impl Send for RWLock {}
1113
unsafe impl Sync for RWLock {}
1214

@@ -139,55 +141,3 @@ impl RWLock {
139141
}
140142
}
141143
}
142-
143-
pub struct StaticRWLock(RWLock);
144-
145-
impl StaticRWLock {
146-
pub const fn new() -> StaticRWLock {
147-
StaticRWLock(RWLock::new())
148-
}
149-
150-
/// Acquires shared access to the underlying lock, blocking the current
151-
/// thread to do so.
152-
///
153-
/// The lock is automatically unlocked when the returned guard is dropped.
154-
#[inline]
155-
pub fn read_with_guard(&'static self) -> RWLockReadGuard {
156-
// SAFETY: All methods require static references, therefore self
157-
// cannot be moved between invocations.
158-
unsafe {
159-
self.0.read();
160-
}
161-
RWLockReadGuard(&self.0)
162-
}
163-
164-
/// Acquires write access to the underlying lock, blocking the current thread
165-
/// to do so.
166-
///
167-
/// The lock is automatically unlocked when the returned guard is dropped.
168-
#[inline]
169-
pub fn write_with_guard(&'static self) -> RWLockWriteGuard {
170-
// SAFETY: All methods require static references, therefore self
171-
// cannot be moved between invocations.
172-
unsafe {
173-
self.0.write();
174-
}
175-
RWLockWriteGuard(&self.0)
176-
}
177-
}
178-
179-
pub struct RWLockReadGuard(&'static RWLock);
180-
181-
impl Drop for RWLockReadGuard {
182-
fn drop(&mut self) {
183-
unsafe { self.0.read_unlock() }
184-
}
185-
}
186-
187-
pub struct RWLockWriteGuard(&'static RWLock);
188-
189-
impl Drop for RWLockWriteGuard {
190-
fn drop(&mut self) {
191-
unsafe { self.0.write_unlock() }
192-
}
193-
}

‎library/std/src/sys/unsupported/rwlock.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ pub struct RWLock {
55
mode: Cell<isize>,
66
}
77

8+
pub type MovableRWLock = RWLock;
9+
810
unsafe impl Send for RWLock {}
911
unsafe impl Sync for RWLock {} // no threads on this platform
1012

‎library/std/src/sys/wasm/atomics/rwlock.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ pub struct RWLock {
88
state: UnsafeCell<State>,
99
}
1010

11+
pub type MovableRWLock = RWLock;
12+
1113
enum State {
1214
Unlocked,
1315
Reading(usize),

‎library/std/src/sys/windows/rwlock.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ pub struct RWLock {
55
inner: UnsafeCell<c::SRWLOCK>,
66
}
77

8+
pub type MovableRWLock = RWLock;
9+
810
unsafe impl Send for RWLock {}
911
unsafe impl Sync for RWLock {}
1012

‎library/std/src/sys_common/rwlock.rs

Lines changed: 83 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,112 @@
11
use crate::sys::rwlock as imp;
22

3+
/// An OS-based reader-writer lock, meant for use in static variables.
4+
///
5+
/// This rwlock does not implement poisoning.
6+
///
7+
/// This rwlock has a const constructor ([`StaticRWLock::new`]), does not
8+
/// implement `Drop` to cleanup resources.
9+
pub struct StaticRWLock(imp::RWLock);
10+
11+
impl StaticRWLock {
12+
/// Creates a new rwlock for use.
13+
pub const fn new() -> Self {
14+
Self(imp::RWLock::new())
15+
}
16+
17+
/// Acquires shared access to the underlying lock, blocking the current
18+
/// thread to do so.
19+
///
20+
/// The lock is automatically unlocked when the returned guard is dropped.
21+
#[inline]
22+
pub fn read(&'static self) -> StaticRWLockReadGuard {
23+
unsafe { self.0.read() };
24+
StaticRWLockReadGuard(&self.0)
25+
}
26+
27+
/// Acquires write access to the underlying lock, blocking the current thread
28+
/// to do so.
29+
///
30+
/// The lock is automatically unlocked when the returned guard is dropped.
31+
#[inline]
32+
pub fn write(&'static self) -> StaticRWLockWriteGuard {
33+
unsafe { self.0.write() };
34+
StaticRWLockWriteGuard(&self.0)
35+
}
36+
}
37+
38+
#[must_use]
39+
pub struct StaticRWLockReadGuard(&'static imp::RWLock);
40+
41+
impl Drop for StaticRWLockReadGuard {
42+
#[inline]
43+
fn drop(&mut self) {
44+
unsafe {
45+
self.0.read_unlock();
46+
}
47+
}
48+
}
49+
50+
#[must_use]
51+
pub struct StaticRWLockWriteGuard(&'static imp::RWLock);
52+
53+
impl Drop for StaticRWLockWriteGuard {
54+
#[inline]
55+
fn drop(&mut self) {
56+
unsafe {
57+
self.0.write_unlock();
58+
}
59+
}
60+
}
61+
362
/// An OS-based reader-writer lock.
463
///
5-
/// This structure is entirely unsafe and serves as the lowest layer of a
6-
/// cross-platform binding of system rwlocks. It is recommended to use the
7-
/// safer types at the top level of this crate instead of this type.
8-
pub struct RWLock(imp::RWLock);
64+
/// This rwlock does *not* have a const constructor, cleans up its resources in
65+
/// its `Drop` implementation and may safely be moved (when not borrowed).
66+
///
67+
/// This rwlock does not implement poisoning.
68+
///
69+
/// This is either a wrapper around `Box<imp::RWLock>` or `imp::RWLock`,
70+
/// depending on the platform. It is boxed on platforms where `imp::RWLock` may
71+
/// not be moved.
72+
pub struct MovableRWLock(imp::MovableRWLock);
973

10-
impl RWLock {
74+
impl MovableRWLock {
1175
/// Creates a new reader-writer lock for use.
12-
///
13-
/// Behavior is undefined if the reader-writer lock is moved after it is
14-
/// first used with any of the functions below.
15-
pub const fn new() -> RWLock {
16-
RWLock(imp::RWLock::new())
76+
pub fn new() -> Self {
77+
Self(imp::MovableRWLock::from(imp::RWLock::new()))
1778
}
1879

1980
/// Acquires shared access to the underlying lock, blocking the current
2081
/// thread to do so.
21-
///
22-
/// Behavior is undefined if the rwlock has been moved between this and any
23-
/// previous method call.
2482
#[inline]
25-
pub unsafe fn read(&self) {
26-
self.0.read()
83+
pub fn read(&self) {
84+
unsafe { self.0.read() }
2785
}
2886

2987
/// Attempts to acquire shared access to this lock, returning whether it
3088
/// succeeded or not.
3189
///
3290
/// This function does not block the current thread.
33-
///
34-
/// Behavior is undefined if the rwlock has been moved between this and any
35-
/// previous method call.
3691
#[inline]
37-
pub unsafe fn try_read(&self) -> bool {
38-
self.0.try_read()
92+
pub fn try_read(&self) -> bool {
93+
unsafe { self.0.try_read() }
3994
}
4095

4196
/// Acquires write access to the underlying lock, blocking the current thread
4297
/// to do so.
43-
///
44-
/// Behavior is undefined if the rwlock has been moved between this and any
45-
/// previous method call.
4698
#[inline]
47-
pub unsafe fn write(&self) {
48-
self.0.write()
99+
pub fn write(&self) {
100+
unsafe { self.0.write() }
49101
}
50102

51103
/// Attempts to acquire exclusive access to this lock, returning whether it
52104
/// succeeded or not.
53105
///
54106
/// This function does not block the current thread.
55-
///
56-
/// Behavior is undefined if the rwlock has been moved between this and any
57-
/// previous method call.
58107
#[inline]
59-
pub unsafe fn try_write(&self) -> bool {
60-
self.0.try_write()
108+
pub fn try_write(&self) -> bool {
109+
unsafe { self.0.try_write() }
61110
}
62111

63112
/// Unlocks previously acquired shared access to this lock.
@@ -76,13 +125,10 @@ impl RWLock {
76125
pub unsafe fn write_unlock(&self) {
77126
self.0.write_unlock()
78127
}
128+
}
79129

80-
/// Destroys OS-related resources with this RWLock.
81-
///
82-
/// Behavior is undefined if there are any currently active users of this
83-
/// lock.
84-
#[inline]
85-
pub unsafe fn destroy(&self) {
86-
self.0.destroy()
130+
impl Drop for MovableRWLock {
131+
fn drop(&mut self) {
132+
unsafe { self.0.destroy() };
87133
}
88134
}

0 commit comments

Comments
 (0)
Please sign in to comment.