]> git.lizzy.rs Git - rust.git/blob - src/librustrt/exclusive.rs
Implement generalized object and type parameter bounds (Fixes #16462)
[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 /// stage0 only
30 #[cfg(stage0)]
31 pub struct ExclusiveGuard<'a, T> {
32     // FIXME #12808: strange name to try to avoid interfering with
33     // field accesses of the contained type via Deref
34     _data: &'a mut T,
35     _guard: mutex::LockGuard<'a>,
36 }
37
38 /// An RAII guard returned via `lock`
39 #[cfg(not(stage0))]
40 pub struct ExclusiveGuard<'a, T:'a> {
41     // FIXME #12808: strange name to try to avoid interfering with
42     // field accesses of the contained type via Deref
43     _data: &'a mut T,
44     _guard: mutex::LockGuard<'a>,
45 }
46
47 impl<T: Send> Exclusive<T> {
48     /// Creates a new `Exclusive` which will protect the data provided.
49     pub fn new(user_data: T) -> Exclusive<T> {
50         Exclusive {
51             lock: unsafe { mutex::NativeMutex::new() },
52             data: UnsafeCell::new(user_data),
53         }
54     }
55
56     /// Acquires this lock, returning a guard which the data is accessed through
57     /// and from which that lock will be unlocked.
58     ///
59     /// This method is unsafe due to many of the same reasons that the
60     /// NativeMutex itself is unsafe.
61     pub unsafe fn lock<'a>(&'a self) -> ExclusiveGuard<'a, T> {
62         let guard = self.lock.lock();
63         let data = &mut *self.data.get();
64
65         ExclusiveGuard {
66             _data: data,
67             _guard: guard,
68         }
69     }
70 }
71
72 impl<'a, T: Send> ExclusiveGuard<'a, T> {
73     // The unsafety here should be ok because our loan guarantees that the lock
74     // itself is not moving
75     pub fn signal(&self) {
76         unsafe { self._guard.signal() }
77     }
78     pub fn wait(&self) {
79         unsafe { self._guard.wait() }
80     }
81 }
82
83 impl<'a, T: Send> Deref<T> for ExclusiveGuard<'a, T> {
84     fn deref<'a>(&'a self) -> &'a T { &*self._data }
85 }
86 impl<'a, T: Send> DerefMut<T> for ExclusiveGuard<'a, T> {
87     fn deref_mut<'a>(&'a mut self) -> &'a mut T { &mut *self._data }
88 }
89
90 #[cfg(test)]
91 mod tests {
92     use std::prelude::*;
93     use alloc::arc::Arc;
94     use super::Exclusive;
95     use std::task;
96
97     #[test]
98     fn exclusive_new_arc() {
99         unsafe {
100             let mut futures = Vec::new();
101
102             let num_tasks = 10;
103             let count = 10;
104
105             let total = Arc::new(Exclusive::new(box 0));
106
107             for _ in range(0u, num_tasks) {
108                 let total = total.clone();
109                 let (tx, rx) = channel();
110                 futures.push(rx);
111
112                 task::spawn(proc() {
113                     for _ in range(0u, count) {
114                         **total.lock() += 1;
115                     }
116                     tx.send(());
117                 });
118             };
119
120             for f in futures.mut_iter() { f.recv() }
121
122             assert_eq!(**total.lock(), num_tasks * count);
123         }
124     }
125 }