in src/sync/rwlock.rs [128:210]
fn lock(&self, typ: RwLockType) {
let me = ExecutionState::me();
let mut state = self.state.borrow_mut();
trace!(
holder = ?state.holder,
waiting_readers = ?state.waiting_readers,
waiting_writers = ?state.waiting_writers,
"waiting to acquire {:?} lock on rwlock {:p}",
typ,
self.state,
);
// We are waiting for the lock
if typ == RwLockType::Write {
state.waiting_writers.insert(me);
} else {
state.waiting_readers.insert(me);
}
// Block if the lock is in a state where we can't acquire it immediately
match &state.holder {
RwLockHolder::Write(writer) => {
assert_ne!(*writer, me);
ExecutionState::with(|s| s.current_mut().block());
}
RwLockHolder::Read(readers) => {
assert!(!readers.contains(me));
if typ == RwLockType::Write {
ExecutionState::with(|s| s.current_mut().block());
}
}
_ => {}
}
drop(state);
// Acquiring a lock is a yield point
thread::switch();
let mut state = self.state.borrow_mut();
// Once the scheduler has resumed this thread, we are clear to take the lock. We might
// not actually be in the waiters, though (if the lock was uncontended).
// TODO should always be in the waiters?
match (typ, &mut state.holder) {
(RwLockType::Write, RwLockHolder::None) => {
state.holder = RwLockHolder::Write(me);
}
(RwLockType::Read, RwLockHolder::None) => {
let mut readers = TaskSet::new();
readers.insert(me);
state.holder = RwLockHolder::Read(readers);
}
(RwLockType::Read, RwLockHolder::Read(readers)) => {
readers.insert(me);
}
_ => {
panic!(
"resumed a waiting {:?} thread while the lock was in state {:?}",
typ, state.holder
);
}
}
if typ == RwLockType::Write {
state.waiting_writers.remove(me);
} else {
state.waiting_readers.remove(me);
}
trace!(
holder = ?state.holder,
waiting_readers = ?state.waiting_readers,
waiting_writers = ?state.waiting_writers,
"acquired {:?} lock on rwlock {:p}",
typ,
self.state
);
// Update acquiring thread's clock with the clock stored in the RwLock
ExecutionState::with(|s| s.update_clock(&state.clock));
// Block all other waiters, since we won the race to take this lock
// TODO a bit of a bummer that we have to do this (it would be cleaner if those threads
// TODO never become unblocked), but might need to track more state to avoid this.
Self::block_waiters(&*state, me, typ);
drop(state);
}