]> git.proxmox.com Git - rustc.git/blob - src/libstd/sys/common/poison.rs
New upstream version 1.12.0+dfsg1
[rustc.git] / src / libstd / sys / common / poison.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use error::{Error};
12 use fmt;
13 use marker::Reflect;
14 use sync::atomic::{AtomicBool, Ordering};
15 use thread;
16
17 pub struct Flag { failed: AtomicBool }
18
19 // Note that the Ordering uses to access the `failed` field of `Flag` below is
20 // always `Relaxed`, and that's because this isn't actually protecting any data,
21 // it's just a flag whether we've panicked or not.
22 //
23 // The actual location that this matters is when a mutex is **locked** which is
24 // where we have external synchronization ensuring that we see memory
25 // reads/writes to this flag.
26 //
27 // As a result, if it matters, we should see the correct value for `failed` in
28 // all cases.
29
30 impl Flag {
31 pub const fn new() -> Flag {
32 Flag { failed: AtomicBool::new(false) }
33 }
34
35 #[inline]
36 pub fn borrow(&self) -> LockResult<Guard> {
37 let ret = Guard { panicking: thread::panicking() };
38 if self.get() {
39 Err(PoisonError::new(ret))
40 } else {
41 Ok(ret)
42 }
43 }
44
45 #[inline]
46 pub fn done(&self, guard: &Guard) {
47 if !guard.panicking && thread::panicking() {
48 self.failed.store(true, Ordering::Relaxed);
49 }
50 }
51
52 #[inline]
53 pub fn get(&self) -> bool {
54 self.failed.load(Ordering::Relaxed)
55 }
56 }
57
58 pub struct Guard {
59 panicking: bool,
60 }
61
62 /// A type of error which can be returned whenever a lock is acquired.
63 ///
64 /// Both Mutexes and RwLocks are poisoned whenever a thread fails while the lock
65 /// is held. The precise semantics for when a lock is poisoned is documented on
66 /// each lock, but once a lock is poisoned then all future acquisitions will
67 /// return this error.
68 #[stable(feature = "rust1", since = "1.0.0")]
69 pub struct PoisonError<T> {
70 guard: T,
71 }
72
73 /// An enumeration of possible errors which can occur while calling the
74 /// `try_lock` method.
75 #[stable(feature = "rust1", since = "1.0.0")]
76 pub enum TryLockError<T> {
77 /// The lock could not be acquired because another thread failed while holding
78 /// the lock.
79 #[stable(feature = "rust1", since = "1.0.0")]
80 Poisoned(#[stable(feature = "rust1", since = "1.0.0")] PoisonError<T>),
81 /// The lock could not be acquired at this time because the operation would
82 /// otherwise block.
83 #[stable(feature = "rust1", since = "1.0.0")]
84 WouldBlock,
85 }
86
87 /// A type alias for the result of a lock method which can be poisoned.
88 ///
89 /// The `Ok` variant of this result indicates that the primitive was not
90 /// poisoned, and the `Guard` is contained within. The `Err` variant indicates
91 /// that the primitive was poisoned. Note that the `Err` variant *also* carries
92 /// the associated guard, and it can be acquired through the `into_inner`
93 /// method.
94 #[stable(feature = "rust1", since = "1.0.0")]
95 pub type LockResult<Guard> = Result<Guard, PoisonError<Guard>>;
96
97 /// A type alias for the result of a nonblocking locking method.
98 ///
99 /// For more information, see `LockResult`. A `TryLockResult` doesn't
100 /// necessarily hold the associated guard in the `Err` type as the lock may not
101 /// have been acquired for other reasons.
102 #[stable(feature = "rust1", since = "1.0.0")]
103 pub type TryLockResult<Guard> = Result<Guard, TryLockError<Guard>>;
104
105 #[stable(feature = "rust1", since = "1.0.0")]
106 impl<T> fmt::Debug for PoisonError<T> {
107 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108 "PoisonError { inner: .. }".fmt(f)
109 }
110 }
111
112 #[stable(feature = "rust1", since = "1.0.0")]
113 impl<T> fmt::Display for PoisonError<T> {
114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115 "poisoned lock: another task failed inside".fmt(f)
116 }
117 }
118
119 #[stable(feature = "rust1", since = "1.0.0")]
120 impl<T: Reflect> Error for PoisonError<T> {
121 fn description(&self) -> &str {
122 "poisoned lock: another task failed inside"
123 }
124 }
125
126 impl<T> PoisonError<T> {
127 /// Creates a `PoisonError`.
128 #[stable(feature = "sync_poison", since = "1.2.0")]
129 pub fn new(guard: T) -> PoisonError<T> {
130 PoisonError { guard: guard }
131 }
132
133 /// Consumes this error indicating that a lock is poisoned, returning the
134 /// underlying guard to allow access regardless.
135 #[stable(feature = "sync_poison", since = "1.2.0")]
136 pub fn into_inner(self) -> T { self.guard }
137
138 /// Reaches into this error indicating that a lock is poisoned, returning a
139 /// reference to the underlying guard to allow access regardless.
140 #[stable(feature = "sync_poison", since = "1.2.0")]
141 pub fn get_ref(&self) -> &T { &self.guard }
142
143 /// Reaches into this error indicating that a lock is poisoned, returning a
144 /// mutable reference to the underlying guard to allow access regardless.
145 #[stable(feature = "sync_poison", since = "1.2.0")]
146 pub fn get_mut(&mut self) -> &mut T { &mut self.guard }
147 }
148
149 #[stable(feature = "rust1", since = "1.0.0")]
150 impl<T> From<PoisonError<T>> for TryLockError<T> {
151 fn from(err: PoisonError<T>) -> TryLockError<T> {
152 TryLockError::Poisoned(err)
153 }
154 }
155
156 #[stable(feature = "rust1", since = "1.0.0")]
157 impl<T> fmt::Debug for TryLockError<T> {
158 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159 match *self {
160 TryLockError::Poisoned(..) => "Poisoned(..)".fmt(f),
161 TryLockError::WouldBlock => "WouldBlock".fmt(f)
162 }
163 }
164 }
165
166 #[stable(feature = "rust1", since = "1.0.0")]
167 impl<T> fmt::Display for TryLockError<T> {
168 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169 match *self {
170 TryLockError::Poisoned(..) => "poisoned lock: another task failed inside",
171 TryLockError::WouldBlock => "try_lock failed because the operation would block"
172 }.fmt(f)
173 }
174 }
175
176 #[stable(feature = "rust1", since = "1.0.0")]
177 impl<T: Reflect> Error for TryLockError<T> {
178 fn description(&self) -> &str {
179 match *self {
180 TryLockError::Poisoned(ref p) => p.description(),
181 TryLockError::WouldBlock => "try_lock failed because the operation would block"
182 }
183 }
184
185 fn cause(&self) -> Option<&Error> {
186 match *self {
187 TryLockError::Poisoned(ref p) => Some(p),
188 _ => None
189 }
190 }
191 }
192
193 pub fn map_result<T, U, F>(result: LockResult<T>, f: F)
194 -> LockResult<U>
195 where F: FnOnce(T) -> U {
196 match result {
197 Ok(t) => Ok(f(t)),
198 Err(PoisonError { guard }) => Err(PoisonError::new(f(guard)))
199 }
200 }