]> git.lizzy.rs Git - rust.git/blob - src/librustrt/exclusive.rs
auto merge of #16802 : nick29581/rust/dst-bug-1, r=luqmana
[rust.git] / src / librustrt / exclusive.rs
1 // Copyright 2013 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 core::prelude::*;
12
13 use core::cell::UnsafeCell;
14 use mutex;
15
16 /// An OS mutex over some data.
17 ///
18 /// This is not a safe primitive to use, it is unaware of the libgreen
19 /// scheduler, as well as being easily susceptible to misuse due to the usage of
20 /// the inner NativeMutex.
21 ///
22 /// > **Note**: This type is not recommended for general use. The mutex provided
23 /// >           as part of `libsync` should almost always be favored.
24 pub struct Exclusive<T> {
25     lock: mutex::NativeMutex,
26     data: UnsafeCell<T>,
27 }
28
29 /// An RAII guard returned via `lock`
30 pub struct ExclusiveGuard<'a, T:'a> {
31     // FIXME #12808: strange name to try to avoid interfering with
32     // field accesses of the contained type via Deref
33     _data: &'a mut T,
34     _guard: mutex::LockGuard<'a>,
35 }
36
37 impl<T: Send> Exclusive<T> {
38     /// Creates a new `Exclusive` which will protect the data provided.
39     pub fn new(user_data: T) -> Exclusive<T> {
40         Exclusive {
41             lock: unsafe { mutex::NativeMutex::new() },
42             data: UnsafeCell::new(user_data),
43         }
44     }
45
46     /// Acquires this lock, returning a guard which the data is accessed through
47     /// and from which that lock will be unlocked.
48     ///
49     /// This method is unsafe due to many of the same reasons that the
50     /// NativeMutex itself is unsafe.
51     pub unsafe fn lock<'a>(&'a self) -> ExclusiveGuard<'a, T> {
52         let guard = self.lock.lock();
53         let data = &mut *self.data.get();
54
55         ExclusiveGuard {
56             _data: data,
57             _guard: guard,
58         }
59     }
60 }
61
62 impl<'a, T: Send> ExclusiveGuard<'a, T> {
63     // The unsafety here should be ok because our loan guarantees that the lock
64     // itself is not moving
65     pub fn signal(&self) {
66         unsafe { self._guard.signal() }
67     }
68     pub fn wait(&self) {
69         unsafe { self._guard.wait() }
70     }
71 }
72
73 impl<'a, T: Send> Deref<T> for ExclusiveGuard<'a, T> {
74     fn deref<'a>(&'a self) -> &'a T { &*self._data }
75 }
76 impl<'a, T: Send> DerefMut<T> for ExclusiveGuard<'a, T> {
77     fn deref_mut<'a>(&'a mut self) -> &'a mut T { &mut *self._data }
78 }
79
80 #[cfg(test)]
81 mod tests {
82     use std::prelude::*;
83     use alloc::arc::Arc;
84     use super::Exclusive;
85     use std::task;
86
87     #[test]
88     fn exclusive_new_arc() {
89         unsafe {
90             let mut futures = Vec::new();
91
92             let num_tasks = 10;
93             let count = 10;
94
95             let total = Arc::new(Exclusive::new(box 0));
96
97             for _ in range(0u, num_tasks) {
98                 let total = total.clone();
99                 let (tx, rx) = channel();
100                 futures.push(rx);
101
102                 task::spawn(proc() {
103                     for _ in range(0u, count) {
104                         **total.lock() += 1;
105                     }
106                     tx.send(());
107                 });
108             };
109
110             for f in futures.mut_iter() { f.recv() }
111
112             assert_eq!(**total.lock(), num_tasks * count);
113         }
114     }
115 }