use super::{event_list_new, timer_rbtree_new, BoxedPoll, Event, Poll, Timer, Waker, POLLIN};
use crate::{time, Error};
use core::ptr;
use core::time::Duration;
use hicollections::{List, RbTree};
use hioff::container_of_mut;
use hipool::{Boxed, MemPool, NullAlloc};
type Pool = &'static MemPool;
struct StopEvent {
waker: Waker,
event: Event,
stopped: bool,
}
#[repr(C)]
pub struct Scheduler {
poll: BoxedPoll,
events: List<Event>,
monitors: List<Event>,
timers: RbTree<Timer>,
private_data: *const (),
now: Duration,
stop: StopEvent,
}
pub type BoxedScheduler = Boxed<'static, Scheduler, NullAlloc>;
impl Scheduler {
pub fn new_in(pool: Pool) -> Result<BoxedScheduler, Error> {
let waker = Waker::new()?;
let poll = Poll::new_in(pool)?;
let mut boxed = Boxed::new_in(
pool,
Self {
stop: StopEvent {
event: Event::new(Self::stop_event_handle),
waker,
stopped: false,
},
poll,
events: event_list_new(),
monitors: event_list_new(),
timers: timer_rbtree_new(),
now: time::now(),
private_data: ptr::null(),
},
)?;
boxed.active_stop_event();
Ok(boxed.into())
}
}
impl Scheduler {
fn active_stop_event(&mut self) {
let _ = self
.poll
.add_event(self.stop.waker.fd, POLLIN, &self.stop.event);
}
fn stop_event_handle(event: &Event, _events: u32, _sched: &mut Scheduler) {
let this = unsafe { container_of_mut!(event, Self, stop.event) };
if this.stop.waker.awaken() {
this.stop.stopped = true;
}
}
fn wait_timeout(&self) -> i32 {
if !self.events.empty() {
0
} else if let Some(first) = self.timers.first() {
let timeout = first.timeout.get();
if timeout <= self.now {
0
} else {
(timeout - self.now).as_millis() as i32
}
} else {
-1
}
}
fn dispatch_monitors(&mut self) {
if !self.monitors.empty() {
let mut list = event_list_new();
self.monitors.move_head(&mut list);
for event in list.iter() {
event.handle(0, self);
}
list.move_head(&mut self.monitors);
}
}
fn dispatch_events(&mut self) {
let mut list = event_list_new();
self.events.move_head(&mut list);
while let Some(first) = list.first() {
unsafe { list.del(first) };
first.handle(first.events.get(), self);
}
}
fn dispatch_fd_events(&mut self, list: &mut List<Event>) {
while let Some(first) = list.first() {
unsafe { list.del(first) };
first.handle(first.events.get(), self);
}
}
fn dispatch_timers(&mut self) {
while let Some(first) = self.timers.first() {
if first.timeout.get() <= self.now {
self.timers.remove(first);
first.handle(self);
} else {
break;
}
}
}
}
impl Scheduler {
pub fn run(&mut self) {
let mut list = List::<Event>::new(|e| unsafe { ptr::addr_of!((*e).node) });
while !self.stop.stopped {
self.now = time::now();
let timeout = self.wait_timeout();
let Ok(_) = self.poll.wait(timeout, |events, event| {
let event = unsafe { &*(event) };
event.events.set(events);
unsafe { list.add_tail(event) };
}) else { continue };
if timeout > 0 {
self.now = time::now();
}
self.dispatch_timers();
self.dispatch_fd_events(&mut list);
self.dispatch_events();
self.dispatch_monitors();
}
}
pub fn stop(&self) {
self.stop.waker.wake();
}
pub fn stopped(&self) -> bool {
self.stop.stopped
}
pub fn now(&self) -> Duration {
self.now
}
pub fn add_monitor(&mut self, e: &Event) {
unsafe {
self.monitors.del(e);
self.monitors.add_tail(e)
};
}
pub fn add_event(&mut self, e: &Event, events: u32, _priority: i32) {
self.del_event(e);
unsafe { self.events.add_tail(e) };
e.events.set(events);
}
pub fn add_event_list(&mut self, events: &mut List<Event>, _priority: i32) {
events.move_tail(&mut self.events);
}
pub fn del_event(&mut self, e: &Event) {
unsafe {
self.events.del(e);
}
}
pub fn add_fd_event(&self, e: &Event, events: u32, fd: i32) -> Result<(), Error> {
self.poll.add_event(fd, events, e as *const Event)
}
pub fn mod_fd_event(&self, e: &Event, events: u32, fd: i32) -> Result<(), Error> {
self.poll.mod_event(fd, events, e as *const Event)
}
pub fn del_fd_event(&self, fd: i32) -> Result<(), Error> {
self.poll.del_event(fd)
}
pub fn set_timer(&mut self, t: &Timer, micros: u32) {
self.timers.remove(t);
t.timeout
.set(self.now + Duration::from_micros(micros as u64));
unsafe { self.timers.insert(t, false) };
}
pub fn del_timer(&mut self, t: &Timer) {
self.timers.remove(t);
}
pub fn private_data(&self) -> *const () {
self.private_data
}
pub fn set_private_data(&mut self, data: *const ()) {
self.private_data = data;
}
}