fn lock()

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);
    }