mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-02 08:20:09 +00:00
Allow resetting executor::Deterministic
's RNG
This commit is contained in:
parent
bd68d83519
commit
1813a3cc91
1 changed files with 47 additions and 33 deletions
|
@ -9,7 +9,11 @@ use std::{
|
||||||
mem,
|
mem,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{mpsc::SyncSender, Arc},
|
sync::{
|
||||||
|
atomic::{AtomicBool, Ordering::SeqCst},
|
||||||
|
mpsc::SyncSender,
|
||||||
|
Arc,
|
||||||
|
},
|
||||||
thread,
|
thread,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,24 +37,25 @@ pub enum Background {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
struct DeterministicState {
|
||||||
struct Runnables {
|
rng: StdRng,
|
||||||
|
seed: u64,
|
||||||
scheduled: Vec<Runnable>,
|
scheduled: Vec<Runnable>,
|
||||||
spawned_from_foreground: Vec<Runnable>,
|
spawned_from_foreground: Vec<Runnable>,
|
||||||
waker: Option<SyncSender<()>>,
|
waker: Option<SyncSender<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Deterministic {
|
pub struct Deterministic(Arc<Mutex<DeterministicState>>);
|
||||||
seed: u64,
|
|
||||||
runnables: Arc<Mutex<Runnables>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deterministic {
|
impl Deterministic {
|
||||||
fn new(seed: u64) -> Self {
|
fn new(seed: u64) -> Self {
|
||||||
Self {
|
Self(Arc::new(Mutex::new(DeterministicState {
|
||||||
|
rng: StdRng::seed_from_u64(seed),
|
||||||
seed,
|
seed,
|
||||||
runnables: Default::default(),
|
scheduled: Default::default(),
|
||||||
}
|
spawned_from_foreground: Default::default(),
|
||||||
|
waker: None,
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_from_foreground<F, T>(&self, future: F) -> Task<T>
|
pub fn spawn_from_foreground<F, T>(&self, future: F) -> Task<T>
|
||||||
|
@ -58,17 +63,16 @@ impl Deterministic {
|
||||||
T: 'static,
|
T: 'static,
|
||||||
F: Future<Output = T> + 'static,
|
F: Future<Output = T> + 'static,
|
||||||
{
|
{
|
||||||
let scheduled_once = Mutex::new(false);
|
let scheduled_once = AtomicBool::new(false);
|
||||||
let runnables = self.runnables.clone();
|
let state = self.0.clone();
|
||||||
let (runnable, task) = async_task::spawn_local(future, move |runnable| {
|
let (runnable, task) = async_task::spawn_local(future, move |runnable| {
|
||||||
let mut runnables = runnables.lock();
|
let mut state = state.lock();
|
||||||
if *scheduled_once.lock() {
|
if scheduled_once.fetch_or(true, SeqCst) {
|
||||||
runnables.scheduled.push(runnable);
|
state.scheduled.push(runnable);
|
||||||
} else {
|
} else {
|
||||||
runnables.spawned_from_foreground.push(runnable);
|
state.spawned_from_foreground.push(runnable);
|
||||||
*scheduled_once.lock() = true;
|
|
||||||
}
|
}
|
||||||
if let Some(waker) = runnables.waker.as_ref() {
|
if let Some(waker) = state.waker.as_ref() {
|
||||||
waker.send(()).ok();
|
waker.send(()).ok();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -81,11 +85,11 @@ impl Deterministic {
|
||||||
T: 'static + Send,
|
T: 'static + Send,
|
||||||
F: 'static + Send + Future<Output = T>,
|
F: 'static + Send + Future<Output = T>,
|
||||||
{
|
{
|
||||||
let runnables = self.runnables.clone();
|
let state = self.0.clone();
|
||||||
let (runnable, task) = async_task::spawn(future, move |runnable| {
|
let (runnable, task) = async_task::spawn(future, move |runnable| {
|
||||||
let mut runnables = runnables.lock();
|
let mut state = state.lock();
|
||||||
runnables.scheduled.push(runnable);
|
state.scheduled.push(runnable);
|
||||||
if let Some(waker) = runnables.waker.as_ref() {
|
if let Some(waker) = state.waker.as_ref() {
|
||||||
waker.send(()).ok();
|
waker.send(()).ok();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -99,8 +103,8 @@ impl Deterministic {
|
||||||
F: Future<Output = T> + 'static,
|
F: Future<Output = T> + 'static,
|
||||||
{
|
{
|
||||||
let (wake_tx, wake_rx) = std::sync::mpsc::sync_channel(32);
|
let (wake_tx, wake_rx) = std::sync::mpsc::sync_channel(32);
|
||||||
let runnables = self.runnables.clone();
|
let state = self.0.clone();
|
||||||
runnables.lock().waker = Some(wake_tx);
|
state.lock().waker = Some(wake_tx);
|
||||||
|
|
||||||
let (output_tx, output_rx) = std::sync::mpsc::channel();
|
let (output_tx, output_rx) = std::sync::mpsc::channel();
|
||||||
self.spawn_from_foreground(async move {
|
self.spawn_from_foreground(async move {
|
||||||
|
@ -109,23 +113,22 @@ impl Deterministic {
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
let mut rng = StdRng::seed_from_u64(self.seed);
|
|
||||||
loop {
|
loop {
|
||||||
if let Ok(value) = output_rx.try_recv() {
|
if let Ok(value) = output_rx.try_recv() {
|
||||||
runnables.lock().waker = None;
|
state.lock().waker = None;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
wake_rx.recv().unwrap();
|
wake_rx.recv().unwrap();
|
||||||
let runnable = {
|
let runnable = {
|
||||||
let mut runnables = runnables.lock();
|
let state = &mut *state.lock();
|
||||||
let ix = rng.gen_range(
|
let ix = state
|
||||||
0..runnables.scheduled.len() + runnables.spawned_from_foreground.len(),
|
.rng
|
||||||
);
|
.gen_range(0..state.scheduled.len() + state.spawned_from_foreground.len());
|
||||||
if ix < runnables.scheduled.len() {
|
if ix < state.scheduled.len() {
|
||||||
runnables.scheduled.remove(ix)
|
state.scheduled.remove(ix)
|
||||||
} else {
|
} else {
|
||||||
runnables.spawned_from_foreground.remove(0)
|
state.spawned_from_foreground.remove(0)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -171,6 +174,17 @@ impl Foreground {
|
||||||
Self::Deterministic(executor) => executor.run(future),
|
Self::Deterministic(executor) => executor.run(future),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reset(&self) {
|
||||||
|
match self {
|
||||||
|
Self::Platform { .. } => panic!("can't call this method on a platform executor"),
|
||||||
|
Self::Test(_) => panic!("can't call this method on a test executor"),
|
||||||
|
Self::Deterministic(executor) => {
|
||||||
|
let state = &mut *executor.0.lock();
|
||||||
|
state.rng = StdRng::seed_from_u64(state.seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Background {
|
impl Background {
|
||||||
|
|
Loading…
Reference in a new issue