add stackless_coroutine in kernel

This commit is contained in:
Yu Chen 2022-05-01 07:52:23 +08:00
parent 15dec102fa
commit ca433ad389
3 changed files with 126 additions and 0 deletions

View File

@ -53,6 +53,7 @@ pub fn rust_main() -> ! {
trap::init(); trap::init();
trap::enable_timer_interrupt(); trap::enable_timer_interrupt();
timer::set_next_trigger(); timer::set_next_trigger();
task::stackless_coroutine::kernel_stackless_coroutine_test();
fs::list_apps(); fs::list_apps();
task::add_initproc(); task::add_initproc();
task::run_tasks(); task::run_tasks();

View File

@ -5,6 +5,7 @@ mod process;
mod processor; mod processor;
mod signal; mod signal;
mod switch; mod switch;
pub mod stackless_coroutine;
#[allow(clippy::module_inception)] #[allow(clippy::module_inception)]
mod task; mod task;
@ -25,6 +26,9 @@ pub use processor::{
pub use signal::SignalFlags; pub use signal::SignalFlags;
pub use task::{TaskControlBlock, TaskStatus}; pub use task::{TaskControlBlock, TaskStatus};
pub use stackless_coroutine::kernel_stackless_coroutine_test;
pub fn suspend_current_and_run_next() { pub fn suspend_current_and_run_next() {
// There must be an application running. // There must be an application running.
let task = take_current_task().unwrap(); let task = take_current_task().unwrap();

View File

@ -0,0 +1,121 @@
// https://blog.aloni.org/posts/a-stack-less-rust-coroutine-100-loc/
// https://github.com/chyyuu/example-coroutine-and-thread/tree/stackless-coroutine-x86
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
use core::task::{RawWaker, RawWakerVTable, Waker};
extern crate alloc;
use alloc::collections::VecDeque;
use alloc::boxed::Box;
enum State {
Halted,
Running,
}
struct Task {
state: State,
}
impl Task {
fn waiter<'a>(&'a mut self) -> Waiter<'a> {
Waiter { task: self }
}
}
struct Waiter<'a> {
task: &'a mut Task,
}
impl<'a> Future for Waiter<'a> {
type Output = ();
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
match self.task.state {
State::Halted => {
self.task.state = State::Running;
Poll::Ready(())
}
State::Running => {
self.task.state = State::Halted;
Poll::Pending
}
}
}
}
struct Executor {
tasks: VecDeque<Pin<Box<dyn Future<Output = ()>>>>,
}
impl Executor {
fn new() -> Self {
Executor {
tasks: VecDeque::new(),
}
}
fn push<C, F>(&mut self, closure: C)
where
F: Future<Output = ()> + 'static,
C: FnOnce(Task) -> F,
{
let task = Task {
state: State::Running,
};
self.tasks.push_back(Box::pin(closure(task)));
}
fn run(&mut self) {
let waker = create_waker();
let mut context = Context::from_waker(&waker);
while let Some(mut task) = self.tasks.pop_front() {
match task.as_mut().poll(&mut context) {
Poll::Pending => {
self.tasks.push_back(task);
}
Poll::Ready(()) => {}
}
}
}
}
pub fn create_waker() -> Waker {
// Safety: The waker points to a vtable with functions that do nothing. Doing
// nothing is memory-safe.
unsafe { Waker::from_raw(RAW_WAKER) }
}
const RAW_WAKER: RawWaker = RawWaker::new(core::ptr::null(), &VTABLE);
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
unsafe fn clone(_: *const ()) -> RawWaker {
RAW_WAKER
}
unsafe fn wake(_: *const ()) {}
unsafe fn wake_by_ref(_: *const ()) {}
unsafe fn drop(_: *const ()) {}
#[no_mangle]
pub fn kernel_stackless_coroutine_test() {
println!("kernel stackless coroutine Begin..");
let mut exec = Executor::new();
println!(" Create futures");
for instance in 1..=3 {
exec.push(move |mut task| async move {
println!(" Kernel Task {}: begin state", instance);
task.waiter().await;
println!(" Kernel Task {}: next state", instance);
task.waiter().await;
println!(" Kernel Task {}: end state", instance);
});
}
println!(" Running");
exec.run();
println!(" Done");
println!("kernel stackless coroutine PASSED");
}