in src/sync/once.rs [89:141]
fn call_once_inner<F>(&self, f: F, ignore_poisoning: bool)
where
F: FnOnce(&OnceState),
{
let lock = ExecutionState::with(|state| {
// Initialize the state of the `Once` cell if we're the first thread to try
if self.get_state(state).is_none() {
self.init_state(state, OnceInitState::Running(Rc::new(Mutex::new(false))));
}
let init = self.get_state(state).expect("must be initialized by this point");
let init_state = init.borrow();
trace!(state=?init_state, "call_once on cell {:p}", self);
match &*init_state {
OnceInitState::Complete(clock) => {
// If already complete, just update the clock from the thread that inited
let clock = clock.clone();
drop(init_state);
state.update_clock(&clock);
None
}
OnceInitState::Running(lock) => Some(Rc::clone(lock)),
}
});
// If there's a lock, then we need to try racing on it to decide who gets to run their
// initialization closure.
if let Some(lock) = lock {
let (mut flag, is_poisoned) = match lock.lock() {
Ok(flag) => (flag, false),
Err(_) if !ignore_poisoning => panic!("Once instance has previously been poisoned"),
Err(err) => (err.into_inner(), true),
};
if *flag {
return;
}
trace!("won the call_once race for cell {:p}", self);
f(&OnceState(is_poisoned));
*flag = true;
// We were the thread that won the race, so remember our current clock to establish
// causality with future threads that try (and fail) to run `call_once`. The threads
// that were racing with us will get causality through acquiring the `Mutex`.
ExecutionState::with(|state| {
let clock = state.increment_clock().clone();
*self
.get_state(state)
.expect("must be initialized by this point")
.borrow_mut() = OnceInitState::Complete(clock);
});
}
}