//! Async/await: both executors run tasks to completion, and `yield_now` //! makes tasks take turns. #![no_std] #![no_main] #![feature(custom_test_frameworks)] #![test_runner(rust_kernel::test_runner)] #![reexport_test_harness_main = "test_main"] extern crate alloc; use alloc::{rc::Rc, vec, vec::Vec}; use bootloader::{BootInfo, entry_point}; use core::cell::RefCell; use core::panic::PanicInfo; use rust_kernel::allocator; use rust_kernel::memory::{self, BootInfoFrameAllocator}; use rust_kernel::task::{Task, executor::Executor, simple_executor::SimpleExecutor, yield_now}; use x86_64::VirtAddr; entry_point!(main); fn main(boot_info: &'static BootInfo) -> ! { rust_kernel::init(); let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset); let mut mapper = unsafe { memory::init(phys_mem_offset) }; let mut frame_allocator = unsafe { BootInfoFrameAllocator::init(&boot_info.memory_map) }; allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed"); test_main(); rust_kernel::hlt_loop(); } async fn add_one(x: u32) -> u32 { x + 1 } #[test_case] fn simple_executor_runs_tasks() { let result = Rc::new(RefCell::new(0)); let r = result.clone(); let mut executor = SimpleExecutor::new(); executor.spawn(Task::new(async move { *r.borrow_mut() = add_one(41).await; })); executor.run(); assert_eq!(*result.borrow(), 42); } /// Each task logs a step, then yields. With a FIFO task queue they alternate. async fn logger(name: char, log: Rc>>) { for step in 1..=3 { log.borrow_mut().push((name, step)); yield_now().await; } } #[test_case] fn executor_interleaves_yielding_tasks() { let log = Rc::new(RefCell::new(Vec::new())); let mut executor = Executor::new(); executor.spawn(Task::new(logger('a', log.clone()))); executor.spawn(Task::new(logger('b', log.clone()))); executor.run_until_done(); assert_eq!( *log.borrow(), vec![('a', 1), ('b', 1), ('a', 2), ('b', 2), ('a', 3), ('b', 3)] ); } #[panic_handler] fn panic(info: &PanicInfo) -> ! { rust_kernel::test_panic_handler(info) }