#![cfg(not(loom))]
use affinitypool::Threadpool;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::sync::mpsc;
use std::task::{Context, Waker};
use std::thread;
use std::time::Duration;
#[test]
fn self_spawn_wakes_parked_peer_when_spawner_blocks() {
let (done_tx, done_rx) = mpsc::channel::<()>();
let worker = thread::spawn(move || {
let pool = Arc::new(Threadpool::new(2));
let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
rt.block_on(async {
let _ = pool.spawn(|| 0u32).await;
});
thread::sleep(Duration::from_millis(100));
let inner = pool.clone();
let outer = pool.spawn(move || {
let fut = unsafe { inner.spawn_local(|| 42u32) };
let mut fut = Box::pin(fut);
let mut cx = Context::from_waker(Waker::noop());
let _ = fut.as_mut().poll(&mut cx);
drop(fut);
});
rt.block_on(outer);
let _ = done_tx.send(());
});
assert!(
done_rx.recv_timeout(Duration::from_secs(10)).is_ok(),
"deadlock: a self-spawned runnable was stranded in the deque of a \
worker that then blocked, while its peer stayed parked"
);
worker.join().unwrap();
}
#[test]
fn self_spawn_still_runs_on_spawning_worker() {
let (done_tx, done_rx) = mpsc::channel::<u32>();
let worker = thread::spawn(move || {
let pool = Arc::new(Threadpool::new(2));
let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
let inner = pool.clone();
type Inner = Pin<Box<dyn Future<Output = u32> + Send>>;
let (tx, rx) = mpsc::channel::<Inner>();
let outer = pool.spawn(move || {
let f: Inner = Box::pin(inner.spawn(|| 42u32));
tx.send(f).unwrap();
});
rt.block_on(async {
outer.await;
let f = rx.recv_timeout(Duration::from_secs(5)).expect("no inner future");
let _ = done_tx.send(f.await);
});
});
assert_eq!(
done_rx.recv_timeout(Duration::from_secs(10)).ok(),
Some(42),
"self-spawned runnable did not complete"
);
worker.join().unwrap();
}