]> git.lizzy.rs Git - rust.git/blob - library/std/src/sys/hermit/rwlock.rs
Rollup merge of #97436 - compiler-errors:macos-ping-2, r=Mark-Simulacrum
[rust.git] / library / std / src / sys / hermit / rwlock.rs
1 use crate::cell::UnsafeCell;
2 use crate::sys::locks::{Condvar, Mutex};
3
4 pub struct RwLock {
5     lock: Mutex,
6     cond: Condvar,
7     state: UnsafeCell<State>,
8 }
9
10 pub type MovableRwLock = RwLock;
11
12 enum State {
13     Unlocked,
14     Reading(usize),
15     Writing,
16 }
17
18 unsafe impl Send for RwLock {}
19 unsafe impl Sync for RwLock {}
20
21 // This rwlock implementation is a relatively simple implementation which has a
22 // condition variable for readers/writers as well as a mutex protecting the
23 // internal state of the lock. A current downside of the implementation is that
24 // unlocking the lock will notify *all* waiters rather than just readers or just
25 // writers. This can cause lots of "thundering stampede" problems. While
26 // hopefully correct this implementation is very likely to want to be changed in
27 // the future.
28
29 impl RwLock {
30     pub const fn new() -> RwLock {
31         RwLock { lock: Mutex::new(), cond: Condvar::new(), state: UnsafeCell::new(State::Unlocked) }
32     }
33
34     #[inline]
35     pub unsafe fn read(&self) {
36         self.lock.lock();
37         while !(*self.state.get()).inc_readers() {
38             self.cond.wait(&self.lock);
39         }
40         self.lock.unlock();
41     }
42
43     #[inline]
44     pub unsafe fn try_read(&self) -> bool {
45         self.lock.lock();
46         let ok = (*self.state.get()).inc_readers();
47         self.lock.unlock();
48         return ok;
49     }
50
51     #[inline]
52     pub unsafe fn write(&self) {
53         self.lock.lock();
54         while !(*self.state.get()).inc_writers() {
55             self.cond.wait(&self.lock);
56         }
57         self.lock.unlock();
58     }
59
60     #[inline]
61     pub unsafe fn try_write(&self) -> bool {
62         self.lock.lock();
63         let ok = (*self.state.get()).inc_writers();
64         self.lock.unlock();
65         return ok;
66     }
67
68     #[inline]
69     pub unsafe fn read_unlock(&self) {
70         self.lock.lock();
71         let notify = (*self.state.get()).dec_readers();
72         self.lock.unlock();
73         if notify {
74             // FIXME: should only wake up one of these some of the time
75             self.cond.notify_all();
76         }
77     }
78
79     #[inline]
80     pub unsafe fn write_unlock(&self) {
81         self.lock.lock();
82         (*self.state.get()).dec_writers();
83         self.lock.unlock();
84         // FIXME: should only wake up one of these some of the time
85         self.cond.notify_all();
86     }
87
88     #[inline]
89     pub unsafe fn destroy(&self) {
90         self.lock.destroy();
91         self.cond.destroy();
92     }
93 }
94
95 impl State {
96     fn inc_readers(&mut self) -> bool {
97         match *self {
98             State::Unlocked => {
99                 *self = State::Reading(1);
100                 true
101             }
102             State::Reading(ref mut cnt) => {
103                 *cnt += 1;
104                 true
105             }
106             State::Writing => false,
107         }
108     }
109
110     fn inc_writers(&mut self) -> bool {
111         match *self {
112             State::Unlocked => {
113                 *self = State::Writing;
114                 true
115             }
116             State::Reading(_) | State::Writing => false,
117         }
118     }
119
120     fn dec_readers(&mut self) -> bool {
121         let zero = match *self {
122             State::Reading(ref mut cnt) => {
123                 *cnt -= 1;
124                 *cnt == 0
125             }
126             State::Unlocked | State::Writing => invalid(),
127         };
128         if zero {
129             *self = State::Unlocked;
130         }
131         zero
132     }
133
134     fn dec_writers(&mut self) {
135         match *self {
136             State::Writing => {}
137             State::Unlocked | State::Reading(_) => invalid(),
138         }
139         *self = State::Unlocked;
140     }
141 }
142
143 fn invalid() -> ! {
144     panic!("inconsistent rwlock");
145 }