mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-24 10:26:25 +04:00
add stackless_coroutine in kernel
This commit is contained in:
parent
15dec102fa
commit
ca433ad389
@ -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();
|
||||||
|
@ -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();
|
||||||
|
121
os/src/task/stackless_coroutine.rs
Normal file
121
os/src/task/stackless_coroutine.rs
Normal 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");
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user