]> git.lizzy.rs Git - rust.git/blob - src/libstd/sync/mutex.rs
Auto merge of #28957 - GuillaumeGomez:patch-5, r=Manishearth
[rust.git] / src / libstd / sync / mutex.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 prelude::v1::*;
12
13 use cell::UnsafeCell;
14 use fmt;
15 use marker;
16 use mem;
17 use ops::{Deref, DerefMut};
18 use ptr;
19 use sys_common::mutex as sys;
20 use sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
21
22 /// A mutual exclusion primitive useful for protecting shared data
23 ///
24 /// This mutex will block threads waiting for the lock to become available. The
25 /// mutex can also be statically initialized or created via a `new`
26 /// constructor. Each mutex has a type parameter which represents the data that
27 /// it is protecting. The data can only be accessed through the RAII guards
28 /// returned from `lock` and `try_lock`, which guarantees that the data is only
29 /// ever accessed when the mutex is locked.
30 ///
31 /// # Poisoning
32 ///
33 /// The mutexes in this module implement a strategy called "poisoning" where a
34 /// mutex is considered poisoned whenever a thread panics while holding the
35 /// lock. Once a mutex is poisoned, all other threads are unable to access the
36 /// data by default as it is likely tainted (some invariant is not being
37 /// upheld).
38 ///
39 /// For a mutex, this means that the `lock` and `try_lock` methods return a
40 /// `Result` which indicates whether a mutex has been poisoned or not. Most
41 /// usage of a mutex will simply `unwrap()` these results, propagating panics
42 /// among threads to ensure that a possibly invalid invariant is not witnessed.
43 ///
44 /// A poisoned mutex, however, does not prevent all access to the underlying
45 /// data. The `PoisonError` type has an `into_inner` method which will return
46 /// the guard that would have otherwise been returned on a successful lock. This
47 /// allows access to the data, despite the lock being poisoned.
48 ///
49 /// # Examples
50 ///
51 /// ```
52 /// use std::sync::{Arc, Mutex};
53 /// use std::thread;
54 /// use std::sync::mpsc::channel;
55 ///
56 /// const N: usize = 10;
57 ///
58 /// // Spawn a few threads to increment a shared variable (non-atomically), and
59 /// // let the main thread know once all increments are done.
60 /// //
61 /// // Here we're using an Arc to share memory among threads, and the data inside
62 /// // the Arc is protected with a mutex.
63 /// let data = Arc::new(Mutex::new(0));
64 ///
65 /// let (tx, rx) = channel();
66 /// for _ in 0..10 {
67 ///     let (data, tx) = (data.clone(), tx.clone());
68 ///     thread::spawn(move || {
69 ///         // The shared static can only be accessed once the lock is held.
70 ///         // Our non-atomic increment is safe because we're the only thread
71 ///         // which can access the shared state when the lock is held.
72 ///         //
73 ///         // We unwrap() the return value to assert that we are not expecting
74 ///         // threads to ever fail while holding the lock.
75 ///         let mut data = data.lock().unwrap();
76 ///         *data += 1;
77 ///         if *data == N {
78 ///             tx.send(()).unwrap();
79 ///         }
80 ///         // the lock is unlocked here when `data` goes out of scope.
81 ///     });
82 /// }
83 ///
84 /// rx.recv().unwrap();
85 /// ```
86 ///
87 /// To recover from a poisoned mutex:
88 ///
89 /// ```
90 /// use std::sync::{Arc, Mutex};
91 /// use std::thread;
92 ///
93 /// let lock = Arc::new(Mutex::new(0_u32));
94 /// let lock2 = lock.clone();
95 ///
96 /// let _ = thread::spawn(move || -> () {
97 ///     // This thread will acquire the mutex first, unwrapping the result of
98 ///     // `lock` because the lock has not been poisoned.
99 ///     let _lock = lock2.lock().unwrap();
100 ///
101 ///     // This panic while holding the lock (`_guard` is in scope) will poison
102 ///     // the mutex.
103 ///     panic!();
104 /// }).join();
105 ///
106 /// // The lock is poisoned by this point, but the returned result can be
107 /// // pattern matched on to return the underlying guard on both branches.
108 /// let mut guard = match lock.lock() {
109 ///     Ok(guard) => guard,
110 ///     Err(poisoned) => poisoned.into_inner(),
111 /// };
112 ///
113 /// *guard += 1;
114 /// ```
115 #[stable(feature = "rust1", since = "1.0.0")]
116 pub struct Mutex<T: ?Sized> {
117     // Note that this static mutex is in a *box*, not inlined into the struct
118     // itself. Once a native mutex has been used once, its address can never
119     // change (it can't be moved). This mutex type can be safely moved at any
120     // time, so to ensure that the native mutex is used correctly we box the
121     // inner lock to give it a constant address.
122     inner: Box<StaticMutex>,
123     data: UnsafeCell<T>,
124 }
125
126 // these are the only places where `T: Send` matters; all other
127 // functionality works fine on a single thread.
128 unsafe impl<T: ?Sized + Send> Send for Mutex<T> { }
129
130 unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { }
131
132 /// The static mutex type is provided to allow for static allocation of mutexes.
133 ///
134 /// Note that this is a separate type because using a Mutex correctly means that
135 /// it needs to have a destructor run. In Rust, statics are not allowed to have
136 /// destructors. As a result, a `StaticMutex` has one extra method when compared
137 /// to a `Mutex`, a `destroy` method. This method is unsafe to call, and
138 /// documentation can be found directly on the method.
139 ///
140 /// # Examples
141 ///
142 /// ```
143 /// #![feature(static_mutex)]
144 ///
145 /// use std::sync::{StaticMutex, MUTEX_INIT};
146 ///
147 /// static LOCK: StaticMutex = MUTEX_INIT;
148 ///
149 /// {
150 ///     let _g = LOCK.lock().unwrap();
151 ///     // do some productive work
152 /// }
153 /// // lock is unlocked here.
154 /// ```
155 #[unstable(feature = "static_mutex",
156            reason = "may be merged with Mutex in the future",
157            issue = "27717")]
158 pub struct StaticMutex {
159     lock: sys::Mutex,
160     poison: poison::Flag,
161 }
162
163 /// An RAII implementation of a "scoped lock" of a mutex. When this structure is
164 /// dropped (falls out of scope), the lock will be unlocked.
165 ///
166 /// The data protected by the mutex can be access through this guard via its
167 /// `Deref` and `DerefMut` implementations
168 #[must_use]
169 #[stable(feature = "rust1", since = "1.0.0")]
170 pub struct MutexGuard<'a, T: ?Sized + 'a> {
171     // funny underscores due to how Deref/DerefMut currently work (they
172     // disregard field privacy).
173     __lock: &'a StaticMutex,
174     __data: &'a UnsafeCell<T>,
175     __poison: poison::Guard,
176 }
177
178 impl<'a, T: ?Sized> !marker::Send for MutexGuard<'a, T> {}
179
180 /// Static initialization of a mutex. This constant can be used to initialize
181 /// other mutex constants.
182 #[unstable(feature = "static_mutex",
183            reason = "may be merged with Mutex in the future",
184            issue = "27717")]
185 pub const MUTEX_INIT: StaticMutex = StaticMutex::new();
186
187 impl<T> Mutex<T> {
188     /// Creates a new mutex in an unlocked state ready for use.
189     #[stable(feature = "rust1", since = "1.0.0")]
190     pub fn new(t: T) -> Mutex<T> {
191         Mutex {
192             inner: box StaticMutex::new(),
193             data: UnsafeCell::new(t),
194         }
195     }
196 }
197
198 impl<T: ?Sized> Mutex<T> {
199     /// Acquires a mutex, blocking the current thread until it is able to do so.
200     ///
201     /// This function will block the local thread until it is available to acquire
202     /// the mutex. Upon returning, the thread is the only thread with the mutex
203     /// held. An RAII guard is returned to allow scoped unlock of the lock. When
204     /// the guard goes out of scope, the mutex will be unlocked.
205     ///
206     /// # Failure
207     ///
208     /// If another user of this mutex panicked while holding the mutex, then
209     /// this call will return an error once the mutex is acquired.
210     #[stable(feature = "rust1", since = "1.0.0")]
211     pub fn lock(&self) -> LockResult<MutexGuard<T>> {
212         unsafe { self.inner.lock.lock() }
213         MutexGuard::new(&*self.inner, &self.data)
214     }
215
216     /// Attempts to acquire this lock.
217     ///
218     /// If the lock could not be acquired at this time, then `Err` is returned.
219     /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
220     /// guard is dropped.
221     ///
222     /// This function does not block.
223     ///
224     /// # Failure
225     ///
226     /// If another user of this mutex panicked while holding the mutex, then
227     /// this call will return failure if the mutex would otherwise be
228     /// acquired.
229     #[stable(feature = "rust1", since = "1.0.0")]
230     pub fn try_lock(&self) -> TryLockResult<MutexGuard<T>> {
231         if unsafe { self.inner.lock.try_lock() } {
232             Ok(try!(MutexGuard::new(&*self.inner, &self.data)))
233         } else {
234             Err(TryLockError::WouldBlock)
235         }
236     }
237
238     /// Determines whether the lock is poisoned.
239     ///
240     /// If another thread is active, the lock can still become poisoned at any
241     /// time.  You should not trust a `false` value for program correctness
242     /// without additional synchronization.
243     #[inline]
244     #[stable(feature = "sync_poison", since = "1.2.0")]
245     pub fn is_poisoned(&self) -> bool {
246         self.inner.poison.get()
247     }
248
249     /// Consumes this mutex, returning the underlying data.
250     ///
251     /// # Failure
252     ///
253     /// If another user of this mutex panicked while holding the mutex, then
254     /// this call will return an error instead.
255     #[unstable(feature = "mutex_into_inner", reason = "recently added", issue = "28968")]
256     pub fn into_inner(self) -> LockResult<T> where T: Sized {
257         // We know statically that there are no outstanding references to
258         // `self` so there's no need to lock the inner StaticMutex.
259         //
260         // To get the inner value, we'd like to call `data.into_inner()`,
261         // but because `Mutex` impl-s `Drop`, we can't move out of it, so
262         // we'll have to destructure it manually instead.
263         unsafe {
264             // Like `let Mutex { inner, data } = self`.
265             let (inner, data) = {
266                 let Mutex { ref inner, ref data } = self;
267                 (ptr::read(inner), ptr::read(data))
268             };
269             mem::forget(self);
270             inner.lock.destroy();  // Keep in sync with the `Drop` impl.
271
272             poison::map_result(inner.poison.borrow(), |_| data.into_inner())
273         }
274     }
275
276     /// Returns a mutable reference to the underlying data.
277     ///
278     /// Since this call borrows the `Mutex` mutably, no actual locking needs to
279     /// take place---the mutable borrow statically guarantees no locks exist.
280     ///
281     /// # Failure
282     ///
283     /// If another user of this mutex panicked while holding the mutex, then
284     /// this call will return an error instead.
285     #[unstable(feature = "mutex_get_mut", reason = "recently added", issue = "28968")]
286     pub fn get_mut(&mut self) -> LockResult<&mut T> {
287         // We know statically that there are no other references to `self`, so
288         // there's no need to lock the inner StaticMutex.
289         let data = unsafe { &mut *self.data.get() };
290         poison::map_result(self.inner.poison.borrow(), |_| data )
291     }
292 }
293
294 #[stable(feature = "rust1", since = "1.0.0")]
295 impl<T: ?Sized> Drop for Mutex<T> {
296     fn drop(&mut self) {
297         // This is actually safe b/c we know that there is no further usage of
298         // this mutex (it's up to the user to arrange for a mutex to get
299         // dropped, that's not our job)
300         //
301         // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`.
302         unsafe { self.inner.lock.destroy() }
303     }
304 }
305
306 #[stable(feature = "rust1", since = "1.0.0")]
307 impl<T: ?Sized + fmt::Debug + 'static> fmt::Debug for Mutex<T> {
308     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
309         match self.try_lock() {
310             Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", &*guard),
311             Err(TryLockError::Poisoned(err)) => {
312                 write!(f, "Mutex {{ data: Poisoned({:?}) }}", &**err.get_ref())
313             },
314             Err(TryLockError::WouldBlock) => write!(f, "Mutex {{ <locked> }}")
315         }
316     }
317 }
318
319 struct Dummy(UnsafeCell<()>);
320 unsafe impl Sync for Dummy {}
321 static DUMMY: Dummy = Dummy(UnsafeCell::new(()));
322
323 #[unstable(feature = "static_mutex",
324            reason = "may be merged with Mutex in the future",
325            issue = "27717")]
326 impl StaticMutex {
327     /// Creates a new mutex in an unlocked state ready for use.
328     pub const fn new() -> StaticMutex {
329         StaticMutex {
330             lock: sys::Mutex::new(),
331             poison: poison::Flag::new(),
332         }
333     }
334
335     /// Acquires this lock, see `Mutex::lock`
336     #[inline]
337     pub fn lock(&'static self) -> LockResult<MutexGuard<()>> {
338         unsafe { self.lock.lock() }
339         MutexGuard::new(self, &DUMMY.0)
340     }
341
342     /// Attempts to grab this lock, see `Mutex::try_lock`
343     #[inline]
344     pub fn try_lock(&'static self) -> TryLockResult<MutexGuard<()>> {
345         if unsafe { self.lock.try_lock() } {
346             Ok(try!(MutexGuard::new(self, &DUMMY.0)))
347         } else {
348             Err(TryLockError::WouldBlock)
349         }
350     }
351
352     /// Deallocates resources associated with this static mutex.
353     ///
354     /// This method is unsafe because it provides no guarantees that there are
355     /// no active users of this mutex, and safety is not guaranteed if there are
356     /// active users of this mutex.
357     ///
358     /// This method is required to ensure that there are no memory leaks on
359     /// *all* platforms. It may be the case that some platforms do not leak
360     /// memory if this method is not called, but this is not guaranteed to be
361     /// true on all platforms.
362     pub unsafe fn destroy(&'static self) {
363         self.lock.destroy()
364     }
365 }
366
367 impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> {
368
369     fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell<T>)
370            -> LockResult<MutexGuard<'mutex, T>> {
371         poison::map_result(lock.poison.borrow(), |guard| {
372             MutexGuard {
373                 __lock: lock,
374                 __data: data,
375                 __poison: guard,
376             }
377         })
378     }
379 }
380
381 #[stable(feature = "rust1", since = "1.0.0")]
382 impl<'mutex, T: ?Sized> Deref for MutexGuard<'mutex, T> {
383     type Target = T;
384
385     fn deref(&self) -> &T {
386         unsafe { &*self.__data.get() }
387     }
388 }
389
390 #[stable(feature = "rust1", since = "1.0.0")]
391 impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> {
392     fn deref_mut(&mut self) -> &mut T {
393         unsafe { &mut *self.__data.get() }
394     }
395 }
396
397 #[stable(feature = "rust1", since = "1.0.0")]
398 impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
399     #[inline]
400     fn drop(&mut self) {
401         unsafe {
402             self.__lock.poison.done(&self.__poison);
403             self.__lock.lock.unlock();
404         }
405     }
406 }
407
408 pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
409     &guard.__lock.lock
410 }
411
412 pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
413     &guard.__lock.poison
414 }
415
416 #[cfg(test)]
417 mod tests {
418     use prelude::v1::*;
419
420     use sync::mpsc::channel;
421     use sync::{Arc, Mutex, StaticMutex, Condvar};
422     use sync::atomic::{AtomicUsize, Ordering};
423     use thread;
424
425     struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
426
427     #[derive(Eq, PartialEq, Debug)]
428     struct NonCopy(i32);
429
430     unsafe impl<T: Send> Send for Packet<T> {}
431     unsafe impl<T> Sync for Packet<T> {}
432
433     #[test]
434     fn smoke() {
435         let m = Mutex::new(());
436         drop(m.lock().unwrap());
437         drop(m.lock().unwrap());
438     }
439
440     #[test]
441     fn smoke_static() {
442         static M: StaticMutex = StaticMutex::new();
443         unsafe {
444             drop(M.lock().unwrap());
445             drop(M.lock().unwrap());
446             M.destroy();
447         }
448     }
449
450     #[test]
451     fn lots_and_lots() {
452         static M: StaticMutex = StaticMutex::new();
453         static mut CNT: u32 = 0;
454         const J: u32 = 1000;
455         const K: u32 = 3;
456
457         fn inc() {
458             for _ in 0..J {
459                 unsafe {
460                     let _g = M.lock().unwrap();
461                     CNT += 1;
462                 }
463             }
464         }
465
466         let (tx, rx) = channel();
467         for _ in 0..K {
468             let tx2 = tx.clone();
469             thread::spawn(move|| { inc(); tx2.send(()).unwrap(); });
470             let tx2 = tx.clone();
471             thread::spawn(move|| { inc(); tx2.send(()).unwrap(); });
472         }
473
474         drop(tx);
475         for _ in 0..2 * K {
476             rx.recv().unwrap();
477         }
478         assert_eq!(unsafe {CNT}, J * K * 2);
479         unsafe {
480             M.destroy();
481         }
482     }
483
484     #[test]
485     fn try_lock() {
486         let m = Mutex::new(());
487         *m.try_lock().unwrap() = ();
488     }
489
490     #[test]
491     fn test_into_inner() {
492         let m = Mutex::new(NonCopy(10));
493         assert_eq!(m.into_inner().unwrap(), NonCopy(10));
494     }
495
496     #[test]
497     fn test_into_inner_drop() {
498         struct Foo(Arc<AtomicUsize>);
499         impl Drop for Foo {
500             fn drop(&mut self) {
501                 self.0.fetch_add(1, Ordering::SeqCst);
502             }
503         }
504         let num_drops = Arc::new(AtomicUsize::new(0));
505         let m = Mutex::new(Foo(num_drops.clone()));
506         assert_eq!(num_drops.load(Ordering::SeqCst), 0);
507         {
508             let _inner = m.into_inner().unwrap();
509             assert_eq!(num_drops.load(Ordering::SeqCst), 0);
510         }
511         assert_eq!(num_drops.load(Ordering::SeqCst), 1);
512     }
513
514     #[test]
515     fn test_into_inner_poison() {
516         let m = Arc::new(Mutex::new(NonCopy(10)));
517         let m2 = m.clone();
518         let _ = thread::spawn(move || {
519             let _lock = m2.lock().unwrap();
520             panic!("test panic in inner thread to poison mutex");
521         }).join();
522
523         assert!(m.is_poisoned());
524         match Arc::try_unwrap(m).unwrap().into_inner() {
525             Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
526             Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x),
527         }
528     }
529
530     #[test]
531     fn test_get_mut() {
532         let mut m = Mutex::new(NonCopy(10));
533         *m.get_mut().unwrap() = NonCopy(20);
534         assert_eq!(m.into_inner().unwrap(), NonCopy(20));
535     }
536
537     #[test]
538     fn test_get_mut_poison() {
539         let m = Arc::new(Mutex::new(NonCopy(10)));
540         let m2 = m.clone();
541         let _ = thread::spawn(move || {
542             let _lock = m2.lock().unwrap();
543             panic!("test panic in inner thread to poison mutex");
544         }).join();
545
546         assert!(m.is_poisoned());
547         match Arc::try_unwrap(m).unwrap().get_mut() {
548             Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
549             Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x),
550         }
551     }
552
553     #[test]
554     fn test_mutex_arc_condvar() {
555         let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
556         let packet2 = Packet(packet.0.clone());
557         let (tx, rx) = channel();
558         let _t = thread::spawn(move|| {
559             // wait until parent gets in
560             rx.recv().unwrap();
561             let &(ref lock, ref cvar) = &*packet2.0;
562             let mut lock = lock.lock().unwrap();
563             *lock = true;
564             cvar.notify_one();
565         });
566
567         let &(ref lock, ref cvar) = &*packet.0;
568         let mut lock = lock.lock().unwrap();
569         tx.send(()).unwrap();
570         assert!(!*lock);
571         while !*lock {
572             lock = cvar.wait(lock).unwrap();
573         }
574     }
575
576     #[test]
577     fn test_arc_condvar_poison() {
578         let packet = Packet(Arc::new((Mutex::new(1), Condvar::new())));
579         let packet2 = Packet(packet.0.clone());
580         let (tx, rx) = channel();
581
582         let _t = thread::spawn(move || -> () {
583             rx.recv().unwrap();
584             let &(ref lock, ref cvar) = &*packet2.0;
585             let _g = lock.lock().unwrap();
586             cvar.notify_one();
587             // Parent should fail when it wakes up.
588             panic!();
589         });
590
591         let &(ref lock, ref cvar) = &*packet.0;
592         let mut lock = lock.lock().unwrap();
593         tx.send(()).unwrap();
594         while *lock == 1 {
595             match cvar.wait(lock) {
596                 Ok(l) => {
597                     lock = l;
598                     assert_eq!(*lock, 1);
599                 }
600                 Err(..) => break,
601             }
602         }
603     }
604
605     #[test]
606     fn test_mutex_arc_poison() {
607         let arc = Arc::new(Mutex::new(1));
608         assert!(!arc.is_poisoned());
609         let arc2 = arc.clone();
610         let _ = thread::spawn(move|| {
611             let lock = arc2.lock().unwrap();
612             assert_eq!(*lock, 2);
613         }).join();
614         assert!(arc.lock().is_err());
615         assert!(arc.is_poisoned());
616     }
617
618     #[test]
619     fn test_mutex_arc_nested() {
620         // Tests nested mutexes and access
621         // to underlying data.
622         let arc = Arc::new(Mutex::new(1));
623         let arc2 = Arc::new(Mutex::new(arc));
624         let (tx, rx) = channel();
625         let _t = thread::spawn(move|| {
626             let lock = arc2.lock().unwrap();
627             let lock2 = lock.lock().unwrap();
628             assert_eq!(*lock2, 1);
629             tx.send(()).unwrap();
630         });
631         rx.recv().unwrap();
632     }
633
634     #[test]
635     fn test_mutex_arc_access_in_unwind() {
636         let arc = Arc::new(Mutex::new(1));
637         let arc2 = arc.clone();
638         let _ = thread::spawn(move|| -> () {
639             struct Unwinder {
640                 i: Arc<Mutex<i32>>,
641             }
642             impl Drop for Unwinder {
643                 fn drop(&mut self) {
644                     *self.i.lock().unwrap() += 1;
645                 }
646             }
647             let _u = Unwinder { i: arc2 };
648             panic!();
649         }).join();
650         let lock = arc.lock().unwrap();
651         assert_eq!(*lock, 2);
652     }
653
654     #[test]
655     fn test_mutex_unsized() {
656         let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
657         {
658             let b = &mut *mutex.lock().unwrap();
659             b[0] = 4;
660             b[2] = 5;
661         }
662         let comp: &[i32] = &[4, 2, 5];
663         assert_eq!(&*mutex.lock().unwrap(), comp);
664     }
665 }