use std::collections::VecDeque;
use std::future::Future;
use std::pin::Pin;
use std::sync::{Arc, Mutex, Condvar};
use std::task::{Context, Poll, Waker};
use std::time::{Duration, Instant};
use std::thread;
use crate::reactor::Reactor;
use crate::timer::GlobalTimerWheel;
thread_local! {
static RUNTIME: Runtime = Runtime::new();
}
pub struct Runtime {
thread_pool: Arc<ThreadPool>,
reactor: Arc<Mutex<Reactor>>,
timer_wheel: Arc<GlobalTimerWheel>,
}
impl Runtime {
pub fn new() -> Self {
let cpu_count = thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(4);
let reactor = Arc::new(Mutex::new(Reactor::new().expect("Failed to create reactor")));
let timer_wheel = Arc::new(GlobalTimerWheel::new());
let reactor_clone = Arc::clone(&reactor);
let timer_clone = Arc::clone(&timer_wheel);
thread::spawn(move || {
let mut events = Vec::with_capacity(1024);
loop {
{
events.clear();
let mut r = reactor_clone.lock().unwrap();
match r.wait(&mut events, Some(Duration::from_millis(1))) {
Ok(_) => {
r.wake_events(&events);
}
Err(e) => {
eprintln!("Reactor wait error: {:?}", e);
}
}
}
timer_clone.tick();
thread::sleep(Duration::from_micros(100));
}
});
Self {
thread_pool: Arc::new(ThreadPool::new(cpu_count)),
reactor,
timer_wheel,
}
}
pub fn reactor(&self) -> Arc<Mutex<Reactor>> {
Arc::clone(&self.reactor)
}
pub fn timer_wheel(&self) -> Arc<GlobalTimerWheel> {
Arc::clone(&self.timer_wheel)
}
pub fn block_on<F: Future>(&self, future: F) -> F::Output {
let mut pinned = Box::pin(future);
loop {
let waker = noop_waker();
let mut cx = Context::from_waker(&waker);
match pinned.as_mut().poll(&mut cx) {
Poll::Ready(output) => return output,
Poll::Pending => {
thread::yield_now();
}
}
}
}
pub fn spawn<F>(&self, future: F)
where
F: Future<Output = ()> + Send + 'static,
{
self.thread_pool.spawn(future);
}
}
impl Default for Runtime {
fn default() -> Self {
Self::new()
}
}
struct ThreadPool {
workers: Vec<Worker>,
sender: Arc<Mutex<VecDeque<Task>>>,
condvar: Arc<Condvar>,
}
type Task = Pin<Box<dyn Future<Output = ()> + Send>>;
impl ThreadPool {
fn new(size: usize) -> Self {
let sender = Arc::new(Mutex::new(VecDeque::new()));
let condvar = Arc::new(Condvar::new());
let mut workers = Vec::with_capacity(size);
for id in 0..size {
workers.push(Worker::new(
id,
Arc::clone(&sender),
Arc::clone(&condvar),
));
}
Self {
workers,
sender,
condvar,
}
}
fn spawn<F>(&self, future: F)
where
F: Future<Output = ()> + Send + 'static,
{
let task = Box::pin(future);
{
let mut queue = self.sender.lock().unwrap();
queue.push_back(task);
}
self.condvar.notify_one();
}
}
struct Worker {
_thread: thread::JoinHandle<()>,
}
impl Worker {
fn new(
id: usize,
receiver: Arc<Mutex<VecDeque<Task>>>,
condvar: Arc<Condvar>,
) -> Self {
let thread = thread::spawn(move || {
loop {
let task = {
let mut queue = receiver.lock().unwrap();
while queue.is_empty() {
queue = condvar.wait(queue).unwrap();
}
queue.pop_front()
};
if let Some(mut task) = task {
let waker = noop_waker();
let mut cx = Context::from_waker(&waker);
let _ = task.as_mut().poll(&mut cx);
}
}
});
Worker { _thread: thread }
}
}
fn noop_waker() -> Waker {
use std::task::{RawWaker, RawWakerVTable};
unsafe fn clone(_: *const ()) -> RawWaker {
RawWaker::new(std::ptr::null(), &VTABLE)
}
unsafe fn wake(_: *const ()) {}
unsafe fn wake_by_ref(_: *const ()) {}
unsafe fn drop(_: *const ()) {}
static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
unsafe {
Waker::from_raw(RawWaker::new(std::ptr::null(), &VTABLE))
}
}
pub fn sleep(duration: Duration) -> crate::timer::Sleep {
crate::timer::sleep(duration)
}
pub fn block_on<F: Future>(future: F) -> F::Output {
RUNTIME.with(|rt| rt.block_on(future))
}
pub fn spawn<F>(future: F)
where
F: Future<Output = ()> + Send + 'static,
{
RUNTIME.with(|rt| rt.spawn(future));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_runtime_creation() {
let runtime = Runtime::new();
assert!(runtime.thread_pool.workers.len() > 0);
}
#[test]
fn test_block_on() {
let runtime = Runtime::new();
let result = runtime.block_on(async {
42
});
assert_eq!(result, 42);
}
}