2023-08-22 08:52:30 -05:00
|
|
|
use {
|
2024-11-27 10:53:17 -06:00
|
|
|
alloc::{
|
|
|
|
boxed::Box,
|
|
|
|
collections::{BTreeMap, BTreeSet},
|
|
|
|
sync::Arc,
|
|
|
|
},
|
2023-08-22 08:52:30 -05:00
|
|
|
core::{
|
|
|
|
future::Future,
|
|
|
|
pin::Pin,
|
2024-11-26 13:32:19 -06:00
|
|
|
sync::atomic::{AtomicBool, Ordering},
|
|
|
|
task::{Context, ContextBuilder, Poll, RawWaker, RawWakerVTable, Waker},
|
2023-08-22 08:52:30 -05:00
|
|
|
},
|
|
|
|
crossbeam_queue::SegQueue,
|
|
|
|
slab::Slab,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub fn yield_now() -> impl Future<Output = ()> {
|
|
|
|
struct YieldNow(bool);
|
|
|
|
impl Future for YieldNow {
|
|
|
|
type Output = ();
|
|
|
|
|
|
|
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
|
|
if self.0 {
|
|
|
|
Poll::Ready(())
|
|
|
|
} else {
|
|
|
|
self.0 = true;
|
|
|
|
cx.waker().wake_by_ref();
|
|
|
|
Poll::Pending
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
YieldNow(false)
|
|
|
|
}
|
|
|
|
|
2024-11-26 13:32:19 -06:00
|
|
|
pub trait Process: Future<Output = ()> + Send {}
|
|
|
|
impl<T: Future<Output = ()> + Send> Process for T {}
|
|
|
|
|
2024-11-17 14:29:32 -06:00
|
|
|
pub struct Executor {
|
2024-11-27 06:52:48 -06:00
|
|
|
tasks: Slab<Task>,
|
2024-11-26 13:32:19 -06:00
|
|
|
task_queue: Arc<SegQueue<usize>>,
|
2024-11-26 15:53:50 -06:00
|
|
|
interrupt_lookup: [Option<usize>; u8::MAX as usize],
|
2024-11-27 10:53:17 -06:00
|
|
|
buffer_lookup: BTreeMap<usize, BTreeSet<usize>>,
|
2023-08-22 08:52:30 -05:00
|
|
|
}
|
|
|
|
|
2024-11-17 14:29:32 -06:00
|
|
|
impl Executor {
|
|
|
|
pub fn new() -> Self {
|
2024-09-13 16:41:31 -05:00
|
|
|
Self {
|
2024-11-27 06:52:48 -06:00
|
|
|
tasks: Slab::new(),
|
2024-11-26 13:32:19 -06:00
|
|
|
task_queue: Arc::new(SegQueue::new()),
|
2024-11-26 15:53:50 -06:00
|
|
|
interrupt_lookup: [None; u8::MAX as usize],
|
2024-11-27 10:53:17 -06:00
|
|
|
buffer_lookup: BTreeMap::new(),
|
2024-09-13 16:41:31 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-26 13:32:19 -06:00
|
|
|
pub fn spawn(&mut self, future: Pin<Box<dyn Process>>) -> usize {
|
2024-11-17 14:29:32 -06:00
|
|
|
let id = self.tasks.insert(Task::new(future));
|
2024-11-26 13:32:19 -06:00
|
|
|
self.task_queue.push(id);
|
|
|
|
|
2024-11-17 14:29:32 -06:00
|
|
|
id
|
2023-08-22 08:52:30 -05:00
|
|
|
}
|
|
|
|
|
2024-11-26 15:53:50 -06:00
|
|
|
pub fn pause(&self, id: usize) {
|
2024-11-26 13:32:19 -06:00
|
|
|
if let Some(task) = self.tasks.get(id) {
|
|
|
|
task.set_paused(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-26 15:53:50 -06:00
|
|
|
pub fn unpause(&self, id: usize) {
|
2024-11-26 13:32:19 -06:00
|
|
|
if let Some(task) = self.tasks.get(id) {
|
|
|
|
task.set_paused(false);
|
|
|
|
self.task_queue.push(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-27 06:52:48 -06:00
|
|
|
pub fn interrupt_subscribe(&mut self, pid: usize, interrupt_type: u8) {
|
2024-11-27 10:53:17 -06:00
|
|
|
self.pause(pid);
|
2024-11-26 15:53:50 -06:00
|
|
|
self.interrupt_lookup[interrupt_type as usize] = Some(pid);
|
|
|
|
}
|
|
|
|
|
2024-11-27 10:53:17 -06:00
|
|
|
pub fn buffer_subscribe(&mut self, pid: usize, buffer_id: usize) {
|
|
|
|
self.pause(pid);
|
|
|
|
if let Some(buf) = self.buffer_lookup.get_mut(&buffer_id) {
|
|
|
|
buf.insert(pid);
|
|
|
|
} else {
|
|
|
|
self.buffer_lookup.insert(buffer_id, BTreeSet::from([pid]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-22 08:52:30 -05:00
|
|
|
pub fn run(&mut self) {
|
2024-09-13 16:41:31 -05:00
|
|
|
let mut task_batch = [0; 32];
|
|
|
|
loop {
|
2024-11-26 13:32:19 -06:00
|
|
|
let mut batch_len = 0;
|
2024-09-13 16:41:31 -05:00
|
|
|
|
2024-11-26 13:32:19 -06:00
|
|
|
while let Some(id) = self.task_queue.pop() {
|
|
|
|
task_batch[batch_len] = id;
|
|
|
|
batch_len += 1;
|
|
|
|
if batch_len == task_batch.len() {
|
2024-09-13 16:41:31 -05:00
|
|
|
break;
|
|
|
|
}
|
2023-08-22 08:52:30 -05:00
|
|
|
}
|
|
|
|
|
2024-11-26 13:32:19 -06:00
|
|
|
if batch_len == 0 {
|
2024-11-27 06:52:48 -06:00
|
|
|
// break;
|
2024-11-26 15:53:50 -06:00
|
|
|
continue;
|
2024-11-26 13:32:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
for &(mut id) in &task_batch[..batch_len] {
|
2024-09-13 16:41:31 -05:00
|
|
|
if let Some(task) = self.tasks.get_mut(id) {
|
2024-11-26 13:32:19 -06:00
|
|
|
if task.is_paused() {
|
|
|
|
continue;
|
|
|
|
}
|
2023-08-22 08:52:30 -05:00
|
|
|
|
2024-11-26 13:32:19 -06:00
|
|
|
let waker = create_waker(id, Arc::clone(&self.task_queue));
|
|
|
|
let mut cx = ContextBuilder::from_waker(&waker).ext(&mut id).build();
|
2024-09-13 16:41:31 -05:00
|
|
|
|
|
|
|
if let Poll::Ready(()) = task.poll(&mut cx) {
|
|
|
|
self.tasks.remove(id);
|
2024-11-27 06:52:48 -06:00
|
|
|
self.interrupt_lookup.map(|pid| {
|
|
|
|
if let Some(pid) = pid {
|
2024-11-26 15:53:50 -06:00
|
|
|
if pid == id {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pid;
|
|
|
|
});
|
2024-11-27 10:53:17 -06:00
|
|
|
self.buffer_lookup.iter_mut().for_each(|(_, pid_set)| {
|
|
|
|
pid_set.remove(&id);
|
|
|
|
});
|
2023-08-22 08:52:30 -05:00
|
|
|
}
|
2024-09-13 16:41:31 -05:00
|
|
|
}
|
2023-08-22 08:52:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-11-26 15:53:50 -06:00
|
|
|
|
2024-11-27 06:52:48 -06:00
|
|
|
pub fn send_interrupt(&self, interrupt: u8) {
|
2024-11-26 15:53:50 -06:00
|
|
|
let id = self.interrupt_lookup[interrupt as usize];
|
2024-11-27 06:52:48 -06:00
|
|
|
if let Some(id) = id {
|
2024-11-26 15:53:50 -06:00
|
|
|
self.unpause(id);
|
|
|
|
}
|
|
|
|
}
|
2024-11-27 10:53:17 -06:00
|
|
|
pub fn send_buffer(&self, id: usize) {
|
|
|
|
if let Some(buf) = self.buffer_lookup.get(&id) {
|
|
|
|
buf.iter().for_each(|pid| self.unpause(*pid));
|
|
|
|
}
|
|
|
|
}
|
2023-08-22 08:52:30 -05:00
|
|
|
}
|
|
|
|
|
2024-11-17 14:29:32 -06:00
|
|
|
struct Task {
|
2024-11-26 13:32:19 -06:00
|
|
|
future: Pin<Box<dyn Process>>,
|
|
|
|
paused: AtomicBool,
|
2023-08-22 08:52:30 -05:00
|
|
|
}
|
|
|
|
|
2024-11-17 14:29:32 -06:00
|
|
|
impl Task {
|
2024-11-26 13:32:19 -06:00
|
|
|
fn new(future: Pin<Box<dyn Process>>) -> Self {
|
2023-08-22 08:52:30 -05:00
|
|
|
Self {
|
2024-11-17 14:29:32 -06:00
|
|
|
future,
|
2024-11-26 13:32:19 -06:00
|
|
|
paused: AtomicBool::new(false),
|
2023-08-22 08:52:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn poll(&mut self, cx: &mut Context) -> Poll<()> {
|
|
|
|
self.future.as_mut().poll(cx)
|
|
|
|
}
|
2024-11-26 13:32:19 -06:00
|
|
|
|
|
|
|
fn is_paused(&self) -> bool {
|
|
|
|
self.paused.load(Ordering::Acquire)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_paused(&self, paused: bool) {
|
|
|
|
self.paused.store(paused, Ordering::Release)
|
|
|
|
}
|
2023-08-22 08:52:30 -05:00
|
|
|
}
|
|
|
|
|
2024-11-26 13:32:19 -06:00
|
|
|
fn create_waker(task_id: usize, task_queue: Arc<SegQueue<usize>>) -> Waker {
|
|
|
|
let data = Box::new(TaskWaker {
|
|
|
|
task_id,
|
|
|
|
task_queue,
|
|
|
|
});
|
|
|
|
let raw_waker = RawWaker::new(Box::into_raw(data) as *const (), &VTABLE);
|
|
|
|
unsafe { Waker::from_raw(raw_waker) }
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
2024-09-13 16:41:31 -05:00
|
|
|
struct TaskWaker {
|
2024-11-26 13:32:19 -06:00
|
|
|
task_id: usize,
|
|
|
|
task_queue: Arc<SegQueue<usize>>,
|
2024-09-13 16:41:31 -05:00
|
|
|
}
|
2023-08-22 08:52:30 -05:00
|
|
|
|
2024-09-13 16:41:31 -05:00
|
|
|
impl TaskWaker {
|
|
|
|
fn wake(&self) {
|
2024-11-26 13:32:19 -06:00
|
|
|
self.task_queue.push(self.task_id);
|
2024-09-13 16:41:31 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw);
|
|
|
|
|
|
|
|
unsafe fn clone_raw(ptr: *const ()) -> RawWaker {
|
2024-11-26 13:32:19 -06:00
|
|
|
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
|
|
|
|
let raw_waker = RawWaker::new(Box::into_raw(task_waker.clone()) as *const (), &VTABLE);
|
|
|
|
raw_waker
|
2024-09-13 16:41:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn wake_raw(ptr: *const ()) {
|
2024-11-26 13:32:19 -06:00
|
|
|
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
|
|
|
|
task_waker.wake();
|
2024-09-13 16:41:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn wake_by_ref_raw(ptr: *const ()) {
|
2024-11-26 13:32:19 -06:00
|
|
|
let task_waker = &*(ptr as *const TaskWaker);
|
|
|
|
task_waker.wake();
|
2023-08-22 08:52:30 -05:00
|
|
|
}
|
|
|
|
|
2024-11-26 13:32:19 -06:00
|
|
|
unsafe fn drop_raw(ptr: *const ()) {
|
|
|
|
drop(Box::from_raw(ptr as *mut TaskWaker));
|
2023-08-22 08:52:30 -05:00
|
|
|
}
|