use std::{
future::poll_fn, hint::black_box, num::NonZeroUsize, task::Poll, thread, time::Duration,
};
use compio::{
BufResult,
dispatcher::Dispatcher,
io::{AsyncRead, AsyncWriteExt},
net::{TcpListener, TcpStream},
runtime::{Runtime, SpawnMeta, spawn_at, spawn_blocking_at},
time::sleep,
};
const WORKERS: usize = 4;
fn main() {
console_subscriber::init();
let lints = spawn_runtime("compio-lints", lints);
let hog = spawn_runtime("compio-hog", never_yields);
Runtime::new().unwrap().block_on(server());
lints.join().unwrap();
hog.join().unwrap();
}
#[track_caller]
fn spawn_runtime<F: Future<Output = ()> + 'static>(
name: &'static str,
f: fn() -> F,
) -> thread::JoinHandle<()> {
let meta = SpawnMeta::capture();
thread::Builder::new()
.name(name.to_owned())
.spawn(move || Runtime::new().unwrap().block_on_at(f(), meta))
.unwrap()
}
#[track_caller]
fn spawn(name: &'static str, f: impl Future<Output = ()> + 'static) {
spawn_at(f, SpawnMeta::capture().named(name)).detach();
}
async fn server() {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
let dispatcher = Dispatcher::builder()
.worker_threads(NonZeroUsize::new(WORKERS).unwrap())
.thread_names(|i| format!("compio-worker-{i}"))
.build()
.unwrap();
spawn("load-generator", async move {
loop {
let mut client = TcpStream::connect(&addr).await.unwrap();
client.write_all("hello from compio").await.unwrap();
sleep(Duration::from_millis(50)).await;
}
});
spawn("blocking-pool", async {
loop {
spawn_blocking_at(
|| thread::sleep(Duration::from_millis(200)),
SpawnMeta::capture().named("blocking-pool-work"),
)
.await
.unwrap();
sleep(Duration::from_millis(300)).await;
}
});
spawn("idle-timer", async {
loop {
sleep(Duration::from_millis(500)).await;
}
});
println!("run `tokio-console` to watch this process");
loop {
let (mut stream, _) = listener.accept().await.unwrap();
drop(
dispatcher
.dispatch(move || async move {
let BufResult(read, buf) = stream.read(Vec::with_capacity(32)).await;
read.unwrap();
stream.write_all(buf).await.unwrap();
})
.unwrap(),
);
}
}
async fn lints() {
spawn("self-waker", async {
loop {
for _ in 0..3 {
let mut woken = false;
poll_fn(|cx| {
if woken {
return Poll::Ready(());
}
woken = true;
cx.waker().wake_by_ref();
Poll::Pending
})
.await;
}
sleep(Duration::from_millis(100)).await;
}
});
spawn("lost-waker", poll_fn(|_| Poll::Pending));
spawn("large-future", async {
loop {
let buf = [0u8; 8192];
sleep(Duration::from_millis(400)).await;
black_box(&buf);
}
});
std::future::pending().await
}
async fn never_yields() {
spawn("never-yields", async {
loop {
thread::sleep(Duration::from_millis(500));
}
});
std::future::pending().await
}