Skip to content

Commit d4f9ec5

Browse files
committed
Auto merge of #21565 - kmcallister:poison, r=alexcrichton
I needed these to implement efficient poisoning in [seqloq](https://github.com/kmcallister/seqloq/tree/poison).
2 parents cdaf3a4 + 7324c2c commit d4f9ec5

File tree

4 files changed

+40
-12
lines changed

4 files changed

+40
-12
lines changed

src/libstd/sync/condvar.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use sys::time::SteadyTime;
1616
use sys_common::condvar as sys;
1717
use sys_common::mutex as sys_mutex;
1818
use time::Duration;
19-
use sync::{mutex, MutexGuard};
19+
use sync::{mutex, MutexGuard, PoisonError};
2020

2121
/// A Condition Variable
2222
///
@@ -228,7 +228,7 @@ impl StaticCondvar {
228228
mutex::guard_poison(&guard).get()
229229
};
230230
if poisoned {
231-
Err(poison::new_poison_error(guard))
231+
Err(PoisonError::new(guard))
232232
} else {
233233
Ok(guard)
234234
}
@@ -249,7 +249,7 @@ impl StaticCondvar {
249249
(mutex::guard_poison(&guard).get(), success)
250250
};
251251
if poisoned {
252-
Err(poison::new_poison_error((guard, success)))
252+
Err(PoisonError::new((guard, success)))
253253
} else {
254254
Ok((guard, success))
255255
}
@@ -276,23 +276,23 @@ impl StaticCondvar {
276276
while !f(guard_result
277277
.as_mut()
278278
.map(|g| &mut **g)
279-
.map_err(|e| poison::new_poison_error(&mut **e.get_mut()))) {
279+
.map_err(|e| PoisonError::new(&mut **e.get_mut()))) {
280280
let now = SteadyTime::now();
281281
let consumed = &now - &start;
282282
let guard = guard_result.unwrap_or_else(|e| e.into_inner());
283283
let (new_guard_result, no_timeout) = match self.wait_timeout(guard, dur - consumed) {
284284
Ok((new_guard, no_timeout)) => (Ok(new_guard), no_timeout),
285285
Err(err) => {
286286
let (new_guard, no_timeout) = err.into_inner();
287-
(Err(poison::new_poison_error(new_guard)), no_timeout)
287+
(Err(PoisonError::new(new_guard)), no_timeout)
288288
}
289289
};
290290
guard_result = new_guard_result;
291291
if !no_timeout {
292292
let result = f(guard_result
293293
.as_mut()
294294
.map(|g| &mut **g)
295-
.map_err(|e| poison::new_poison_error(&mut **e.get_mut())));
295+
.map_err(|e| PoisonError::new(&mut **e.get_mut())));
296296
return poison::map_result(guard_result, |g| (g, result));
297297
}
298298
}

src/libstd/sync/mutex.rs

+13
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,17 @@ impl<T: Send> Mutex<T> {
228228
Err(TryLockError::WouldBlock)
229229
}
230230
}
231+
232+
/// Determine whether the lock is poisoned.
233+
///
234+
/// If another thread is active, the lock can still become poisoned at any
235+
/// time. You should not trust a `false` value for program correctness
236+
/// without additional synchronization.
237+
#[inline]
238+
#[unstable(feature = "std_misc")]
239+
pub fn is_poisoned(&self) -> bool {
240+
self.inner.poison.get()
241+
}
231242
}
232243

233244
#[unsafe_destructor]
@@ -458,12 +469,14 @@ mod test {
458469
#[test]
459470
fn test_mutex_arc_poison() {
460471
let arc = Arc::new(Mutex::new(1));
472+
assert!(!arc.is_poisoned());
461473
let arc2 = arc.clone();
462474
let _ = Thread::scoped(move|| {
463475
let lock = arc2.lock().unwrap();
464476
assert_eq!(*lock, 2);
465477
}).join();
466478
assert!(arc.lock().is_err());
479+
assert!(arc.is_poisoned());
467480
}
468481

469482
#[test]

src/libstd/sync/poison.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ impl Flag {
2323
pub fn borrow(&self) -> LockResult<Guard> {
2424
let ret = Guard { panicking: Thread::panicking() };
2525
if unsafe { *self.failed.get() } {
26-
Err(new_poison_error(ret))
26+
Err(PoisonError::new(ret))
2727
} else {
2828
Ok(ret)
2929
}
@@ -110,6 +110,12 @@ impl<T> Error for PoisonError<T> {
110110
}
111111

112112
impl<T> PoisonError<T> {
113+
/// Create a `PoisonError`.
114+
#[unstable(feature = "std_misc")]
115+
pub fn new(guard: T) -> PoisonError<T> {
116+
PoisonError { guard: guard }
117+
}
118+
113119
/// Consumes this error indicating that a lock is poisoned, returning the
114120
/// underlying guard to allow access regardless.
115121
#[unstable(feature = "std_misc")]
@@ -171,15 +177,11 @@ impl<T> Error for TryLockError<T> {
171177
}
172178
}
173179

174-
pub fn new_poison_error<T>(guard: T) -> PoisonError<T> {
175-
PoisonError { guard: guard }
176-
}
177-
178180
pub fn map_result<T, U, F>(result: LockResult<T>, f: F)
179181
-> LockResult<U>
180182
where F: FnOnce(T) -> U {
181183
match result {
182184
Ok(t) => Ok(f(t)),
183-
Err(PoisonError { guard }) => Err(new_poison_error(f(guard)))
185+
Err(PoisonError { guard }) => Err(PoisonError::new(f(guard)))
184186
}
185187
}

src/libstd/sync/rwlock.rs

+13
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,17 @@ impl<T: Send + Sync> RwLock<T> {
237237
Err(TryLockError::WouldBlock)
238238
}
239239
}
240+
241+
/// Determine whether the lock is poisoned.
242+
///
243+
/// If another thread is active, the lock can still become poisoned at any
244+
/// time. You should not trust a `false` value for program correctness
245+
/// without additional synchronization.
246+
#[inline]
247+
#[unstable(feature = "std_misc")]
248+
pub fn is_poisoned(&self) -> bool {
249+
self.inner.poison.get()
250+
}
240251
}
241252

242253
#[unsafe_destructor]
@@ -451,12 +462,14 @@ mod tests {
451462
#[test]
452463
fn test_rw_arc_poison_ww() {
453464
let arc = Arc::new(RwLock::new(1));
465+
assert!(!arc.is_poisoned());
454466
let arc2 = arc.clone();
455467
let _: Result<uint, _> = Thread::scoped(move|| {
456468
let _lock = arc2.write().unwrap();
457469
panic!();
458470
}).join();
459471
assert!(arc.write().is_err());
472+
assert!(arc.is_poisoned());
460473
}
461474

462475
#[test]

0 commit comments

Comments
 (0)