Skip to content

Commit a8c2d4f

Browse files
committed
Move boxing and mutex checking logic of condvar into sys_common.
1 parent f283d3f commit a8c2d4f

File tree

4 files changed

+55
-78
lines changed

4 files changed

+55
-78
lines changed

library/std/src/sync/condvar.rs

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22
mod tests;
33

44
use crate::fmt;
5-
use crate::sync::atomic::{AtomicUsize, Ordering};
65
use crate::sync::{mutex, MutexGuard, PoisonError};
76
use crate::sys_common::condvar as sys;
8-
use crate::sys_common::mutex as sys_mutex;
97
use crate::sys_common::poison::{self, LockResult};
108
use crate::time::{Duration, Instant};
119

@@ -109,8 +107,7 @@ impl WaitTimeoutResult {
109107
/// ```
110108
#[stable(feature = "rust1", since = "1.0.0")]
111109
pub struct Condvar {
112-
inner: Box<sys::Condvar>,
113-
mutex: AtomicUsize,
110+
inner: sys::Condvar,
114111
}
115112

116113
impl Condvar {
@@ -126,11 +123,7 @@ impl Condvar {
126123
/// ```
127124
#[stable(feature = "rust1", since = "1.0.0")]
128125
pub fn new() -> Condvar {
129-
let mut c = Condvar { inner: box sys::Condvar::new(), mutex: AtomicUsize::new(0) };
130-
unsafe {
131-
c.inner.init();
132-
}
133-
c
126+
Condvar { inner: sys::Condvar::new() }
134127
}
135128

136129
/// Blocks the current thread until this condition variable receives a
@@ -192,7 +185,6 @@ impl Condvar {
192185
pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> LockResult<MutexGuard<'a, T>> {
193186
let poisoned = unsafe {
194187
let lock = mutex::guard_lock(&guard);
195-
self.verify(lock);
196188
self.inner.wait(lock);
197189
mutex::guard_poison(&guard).get()
198190
};
@@ -389,7 +381,6 @@ impl Condvar {
389381
) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
390382
let (poisoned, result) = unsafe {
391383
let lock = mutex::guard_lock(&guard);
392-
self.verify(lock);
393384
let success = self.inner.wait_timeout(lock, dur);
394385
(mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success))
395386
};
@@ -510,7 +501,7 @@ impl Condvar {
510501
/// ```
511502
#[stable(feature = "rust1", since = "1.0.0")]
512503
pub fn notify_one(&self) {
513-
unsafe { self.inner.notify_one() }
504+
self.inner.notify_one()
514505
}
515506

516507
/// Wakes up all blocked threads on this condvar.
@@ -550,27 +541,7 @@ impl Condvar {
550541
/// ```
551542
#[stable(feature = "rust1", since = "1.0.0")]
552543
pub fn notify_all(&self) {
553-
unsafe { self.inner.notify_all() }
554-
}
555-
556-
fn verify(&self, mutex: &sys_mutex::MovableMutex) {
557-
let addr = mutex.raw() as *const _ as usize;
558-
match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) {
559-
// If we got out 0, then we have successfully bound the mutex to
560-
// this cvar.
561-
0 => {}
562-
563-
// If we get out a value that's the same as `addr`, then someone
564-
// already beat us to the punch.
565-
n if n == addr => {}
566-
567-
// Anything else and we're using more than one mutex on this cvar,
568-
// which is currently disallowed.
569-
_ => panic!(
570-
"attempted to use a condition variable with two \
571-
mutexes"
572-
),
573-
}
544+
self.inner.notify_all()
574545
}
575546
}
576547

@@ -588,10 +559,3 @@ impl Default for Condvar {
588559
Condvar::new()
589560
}
590561
}
591-
592-
#[stable(feature = "rust1", since = "1.0.0")]
593-
impl Drop for Condvar {
594-
fn drop(&mut self) {
595-
unsafe { self.inner.destroy() }
596-
}
597-
}

library/std/src/sys_common/condvar.rs

Lines changed: 27 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,62 @@
11
use crate::sys::condvar as imp;
22
use crate::sys_common::mutex::MovableMutex;
33
use crate::time::Duration;
4+
use check::CondvarCheck;
5+
6+
mod check;
47

58
/// An OS-based condition variable.
6-
///
7-
/// This structure is the lowest layer possible on top of the OS-provided
8-
/// condition variables. It is consequently entirely unsafe to use. It is
9-
/// recommended to use the safer types at the top level of this crate instead of
10-
/// this type.
11-
pub struct Condvar(imp::Condvar);
9+
pub struct Condvar {
10+
inner: Box<imp::Condvar>,
11+
check: CondvarCheck,
12+
}
1213

1314
impl Condvar {
1415
/// Creates a new condition variable for use.
15-
///
16-
/// Behavior is undefined if the condition variable is moved after it is
17-
/// first used with any of the functions below.
18-
pub const fn new() -> Condvar {
19-
Condvar(imp::Condvar::new())
20-
}
21-
22-
/// Prepares the condition variable for use.
23-
///
24-
/// This should be called once the condition variable is at a stable memory
25-
/// address.
26-
#[inline]
27-
pub unsafe fn init(&mut self) {
28-
self.0.init()
16+
pub fn new() -> Self {
17+
let mut c = box imp::Condvar::new();
18+
unsafe { c.init() };
19+
Self { inner: c, check: CondvarCheck::new() }
2920
}
3021

3122
/// Signals one waiter on this condition variable to wake up.
3223
#[inline]
33-
pub unsafe fn notify_one(&self) {
34-
self.0.notify_one()
24+
pub fn notify_one(&self) {
25+
unsafe { self.inner.notify_one() };
3526
}
3627

3728
/// Awakens all current waiters on this condition variable.
3829
#[inline]
39-
pub unsafe fn notify_all(&self) {
40-
self.0.notify_all()
30+
pub fn notify_all(&self) {
31+
unsafe { self.inner.notify_all() };
4132
}
4233

4334
/// Waits for a signal on the specified mutex.
4435
///
4536
/// Behavior is undefined if the mutex is not locked by the current thread.
46-
/// Behavior is also undefined if more than one mutex is used concurrently
47-
/// on this condition variable.
37+
///
38+
/// May panic if used with more than one mutex.
4839
#[inline]
4940
pub unsafe fn wait(&self, mutex: &MovableMutex) {
50-
self.0.wait(mutex.raw())
41+
self.check.verify(mutex);
42+
self.inner.wait(mutex.raw())
5143
}
5244

5345
/// Waits for a signal on the specified mutex with a timeout duration
5446
/// specified by `dur` (a relative time into the future).
5547
///
5648
/// Behavior is undefined if the mutex is not locked by the current thread.
57-
/// Behavior is also undefined if more than one mutex is used concurrently
58-
/// on this condition variable.
49+
///
50+
/// May panic if used with more than one mutex.
5951
#[inline]
6052
pub unsafe fn wait_timeout(&self, mutex: &MovableMutex, dur: Duration) -> bool {
61-
self.0.wait_timeout(mutex.raw(), dur)
53+
self.check.verify(mutex);
54+
self.inner.wait_timeout(mutex.raw(), dur)
6255
}
56+
}
6357

64-
/// Deallocates all resources associated with this condition variable.
65-
///
66-
/// Behavior is undefined if there are current or will be future users of
67-
/// this condition variable.
68-
#[inline]
69-
pub unsafe fn destroy(&self) {
70-
self.0.destroy()
58+
impl Drop for Condvar {
59+
fn drop(&mut self) {
60+
unsafe { self.inner.destroy() };
7161
}
7262
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use crate::sync::atomic::{AtomicUsize, Ordering};
2+
use crate::sys::mutex as mutex_imp;
3+
use crate::sys_common::mutex::MovableMutex;
4+
5+
/// A `Condvar` will check it's only ever used with the same mutex, based on
6+
/// its (stable) address.
7+
pub struct CondvarCheck {
8+
addr: AtomicUsize,
9+
}
10+
11+
impl CondvarCheck {
12+
pub const fn new() -> Self {
13+
Self { addr: AtomicUsize::new(0) }
14+
}
15+
pub fn verify(&self, mutex: &MovableMutex) {
16+
let addr = mutex.raw() as *const mutex_imp::Mutex as usize;
17+
match self.addr.compare_and_swap(0, addr, Ordering::SeqCst) {
18+
0 => {} // Stored the address
19+
n if n == addr => {} // Lost a race to store the same address
20+
_ => panic!("attempted to use a condition variable with two mutexes"),
21+
}
22+
}
23+
}

library/std/src/sys_common/mutex.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ impl MovableMutex {
7272
Self(mutex)
7373
}
7474

75-
pub(crate) fn raw(&self) -> &imp::Mutex {
75+
pub(super) fn raw(&self) -> &imp::Mutex {
7676
&self.0
7777
}
7878

0 commit comments

Comments
 (0)