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