]> git.proxmox.com Git - rustc.git/blob - library/std/src/sys/hermit/rwlock.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / library / std / src / sys / hermit / rwlock.rs
1 use crate::cell::UnsafeCell;
2 use crate::sys::locks::{MovableCondvar, Mutex};
3 use crate::sys_common::lazy_box::{LazyBox, LazyInit};
4
5 pub struct RwLock {
6 lock: Mutex,
7 cond: MovableCondvar,
8 state: UnsafeCell<State>,
9 }
10
11 pub type MovableRwLock = 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 {
33 lock: Mutex::new(),
34 cond: MovableCondvar::new(),
35 state: UnsafeCell::new(State::Unlocked),
36 }
37 }
38
39 #[inline]
40 pub unsafe fn read(&self) {
41 self.lock.lock();
42 while !(*self.state.get()).inc_readers() {
43 self.cond.wait(&self.lock);
44 }
45 self.lock.unlock();
46 }
47
48 #[inline]
49 pub unsafe fn try_read(&self) -> bool {
50 self.lock.lock();
51 let ok = (*self.state.get()).inc_readers();
52 self.lock.unlock();
53 return ok;
54 }
55
56 #[inline]
57 pub unsafe fn write(&self) {
58 self.lock.lock();
59 while !(*self.state.get()).inc_writers() {
60 self.cond.wait(&self.lock);
61 }
62 self.lock.unlock();
63 }
64
65 #[inline]
66 pub unsafe fn try_write(&self) -> bool {
67 self.lock.lock();
68 let ok = (*self.state.get()).inc_writers();
69 self.lock.unlock();
70 return ok;
71 }
72
73 #[inline]
74 pub unsafe fn read_unlock(&self) {
75 self.lock.lock();
76 let notify = (*self.state.get()).dec_readers();
77 self.lock.unlock();
78 if notify {
79 // FIXME: should only wake up one of these some of the time
80 self.cond.notify_all();
81 }
82 }
83
84 #[inline]
85 pub unsafe fn write_unlock(&self) {
86 self.lock.lock();
87 (*self.state.get()).dec_writers();
88 self.lock.unlock();
89 // FIXME: should only wake up one of these some of the time
90 self.cond.notify_all();
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 }