]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/cloudabi/mutex.rs
Rollup merge of #61120 - spastorino:eval-place-iterate, r=oli-obk
[rust.git] / src / libstd / sys / cloudabi / mutex.rs
1 use crate::cell::UnsafeCell;
2 use crate::mem;
3 use crate::sync::atomic::{AtomicU32, Ordering};
4 use crate::sys::cloudabi::abi;
5 use crate::sys::rwlock::{self, RWLock};
6
7 extern "C" {
8     #[thread_local]
9     static __pthread_thread_id: abi::tid;
10 }
11
12 // Implement Mutex using an RWLock. This doesn't introduce any
13 // performance overhead in this environment, as the operations would be
14 // implemented identically.
15 pub struct Mutex(RWLock);
16
17 pub unsafe fn raw(m: &Mutex) -> *mut AtomicU32 {
18     rwlock::raw(&m.0)
19 }
20
21 impl Mutex {
22     pub const fn new() -> Mutex {
23         Mutex(RWLock::new())
24     }
25
26     pub unsafe fn init(&mut self) {
27         // This function should normally reinitialize the mutex after
28         // moving it to a different memory address. This implementation
29         // does not require adjustments after moving.
30     }
31
32     pub unsafe fn try_lock(&self) -> bool {
33         self.0.try_write()
34     }
35
36     pub unsafe fn lock(&self) {
37         self.0.write()
38     }
39
40     pub unsafe fn unlock(&self) {
41         self.0.write_unlock()
42     }
43
44     pub unsafe fn destroy(&self) {
45         self.0.destroy()
46     }
47 }
48
49 pub struct ReentrantMutex {
50     lock: UnsafeCell<AtomicU32>,
51     recursion: UnsafeCell<u32>,
52 }
53
54 impl ReentrantMutex {
55     pub unsafe fn uninitialized() -> ReentrantMutex {
56         mem::uninitialized()
57     }
58
59     pub unsafe fn init(&mut self) {
60         self.lock = UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0));
61         self.recursion = UnsafeCell::new(0);
62     }
63
64     pub unsafe fn try_lock(&self) -> bool {
65         // Attempt to acquire the lock.
66         let lock = self.lock.get();
67         let recursion = self.recursion.get();
68         if let Err(old) = (*lock).compare_exchange(
69             abi::LOCK_UNLOCKED.0,
70             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
71             Ordering::Acquire,
72             Ordering::Relaxed,
73         ) {
74             // If we fail to acquire the lock, it may be the case
75             // that we've already acquired it and may need to recurse.
76             if old & !abi::LOCK_KERNEL_MANAGED.0 == __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 {
77                 *recursion += 1;
78                 true
79             } else {
80                 false
81             }
82         } else {
83             // Success.
84             assert_eq!(*recursion, 0, "Mutex has invalid recursion count");
85             true
86         }
87     }
88
89     pub unsafe fn lock(&self) {
90         if !self.try_lock() {
91             // Call into the kernel to acquire a write lock.
92             let lock = self.lock.get();
93             let subscription = abi::subscription {
94                 type_: abi::eventtype::LOCK_WRLOCK,
95                 union: abi::subscription_union {
96                     lock: abi::subscription_lock {
97                         lock: lock as *mut abi::lock,
98                         lock_scope: abi::scope::PRIVATE,
99                     },
100                 },
101                 ..mem::zeroed()
102             };
103             let mut event: abi::event = mem::uninitialized();
104             let mut nevents: usize = mem::uninitialized();
105             let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
106             assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire mutex");
107             assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire mutex");
108         }
109     }
110
111     pub unsafe fn unlock(&self) {
112         let lock = self.lock.get();
113         let recursion = self.recursion.get();
114         assert_eq!(
115             (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
116             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
117             "This mutex is locked by a different thread"
118         );
119
120         if *recursion > 0 {
121             *recursion -= 1;
122         } else if !(*lock)
123             .compare_exchange(
124                 __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
125                 abi::LOCK_UNLOCKED.0,
126                 Ordering::Release,
127                 Ordering::Relaxed,
128             )
129             .is_ok()
130         {
131             // Lock is managed by kernelspace. Call into the kernel
132             // to unblock waiting threads.
133             let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
134             assert_eq!(ret, abi::errno::SUCCESS, "Failed to unlock a mutex");
135         }
136     }
137
138     pub unsafe fn destroy(&self) {
139         let lock = self.lock.get();
140         let recursion = self.recursion.get();
141         assert_eq!(
142             (*lock).load(Ordering::Relaxed),
143             abi::LOCK_UNLOCKED.0,
144             "Attempted to destroy locked mutex"
145         );
146         assert_eq!(*recursion, 0, "Recursion counter invalid");
147     }
148 }