Skip to content

Commit 363e4f5

Browse files
authored
Rollup merge of rust-lang#72954 - hermitcore:rwlock, r=dtolnay
revise RwLock for HermitCore - current version is derived from the wasm implementation - increasing the readability of `Condvar` - simplify the interface to the libos
2 parents 9008693 + 6925ebd commit 363e4f5

File tree

4 files changed

+142
-43
lines changed

4 files changed

+142
-43
lines changed

Cargo.lock

+2-2
Original file line numberDiff line numberDiff line change
@@ -1242,9 +1242,9 @@ dependencies = [
12421242

12431243
[[package]]
12441244
name = "hermit-abi"
1245-
version = "0.1.14"
1245+
version = "0.1.15"
12461246
source = "registry+https://github.com/rust-lang/crates.io-index"
1247-
checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909"
1247+
checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
12481248
dependencies = [
12491249
"compiler_builtins",
12501250
"libc",

src/libstd/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
4040
fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
4141

4242
[target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies]
43-
hermit-abi = { version = "0.1.14", features = ['rustc-dep-of-std'] }
43+
hermit-abi = { version = "0.1.15", features = ['rustc-dep-of-std'] }
4444

4545
[target.wasm32-wasi.dependencies]
4646
wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }

src/libstd/sys/hermit/condvar.rs

+34-30
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,64 @@
1-
use crate::cmp;
1+
use crate::ffi::c_void;
2+
use crate::ptr;
3+
use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
24
use crate::sys::hermit::abi;
35
use crate::sys::mutex::Mutex;
46
use crate::time::Duration;
57

8+
// The implementation is inspired by Andrew D. Birrell's paper
9+
// "Implementing Condition Variables with Semaphores"
10+
611
pub struct Condvar {
7-
identifier: usize,
12+
counter: AtomicUsize,
13+
sem1: *const c_void,
14+
sem2: *const c_void,
815
}
916

17+
unsafe impl Send for Condvar {}
18+
unsafe impl Sync for Condvar {}
19+
1020
impl Condvar {
1121
pub const fn new() -> Condvar {
12-
Condvar { identifier: 0 }
22+
Condvar { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() }
1323
}
1424

1525
pub unsafe fn init(&mut self) {
16-
let _ = abi::init_queue(self.id());
26+
let _ = abi::sem_init(&mut self.sem1 as *mut *const c_void, 0);
27+
let _ = abi::sem_init(&mut self.sem2 as *mut *const c_void, 0);
1728
}
1829

1930
pub unsafe fn notify_one(&self) {
20-
let _ = abi::notify(self.id(), 1);
31+
if self.counter.load(SeqCst) > 0 {
32+
self.counter.fetch_sub(1, SeqCst);
33+
abi::sem_post(self.sem1);
34+
abi::sem_timedwait(self.sem2, 0);
35+
}
2136
}
2237

23-
#[inline]
2438
pub unsafe fn notify_all(&self) {
25-
let _ = abi::notify(self.id(), -1 /* =all */);
39+
let counter = self.counter.swap(0, SeqCst);
40+
for _ in 0..counter {
41+
abi::sem_post(self.sem1);
42+
}
43+
for _ in 0..counter {
44+
abi::sem_timedwait(self.sem2, 0);
45+
}
2646
}
2747

2848
pub unsafe fn wait(&self, mutex: &Mutex) {
29-
// add current task to the wait queue
30-
let _ = abi::add_queue(self.id(), -1 /* no timeout */);
49+
self.counter.fetch_add(1, SeqCst);
3150
mutex.unlock();
32-
let _ = abi::wait(self.id());
51+
abi::sem_timedwait(self.sem1, 0);
52+
abi::sem_post(self.sem2);
3353
mutex.lock();
3454
}
3555

36-
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
37-
let nanos = dur.as_nanos();
38-
let nanos = cmp::min(i64::MAX as u128, nanos);
39-
40-
// add current task to the wait queue
41-
let _ = abi::add_queue(self.id(), nanos as i64);
42-
43-
mutex.unlock();
44-
// If the return value is !0 then a timeout happened, so we return
45-
// `false` as we weren't actually notified.
46-
let ret = abi::wait(self.id()) == 0;
47-
mutex.lock();
48-
49-
ret
56+
pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
57+
panic!("wait_timeout not supported on hermit");
5058
}
5159

5260
pub unsafe fn destroy(&self) {
53-
let _ = abi::destroy_queue(self.id());
54-
}
55-
56-
#[inline]
57-
fn id(&self) -> usize {
58-
&self.identifier as *const usize as usize
61+
let _ = abi::sem_destroy(self.sem1);
62+
let _ = abi::sem_destroy(self.sem2);
5963
}
6064
}

src/libstd/sys/hermit/rwlock.rs

+105-10
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,144 @@
1-
use super::mutex::Mutex;
1+
use crate::cell::UnsafeCell;
2+
use crate::sys::condvar::Condvar;
3+
use crate::sys::mutex::Mutex;
24

35
pub struct RWLock {
4-
mutex: Mutex,
6+
lock: Mutex,
7+
cond: Condvar,
8+
state: UnsafeCell<State>,
9+
}
10+
11+
enum State {
12+
Unlocked,
13+
Reading(usize),
14+
Writing,
515
}
616

717
unsafe impl Send for RWLock {}
818
unsafe impl Sync for RWLock {}
919

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+
1028
impl RWLock {
1129
pub const fn new() -> RWLock {
12-
RWLock { mutex: Mutex::new() }
30+
RWLock { lock: Mutex::new(), cond: Condvar::new(), state: UnsafeCell::new(State::Unlocked) }
1331
}
1432

1533
#[inline]
1634
pub unsafe fn read(&self) {
17-
self.mutex.lock();
35+
self.lock.lock();
36+
while !(*self.state.get()).inc_readers() {
37+
self.cond.wait(&self.lock);
38+
}
39+
self.lock.unlock();
1840
}
1941

2042
#[inline]
2143
pub unsafe fn try_read(&self) -> bool {
22-
self.mutex.try_lock()
44+
self.lock.lock();
45+
let ok = (*self.state.get()).inc_readers();
46+
self.lock.unlock();
47+
return ok;
2348
}
2449

2550
#[inline]
2651
pub unsafe fn write(&self) {
27-
self.mutex.lock();
52+
self.lock.lock();
53+
while !(*self.state.get()).inc_writers() {
54+
self.cond.wait(&self.lock);
55+
}
56+
self.lock.unlock();
2857
}
2958

3059
#[inline]
3160
pub unsafe fn try_write(&self) -> bool {
32-
self.mutex.try_lock()
61+
self.lock.lock();
62+
let ok = (*self.state.get()).inc_writers();
63+
self.lock.unlock();
64+
return ok;
3365
}
3466

3567
#[inline]
3668
pub unsafe fn read_unlock(&self) {
37-
self.mutex.unlock();
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+
}
3876
}
3977

4078
#[inline]
4179
pub unsafe fn write_unlock(&self) {
42-
self.mutex.unlock();
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();
4385
}
4486

4587
#[inline]
4688
pub unsafe fn destroy(&self) {
47-
self.mutex.destroy();
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
48131
}
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");
49144
}

0 commit comments

Comments
 (0)