ableos/kernel/src/task.rs

171 lines
4.1 KiB
Rust
Raw Normal View History

2023-08-22 08:52:30 -05:00
use {
2024-09-13 16:41:31 -05:00
alloc::{boxed::Box, 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 {
tasks: Slab<Task>,
2024-11-26 13:32:19 -06:00
task_queue: Arc<SegQueue<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-17 14:29:32 -06:00
tasks: Slab::new(),
2024-11-26 13:32:19 -06:00
task_queue: Arc::new(SegQueue::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 13:32:19 -06:00
pub fn pause(&mut self, id: usize) {
if let Some(task) = self.tasks.get(id) {
task.set_paused(true);
}
}
pub fn unpause(&mut self, id: usize) {
if let Some(task) = self.tasks.get(id) {
task.set_paused(false);
self.task_queue.push(id);
}
}
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 {
break;
}
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);
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-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
}