]> git.proxmox.com Git - rustc.git/blame - src/libstd/sys/wasm/rwlock_atomics.rs
New upstream version 1.34.2+dfsg1
[rustc.git] / src / libstd / sys / wasm / rwlock_atomics.rs
CommitLineData
0bf4aa26
XL
1use cell::UnsafeCell;
2use sys::mutex::Mutex;
3use sys::condvar::Condvar;
4
5pub struct RWLock {
6 lock: Mutex,
7 cond: Condvar,
8 state: UnsafeCell<State>,
9}
10
11enum State {
12 Unlocked,
13 Reading(usize),
14 Writing,
15}
16
17unsafe impl Send for RWLock {}
18unsafe 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
28impl RWLock {
29 pub const fn new() -> RWLock {
30 RWLock {
31 lock: Mutex::new(),
32 cond: Condvar::new(),
33 state: UnsafeCell::new(State::Unlocked),
34 }
35 }
36
37 #[inline]
38 pub unsafe fn read(&self) {
39 self.lock.lock();
40 while !(*self.state.get()).inc_readers() {
41 self.cond.wait(&self.lock);
42 }
43 self.lock.unlock();
44 }
45
46 #[inline]
47 pub unsafe fn try_read(&self) -> bool {
48 self.lock.lock();
49 let ok = (*self.state.get()).inc_readers();
50 self.lock.unlock();
51 return ok
52 }
53
54 #[inline]
55 pub unsafe fn write(&self) {
56 self.lock.lock();
57 while !(*self.state.get()).inc_writers() {
58 self.cond.wait(&self.lock);
59 }
60 self.lock.unlock();
61 }
62
63 #[inline]
64 pub unsafe fn try_write(&self) -> bool {
65 self.lock.lock();
66 let ok = (*self.state.get()).inc_writers();
67 self.lock.unlock();
68 return ok
69 }
70
71 #[inline]
72 pub unsafe fn read_unlock(&self) {
73 self.lock.lock();
74 let notify = (*self.state.get()).dec_readers();
75 self.lock.unlock();
76 if notify {
77 // FIXME: should only wake up one of these some of the time
78 self.cond.notify_all();
79 }
80 }
81
82 #[inline]
83 pub unsafe fn write_unlock(&self) {
84 self.lock.lock();
85 (*self.state.get()).dec_writers();
86 self.lock.unlock();
87 // FIXME: should only wake up one of these some of the time
88 self.cond.notify_all();
89 }
90
91 #[inline]
92 pub unsafe fn destroy(&self) {
93 self.lock.destroy();
94 self.cond.destroy();
95 }
96}
97
98impl State {
99 fn inc_readers(&mut self) -> bool {
100 match *self {
101 State::Unlocked => {
102 *self = State::Reading(1);
103 true
104 }
105 State::Reading(ref mut cnt) => {
106 *cnt += 1;
107 true
108 }
109 State::Writing => false
110 }
111 }
112
113 fn inc_writers(&mut self) -> bool {
114 match *self {
115 State::Unlocked => {
116 *self = State::Writing;
117 true
118 }
119 State::Reading(_) |
120 State::Writing => false
121 }
122 }
123
124 fn dec_readers(&mut self) -> bool {
125 let zero = match *self {
126 State::Reading(ref mut cnt) => {
127 *cnt -= 1;
128 *cnt == 0
129 }
130 State::Unlocked |
131 State::Writing => invalid(),
132 };
133 if zero {
134 *self = State::Unlocked;
135 }
136 zero
137 }
138
139 fn dec_writers(&mut self) {
140 match *self {
141 State::Writing => {}
142 State::Unlocked |
143 State::Reading(_) => invalid(),
144 }
145 *self = State::Unlocked;
146 }
147}
148
149fn invalid() -> ! {
150 panic!("inconsistent rwlock");
151}