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