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