]> git.lizzy.rs Git - rust.git/blob - library/std/src/sys/hermit/rwlock.rs
Rollup merge of #101573 - lcnr:param-kind-ord, r=BoxyUwU
[rust.git] / library / std / src / sys / hermit / rwlock.rs
1 use crate::cell::UnsafeCell;
2 use crate::sys::locks::{MovableCondvar, Mutex};
3
4 pub struct RwLock {
5     lock: Mutex,
6     cond: MovableCondvar,
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 {
32             lock: Mutex::new(),
33             cond: MovableCondvar::new(),
34             state: UnsafeCell::new(State::Unlocked),
35         }
36     }
37
38     #[inline]
39     pub unsafe fn read(&self) {
40         self.lock.lock();
41         while !(*self.state.get()).inc_readers() {
42             self.cond.wait(&self.lock);
43         }
44         self.lock.unlock();
45     }
46
47     #[inline]
48     pub unsafe fn try_read(&self) -> bool {
49         self.lock.lock();
50         let ok = (*self.state.get()).inc_readers();
51         self.lock.unlock();
52         return ok;
53     }
54
55     #[inline]
56     pub unsafe fn write(&self) {
57         self.lock.lock();
58         while !(*self.state.get()).inc_writers() {
59             self.cond.wait(&self.lock);
60         }
61         self.lock.unlock();
62     }
63
64     #[inline]
65     pub unsafe fn try_write(&self) -> bool {
66         self.lock.lock();
67         let ok = (*self.state.get()).inc_writers();
68         self.lock.unlock();
69         return ok;
70     }
71
72     #[inline]
73     pub unsafe fn read_unlock(&self) {
74         self.lock.lock();
75         let notify = (*self.state.get()).dec_readers();
76         self.lock.unlock();
77         if notify {
78             // FIXME: should only wake up one of these some of the time
79             self.cond.notify_all();
80         }
81     }
82
83     #[inline]
84     pub unsafe fn write_unlock(&self) {
85         self.lock.lock();
86         (*self.state.get()).dec_writers();
87         self.lock.unlock();
88         // FIXME: should only wake up one of these some of the time
89         self.cond.notify_all();
90     }
91 }
92
93 impl State {
94     fn inc_readers(&mut self) -> bool {
95         match *self {
96             State::Unlocked => {
97                 *self = State::Reading(1);
98                 true
99             }
100             State::Reading(ref mut cnt) => {
101                 *cnt += 1;
102                 true
103             }
104             State::Writing => false,
105         }
106     }
107
108     fn inc_writers(&mut self) -> bool {
109         match *self {
110             State::Unlocked => {
111                 *self = State::Writing;
112                 true
113             }
114             State::Reading(_) | State::Writing => false,
115         }
116     }
117
118     fn dec_readers(&mut self) -> bool {
119         let zero = match *self {
120             State::Reading(ref mut cnt) => {
121                 *cnt -= 1;
122                 *cnt == 0
123             }
124             State::Unlocked | State::Writing => invalid(),
125         };
126         if zero {
127             *self = State::Unlocked;
128         }
129         zero
130     }
131
132     fn dec_writers(&mut self) {
133         match *self {
134             State::Writing => {}
135             State::Unlocked | State::Reading(_) => invalid(),
136         }
137         *self = State::Unlocked;
138     }
139 }
140
141 fn invalid() -> ! {
142     panic!("inconsistent rwlock");
143 }