diff --git a/tornado-kernel/src/syscall/mod.rs b/tornado-kernel/src/syscall/mod.rs index 0b4f4bd..5c2f8aa 100644 --- a/tornado-kernel/src/syscall/mod.rs +++ b/tornado-kernel/src/syscall/mod.rs @@ -6,19 +6,7 @@ mod user_syscall; pub use user_syscall::user_trap_handler; use config::*; - -use crate::{ - hart::KernelHartInfo, - memory::{ - AddressSpaceId, - Satp, - VirtualPageNumber, - VirtualAddress, - PhysicalPageNumber, - KERNEL_MAP_OFFSET - } -}; - +use crate::memory::{AddressSpaceId, Satp, VirtualPageNumber, VirtualAddress,}; use bit_field::BitField; pub enum SyscallResult { @@ -34,10 +22,10 @@ impl SyscallResult { } } -pub fn syscall(param: [usize; 6], func: usize, module: usize) -> SyscallResult { +pub fn syscall(param: [usize; 6], user_satp: usize, func: usize, module: usize) -> SyscallResult { match module { - MODULE_PROCESS => do_process(param, func), - MODULE_TEST_INTERFACE => do_test_interfase(param, func), + MODULE_PROCESS => do_process(param, user_satp, func), + MODULE_TEST_INTERFACE => do_test_interface(param, user_satp, func), MODULE_TASK => do_task(param, func), _ => panic!("Unknown module {:x}", module), } @@ -51,41 +39,44 @@ fn switch_next_task(param: [usize; 6], func: usize) -> SyscallResult { todo!() } -fn do_process(param: [usize; 6], func: usize) -> SyscallResult { +fn do_process(param: [usize; 6], user_satp: usize, func: usize) -> SyscallResult { match func { FUNC_PROCESS_EXIT => SyscallResult::Terminate(param[0] as i32), - FUNC_PROCESS_PANIC => panic!("User panic!"), + FUNC_PROCESS_PANIC => { //[line as usize, col as usize, f_buf, f_len, m_buf, m_len] + let [line, col, f_buf, f_len, m_buf, m_len] = param; + let user_satp = crate::memory::Satp::new(user_satp); + let file_name = if f_buf == 0 { + None + } else { + let slice = unsafe { get_user_buf(user_satp, f_buf, f_len) }; + Some(core::str::from_utf8(slice).unwrap()) + }; + let msg = if m_buf == 0 { + None + } else { + let slice = unsafe { get_user_buf(user_satp, m_buf, m_len) }; + Some(core::str::from_utf8(slice).unwrap()) + }; + let file_name = file_name.unwrap_or(""); + let msg = msg.unwrap_or(""); + println!("[Kernel] User process panicked at '{}', {}:{}:{}", msg, file_name, line, col); + SyscallResult::Terminate(-1) + }, _ => panic!("Unknown syscall process, func: {}, param: {:?}", func, param) } } -fn do_test_interfase(param: [usize; 6], func: usize) -> SyscallResult { +fn do_test_interface(param: [usize; 6], user_satp: usize, func: usize) -> SyscallResult { match func { - FUNC_TEST_WRITE => { - let (asid, _fd, buf_ptr, buf_len) = - (param[0], param[1], param[2], param[3]); // 地址空间参数,文件描述符,缓冲区指针,缓冲区长度 - // println!("[kernel] enter do_test_write with asid: {}, buf_ptr: {:#x}, buf_len: {}", asid, buf_ptr, buf_len); - let user_asid = unsafe { AddressSpaceId::from_raw(asid) }; - if let Some(user_satp) = KernelHartInfo::get_satp(user_asid) { - let offset = buf_ptr.get_bits(0..12); // Sv39 里面虚拟地址偏移量为低 12 位 - let vpn = VirtualPageNumber::floor(VirtualAddress(buf_ptr)); - let ppn = user_satp.translate(vpn).unwrap(); - unsafe { - let ptr = (ppn - .start_address() - .0 - .wrapping_add(KERNEL_MAP_OFFSET) - .wrapping_add(offset) as *const u8) - .as_ref() - .unwrap(); - let slice = core::slice::from_raw_parts(ptr, buf_len); - let str = core::str::from_utf8(slice).unwrap(); - print!("{}", str); - SyscallResult::Procceed {code: 0, extra: buf_len} - } - } else { - panic!("User asid not found!") + FUNC_TEST_WRITE => { + let (_iface, buf_ptr, buf_len) = + (param[0], param[1], param[2]); // 调试接口编号,缓冲区指针,缓冲区长度 + let user_satp = crate::memory::Satp::new(user_satp); + let slice = unsafe { get_user_buf(user_satp, buf_ptr, buf_len) }; + for &byte in slice { + crate::sbi::console_putchar(byte as usize); } + SyscallResult::Procceed { code: 0, extra: buf_len } }, _ => panic!("Unknown syscall test, func: {}, param: {:?}", func, param) } @@ -93,4 +84,14 @@ fn do_test_interfase(param: [usize; 6], func: usize) -> SyscallResult { fn do_task(param: [usize; 6], func: usize) -> SyscallResult { todo!() -} \ No newline at end of file +} + +unsafe fn get_user_buf<'a>(user_satp: Satp, buf_ptr: usize, buf_len: usize) -> &'a [u8] { + let offset = buf_ptr.get_bits(0..12); // Sv39 里面虚拟地址偏移量为低 12 位 + let vpn = VirtualPageNumber::floor(VirtualAddress(buf_ptr)); + let ppn = user_satp.translate(vpn).expect("no page fault"); + let va = ppn.start_address().virtual_address_linear() + .0.wrapping_add(offset); + let ptr = (va as *const u8).as_ref().expect("non-null pointer"); + core::slice::from_raw_parts(ptr, buf_len) +} diff --git a/tornado-kernel/src/syscall/user_syscall.rs b/tornado-kernel/src/syscall/user_syscall.rs index 0beb89a..77606b5 100644 --- a/tornado-kernel/src/syscall/user_syscall.rs +++ b/tornado-kernel/src/syscall/user_syscall.rs @@ -12,8 +12,8 @@ pub extern "C" fn user_trap_handler() { unsafe { asm!("mv {}, t2", out(reg) user_satp, options(nomem, nostack)); } - let user_satp = Satp::new(user_satp); - let swap_cx = unsafe { get_swap_cx(&user_satp) }; + let user_satp_2 = Satp::new(user_satp); + let swap_cx = unsafe { get_swap_cx(&user_satp_2) }; // 从 SwapContext 中读东西 let a0 = swap_cx.x[9]; let a1 = swap_cx.x[10]; @@ -34,18 +34,17 @@ pub extern "C" fn user_trap_handler() { crate::sbi::shutdown(); }, Trap::Exception(scause::Exception::UserEnvCall) => { - let func = a6; let param = [a0, a1, a2, a3, a4, a5]; - match syscall(param, func, a7) { + match syscall(param, user_satp, a6, a7) { SyscallResult::Procceed { code, extra} => { swap_cx.x[9] = code; swap_cx.x[10] = extra; swap_cx.epc = swap_cx.epc.wrapping_add(4); - trap::switch_to_user(swap_cx, user_satp.inner()) + trap::switch_to_user(swap_cx, user_satp) }, SyscallResult::Retry => { // 不跳过指令,继续运行 - trap::switch_to_user(swap_cx, user_satp.inner()) + trap::switch_to_user(swap_cx, user_satp) }, SyscallResult::NextASID{ satp } => { // 需要转到目标地址空间去运行 diff --git a/tornado-kernel/src/task/executor.rs b/tornado-kernel/src/task/executor.rs index d7519c5..3723ffc 100644 --- a/tornado-kernel/src/task/executor.rs +++ b/tornado-kernel/src/task/executor.rs @@ -1,4 +1,4 @@ -use crate::task::{TaskResult, SharedTaskHandle, KernelTask}; +use crate::task::{TaskResult, KernelTask}; use woke::waker_ref; use alloc::sync::Arc; use core::{mem, task::{Poll, Context}}; diff --git a/tornado-kernel/src/trap/handler.rs b/tornado-kernel/src/trap/handler.rs index 4c5568c..b1d01f5 100644 --- a/tornado-kernel/src/trap/handler.rs +++ b/tornado-kernel/src/trap/handler.rs @@ -265,9 +265,9 @@ fn breakpoint(trap_frame: &mut TrapFrame) -> *mut TrapFrame { } fn syscall(trap_frame: &mut TrapFrame) -> *mut TrapFrame { - println!("Syscall at {:#08x}", trap_frame.sepc); + println!("Syscall at {:#08x}; note that user_satp /*todo*/", trap_frame.sepc); let param = [trap_frame.x[10], trap_frame.x[11], 0, 0, 0, 0]; // a0, a1 - match do_syscall(param, trap_frame.x[16], trap_frame.x[17]) { // a6, a7 + match do_syscall(param, 0/* todo */, trap_frame.x[16], trap_frame.x[17]) { // a6, a7 SyscallResult::Procceed { code, extra } => { trap_frame.x[10] = code; // a0 trap_frame.x[11] = extra; // a1 diff --git a/tornado-user/src/bin/alloc-test.rs b/tornado-user/src/bin/alloc-test.rs new file mode 100644 index 0000000..b12fb43 --- /dev/null +++ b/tornado-user/src/bin/alloc-test.rs @@ -0,0 +1,20 @@ +#![no_std] +#![no_main] +#![feature(asm)] +#![feature(llvm_asm)] + +extern crate alloc; +#[macro_use] +extern crate tornado_user; +use alloc::vec; + +// 同步函数的例子,没有调用execute_async_main +#[no_mangle] +fn main() -> i32 { + println!("[user] enter main!"); + let mut test_v = vec![1, 2, 3, 4, 5]; + test_v.iter_mut().for_each(|x| *x += 1); + assert_eq!(test_v, vec![2, 3, 4, 5, 6]); + println!("[User] alloc-test: success!"); + 0 +} diff --git a/tornado-user/src/bin/user_task.rs b/tornado-user/src/bin/user_task.rs index 39f9771..03b38a5 100644 --- a/tornado-user/src/bin/user_task.rs +++ b/tornado-user/src/bin/user_task.rs @@ -1,75 +1,65 @@ -#![no_std] -#![no_main] -#![feature(asm)] -#![feature(llvm_asm)] - -extern crate alloc; -#[macro_use] -extern crate tornado_user; -use alloc::vec; -use core::future::Future; -use core::task::{Context, Poll}; -use core::pin::Pin; -use tornado_user::{ - SHARED_PAYLOAD_BASE, - shared, - task, - exit, -}; - -#[no_mangle] -fn main() -> ! { - let mut test_v = vec![1, 2, 3, 4, 5]; - test_v.iter_mut().for_each(|x| *x += 1); - assert_eq!(test_v, vec![2, 3, 4, 5, 6]); - let shared_payload = unsafe { shared::SharedPayload::new(SHARED_PAYLOAD_BASE) }; - let task = task::UserTask::new(FibonacciFuture::new(6)); - unsafe { - /* todo: hart_id, asid */ - shared_payload.add_task(0, tornado_user::shared::AddressSpaceId::from_raw(tornado_user::ADDRESS_SPACE_ID), task.task_repr()); - } - - shared::run_until_idle( - || unsafe { shared_payload.peek_task(shared::user_should_switch) }, - |task_repr| unsafe { shared_payload.delete_task(task_repr) } - ); - // 用户态退出的系统调用 - exit(0); - unreachable!() -} - -struct FibonacciFuture { - a: usize, - b: usize, - i: usize, - cnt: usize -} - -impl FibonacciFuture { - fn new(cnt: usize) -> FibonacciFuture { - FibonacciFuture { - a: 0, - b: 1, - i: 0, - cnt - } - } -} - -impl Future for FibonacciFuture { - type Output = (); - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - if self.i == self.cnt { - println!("Fibonacci result: {}", self.a); - Poll::Ready(()) - } else { - let t = self.a; - self.a += self.b; - self.b = t; - self.i += 1; - println!("Fibonacci: i = {}, a = {}, b = {}", self.i, self.a, self.b); - cx.waker().wake_by_ref(); - Poll::Pending - } - } -} \ No newline at end of file +#![no_std] +#![no_main] +#![feature(asm)] +#![feature(llvm_asm)] + +extern crate alloc; +#[macro_use] +extern crate tornado_user; +use core::future::Future; +use core::task::{Context, Poll}; +use core::pin::Pin; + +async fn async_main() -> i32 { + // todo: 唤醒逻辑 + tornado_user::spawn(async { + let ans = FibonacciFuture::new(5).await; + println!("[User] Fibonacci[5] = {}", ans); + }); + let ans = FibonacciFuture::new(6).await; + println!("[User] Fibonacci[6] = {}", ans); + 0 +} + +// 异步main函数,由entry调用execute_async_main +#[no_mangle] +fn main() -> i32 { + tornado_user::execute_async_main(async_main()) +} + + +struct FibonacciFuture { + a: usize, + b: usize, + i: usize, + cnt: usize +} + +impl FibonacciFuture { + fn new(cnt: usize) -> FibonacciFuture { + FibonacciFuture { + a: 0, + b: 1, + i: 0, + cnt + } + } +} + +impl Future for FibonacciFuture { + type Output = usize; + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + if self.i == self.cnt { + println!("Fibonacci {} result: {}", self.cnt, self.a); + Poll::Ready(self.a) + } else { + let t = self.a; + self.a += self.b; + self.b = t; + self.i += 1; + println!("Fibonacci {}: i = {}, a = {}, b = {}", self.cnt, self.i, self.a, self.b); + cx.waker().wake_by_ref(); + Poll::Pending + } + } +} diff --git a/tornado-user/src/console.rs b/tornado-user/src/console.rs new file mode 100644 index 0000000..6797cce --- /dev/null +++ b/tornado-user/src/console.rs @@ -0,0 +1,27 @@ +use core::fmt::{self, Write}; +use super::test_write; + +struct Stdout; + +impl Write for Stdout { + fn write_str(&mut self, s: &str) -> fmt::Result { + test_write(s.as_bytes()); + Ok(()) + } +} +pub fn print(args: fmt::Arguments) { + Stdout.write_fmt(args).unwrap(); +} +#[macro_export] +macro_rules! print { + ($fmt: literal $(, $($arg: tt)+)?) => { + $crate::console::print(format_args!($fmt $(, $($arg)+)?)); + } +} + +#[macro_export] +macro_rules! println { + ($fmt: literal $(, $($arg: tt)+)?) => { + $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)); + } +} diff --git a/tornado-user/src/lib.rs b/tornado-user/src/lib.rs index ce39622..4c5b944 100644 --- a/tornado-user/src/lib.rs +++ b/tornado-user/src/lib.rs @@ -7,65 +7,108 @@ extern crate alloc; +#[macro_use] +pub mod console; pub mod shared; pub mod task; use buddy_system_allocator::LockedHeap; +use core::future::Future; - -const USER_HEAP_SIZE: usize = 32768; - -pub static mut ADDRESS_SPACE_ID: usize = 0; -pub static mut SHARED_PAYLOAD_BASE: usize = 0; +const USER_HEAP_SIZE: usize = 64 * 1024; static mut HEAP_SPACE: [u8; USER_HEAP_SIZE] = [0; USER_HEAP_SIZE]; +static mut SHARED_PAYLOAD_BASE: usize = 0; +static mut ADDRESS_SPACE_ID: usize = 0; + #[global_allocator] static HEAP: LockedHeap = LockedHeap::empty(); #[cfg_attr(not(test), panic_handler)] -pub fn panic_handler(_panic_info: &core::panic::PanicInfo) -> ! { - sys_panic(); +pub fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { + let err = panic_info.message().unwrap().as_str(); + if let Some(location) = panic_info.location() { + syscall::sys_panic(Some(location.file()), location.line(), location.column(), err); + } else { + syscall::sys_panic(None, 0, 0, err); + } unreachable!() } #[cfg_attr(not(test), alloc_error_handler)] -pub fn handle_alloc_error(_layout: core::alloc::Layout) -> ! { - sys_panic(); - unreachable!() +pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! { + println!("[User] user alloc error, layout = {:?}", layout); + panic!("user alloc error: {:?}", layout) } #[no_mangle] #[link_section = ".text.entry"] pub extern "C" fn _start() -> ! { - let mut ret: usize; + let mut address_space_id: usize; + let mut shared_payload_base: usize; unsafe { // 从 gp 寄存器里面取出 shared_raw_table 的地址 - asm!("mv {}, gp", out(reg) ret, options(nomem, nostack)); - SHARED_PAYLOAD_BASE = ret; + asm!("mv {}, gp", out(reg) shared_payload_base, options(nomem, nostack)); + SHARED_PAYLOAD_BASE = shared_payload_base; // 从 tp 寄存器里面取出该用户态的地址空间编号 - asm!("mv {}, tp", out(reg) ret, options(nomem, nostack)); - ADDRESS_SPACE_ID = ret; - extern "C" { - fn sbss(); fn ebss(); - } + asm!("mv {}, tp", out(reg) address_space_id, options(nomem, nostack)); + ADDRESS_SPACE_ID = address_space_id; + } + extern "C" { + fn sbss(); fn ebss(); + } + unsafe { r0::zero_bss(&mut sbss as *mut _ as *mut u32, &mut ebss as *mut _ as *mut u32); HEAP.lock().init(HEAP_SPACE.as_ptr() as usize, USER_HEAP_SIZE); } - main() + let exit_code = main(); + exit(exit_code); + unreachable!() } #[linkage = "weak"] +#[link_section = ".text"] // 必须指定,否则llvm好像会把名字为“entry”的函数链接到最开始…… #[no_mangle] -fn main() -> ! { +fn main() -> i32 { + println!("[User] No main function found; user exit"); panic!("Can not find main!"); } +/// 运行一个异步的main函数,在用户的entry函数里调用 +/// 应该作为标准库的一部分,这里使用一个库函数来模拟有标准库的情况 +pub fn execute_async_main(main: impl Future + Send + Sync + 'static) -> i32 { + let shared_payload = unsafe { shared::SharedPayload::new(SHARED_PAYLOAD_BASE) }; + let asid = unsafe { shared::AddressSpaceId::from_raw(ADDRESS_SPACE_ID) }; + static mut EXIT_CODE: i32 = 0; + let main_task = task::UserTask::new(async move { + unsafe { EXIT_CODE = main.await }; + }); + unsafe { + shared_payload.add_task(0/* todo */, asid, main_task.task_repr()); + } + shared::run_until_ready( + || unsafe { shared_payload.peek_task(shared::user_should_switch) }, + |task_repr| unsafe { shared_payload.delete_task(task_repr) } + ); + unsafe { EXIT_CODE } +} + +/// 生成一个新的任务 +pub fn spawn(future: impl Future + Send + Sync + 'static) { + let shared_payload = unsafe { shared::SharedPayload::new(SHARED_PAYLOAD_BASE) }; + let asid = unsafe { shared::AddressSpaceId::from_raw(ADDRESS_SPACE_ID) }; + let task = task::UserTask::new(future); + unsafe { + shared_payload.add_task(0/* todo */, asid, task.task_repr()); + } +} + use syscall::*; pub fn exit(exit_code: i32) -> SyscallResult { sys_exit(exit_code) } pub fn do_yield(next_asid: usize) -> SyscallResult { sys_yield(next_asid) } -pub fn test_write(buf: &[u8]) -> SyscallResult { unsafe { sys_test_write(ADDRESS_SPACE_ID, buf) }} +pub fn test_write(buf: &[u8]) -> SyscallResult { sys_test_write(buf) } mod syscall { const MODULE_PROCESS: usize = 0x114514; const MODULE_TEST_INTERFACE: usize = 0x233666; @@ -186,51 +229,23 @@ mod syscall { } pub fn sys_exit(exit_code: i32) -> SyscallResult { - syscall_1(MODULE_PROCESS, FUNC_PROCESS_EXIT, exit_code as usize) // 暂时放着,写法不规范 + syscall_1(MODULE_PROCESS, FUNC_PROCESS_EXIT, exit_code as usize) } - pub fn sys_panic() -> SyscallResult { - syscall_0(MODULE_PROCESS, FUNC_PROCESS_PANIC) - } + pub fn sys_panic(file_name: Option<&str>, line: u32, col: u32, msg: Option<&str>) -> SyscallResult { + let (f_buf, f_len) = file_name.map(|s| (s.as_ptr() as usize, s.len())).unwrap_or((0, 0)); + let (m_buf, m_len) = msg.map(|s| (s.as_ptr() as usize, s.len())).unwrap_or((0, 0)); + syscall_6( + MODULE_PROCESS, FUNC_PROCESS_PANIC, + [line as usize, col as usize, f_buf, f_len, m_buf, m_len] + ) + } pub fn sys_yield(next_asid: usize) -> SyscallResult { todo!() } - pub fn sys_test_write(asid: usize, buf: &[u8]) -> SyscallResult { - syscall_4(MODULE_TEST_INTERFACE, FUNC_TEST_WRITE, [asid, 0, buf.as_ptr() as usize, buf.len()]) + pub fn sys_test_write(buf: &[u8]) -> SyscallResult { + syscall_3(MODULE_TEST_INTERFACE, FUNC_TEST_WRITE, [0, buf.as_ptr() as usize, buf.len()]) } } - -#[macro_use] -pub mod console { - use core::fmt::{self, Write}; - use super::test_write; - - struct Stdout; - - impl Write for Stdout { - fn write_str(&mut self, s: &str) -> fmt::Result { - test_write(s.as_bytes()); - Ok(()) - } - } - - pub fn print(args: fmt::Arguments) { - Stdout.write_fmt(args).unwrap(); - } - - #[macro_export] - macro_rules! print { - ($fmt: literal $(, $($arg: tt)+)?) => { - $crate::console::print(format_args!($fmt $(, $($arg)+)?)); - } - } - - #[macro_export] - macro_rules! println { - ($fmt: literal $(, $($arg: tt)+)?) => { - $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)); - } - } -} \ No newline at end of file diff --git a/tornado-user/src/shared.rs b/tornado-user/src/shared.rs index d4ae185..ad6e86f 100644 --- a/tornado-user/src/shared.rs +++ b/tornado-user/src/shared.rs @@ -1,123 +1,121 @@ -use crate::do_yield; -use crate::println; - -//! 尝试在用户态给共享调度器添加任务 -use super::task::{TaskResult, UserTask}; -use woke::waker_ref; -use alloc::sync::Arc; -use core::{mem, task::{Poll, Context}}; -use core::ptr::NonNull; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[repr(C)] -pub struct SharedTaskHandle { - /// 处理核编号 - pub(crate) hart_id: usize, - /// 地址空间编号 - pub(crate) address_space_id: AddressSpaceId, - /// task_ptr 是 Arc 的虚拟地址 - pub(crate) task_ptr: usize, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[repr(C)] -pub struct AddressSpaceId(u16); - -impl AddressSpaceId { - // todo: 可见性 - pub unsafe fn from_raw(asid: usize) -> AddressSpaceId { - AddressSpaceId(asid as u16) - } -} - -pub extern "C" fn user_should_switch(_handle: &SharedTaskHandle) -> bool { - false -} - -// 该执行器目前是测试使用,当轮询到一个完成的任务就退出了 -pub fn run_until_idle( - peek_task: impl Fn() -> TaskResult, - delete_task: impl Fn(usize) -> bool, -) { - loop { - let task = peek_task(); - println!(">>> user executor: next task = {:x?}", task); - match task { - TaskResult::Task(task_repr) => { - // 在相同的(内核)地址空间里面 - let task: Arc = unsafe { Arc::from_raw(task_repr as *mut _) }; - task.mark_sleep(); - // make a waker for our task - let waker = waker_ref(&task); - // poll our future and give it a waker - let mut context = Context::from_waker(&*waker); - - let ret = task.future.lock().as_mut().poll(&mut context); - if let Poll::Pending = ret { - mem::forget(task); // 不要释放task的内存,它将继续保存在内存中被使用 - } else { - delete_task(task_repr); - } - }, - TaskResult::ShouldYield(next_asid) => { - // 让出操作 - do_yield(next_asid); - }, - TaskResult::Finished => break - } - } -} - -/// 共享载荷 -#[repr(C)] -pub struct SharedPayload { - shared_scheduler: NonNull<()>, - shared_add_task: unsafe extern "C" fn(NonNull<()>, usize, AddressSpaceId, usize) -> bool, - shared_peek_task: unsafe extern "C" fn(NonNull<()>, extern "C" fn(&SharedTaskHandle) -> bool) -> TaskResult, - shared_delete_task: unsafe extern "C" fn(NonNull<()>, usize) -> bool, -} - -type SharedPayloadAsUsize = [usize; 6]; // 编译时基地址,(已清空)初始化函数,共享调度器地址,添加函数,弹出函数 -type SharedPayloadRaw = ( - usize, // 编译时基地址,转换后类型占位,不使用 - usize, // 初始化函数已清空,不适用 - NonNull<()>, - unsafe extern "C" fn(NonNull<()>, usize, AddressSpaceId, usize) -> bool, - unsafe extern "C" fn(NonNull<()>, extern "C" fn(&SharedTaskHandle) -> bool) -> TaskResult, - unsafe extern "C" fn(NonNull<()>, usize) -> bool, -); - -impl SharedPayload { - pub unsafe fn new(base: usize) -> Self { - let mut payload_usize = *(base as *const SharedPayloadAsUsize); - let compiled_offset = payload_usize[0]; - for (i, idx) in payload_usize.iter_mut().enumerate() { - if i == 0 || i == 1 { - continue - } - *idx = idx.wrapping_sub(compiled_offset).wrapping_add(base); - } - let raw_table: SharedPayloadRaw = mem::transmute(payload_usize); - Self { - shared_scheduler: raw_table.2, - shared_add_task: raw_table.3, - shared_peek_task: raw_table.4, - shared_delete_task: raw_table.5, - } - } - - pub unsafe fn add_task(&self, hart_id: usize, address_space_id: AddressSpaceId, task_repr: usize) -> bool { - let f = self.shared_add_task; - f(self.shared_scheduler, hart_id, address_space_id, task_repr) - } - - pub unsafe fn peek_task(&self, should_yield: extern "C" fn(&SharedTaskHandle) -> bool) -> TaskResult { - let f = self.shared_peek_task; - f(self.shared_scheduler, should_yield) - } - - pub unsafe fn delete_task(&self, task_repr: usize) -> bool { - let f = self.shared_delete_task; - f(self.shared_scheduler, task_repr) - } -} +use crate::do_yield; +use crate::println; + +//! 尝试在用户态给共享调度器添加任务 +use super::task::{TaskResult, UserTask}; +use woke::waker_ref; +use alloc::sync::Arc; +use core::{mem, task::{Poll, Context}}; +use core::ptr::NonNull; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[repr(C)] +pub struct SharedTaskHandle { + /// 处理核编号 + pub(crate) hart_id: usize, + /// 地址空间编号 + pub(crate) address_space_id: AddressSpaceId, + /// task_ptr 是 Arc 的虚拟地址 + pub(crate) task_ptr: usize, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(C)] +pub struct AddressSpaceId(u16); + +impl AddressSpaceId { + // todo: 可见性 + pub unsafe fn from_raw(asid: usize) -> AddressSpaceId { + AddressSpaceId(asid as u16) + } +} + +pub extern "C" fn user_should_switch(_handle: &SharedTaskHandle) -> bool { + false +} + +// 该执行器目前是测试使用,当轮询到一个完成的任务就退出了 +pub fn run_until_ready( + peek_task: impl Fn() -> TaskResult, + delete_task: impl Fn(usize) -> bool, +) { + loop { + let task = peek_task(); + println!(">>> user executor: next task = {:x?}", task); + match task { + TaskResult::Task(task_repr) => { // 在相同的地址空间里面 + let task: Arc = unsafe { Arc::from_raw(task_repr as *mut _) }; + let waker = waker_ref(&task); + let mut context = Context::from_waker(&*waker); + println!(">>> User executor: task = {:p}", task); + let ret = task.future.lock().as_mut().poll(&mut context); + if let Poll::Pending = ret { + mem::forget(task); // 不要释放task的内存,它将继续保存在内存中被使用 + } else { + delete_task(task_repr); + } + }, + TaskResult::ShouldYield(next_asid) => { + // 让出操作 + do_yield(next_asid); + }, + TaskResult::Finished => { + break; + } + } + } +} + +/// 共享载荷 +#[repr(C)] +pub struct SharedPayload { + shared_scheduler: NonNull<()>, + shared_add_task: unsafe extern "C" fn(NonNull<()>, usize, AddressSpaceId, usize) -> bool, + shared_peek_task: unsafe extern "C" fn(NonNull<()>, extern "C" fn(&SharedTaskHandle) -> bool) -> TaskResult, + shared_delete_task: unsafe extern "C" fn(NonNull<()>, usize) -> bool, +} + +type SharedPayloadAsUsize = [usize; 6]; // 编译时基地址,(已清空)初始化函数,共享调度器地址,添加函数,弹出函数 +type SharedPayloadRaw = ( + usize, // 编译时基地址,转换后类型占位,不使用 + usize, // 初始化函数已清空,不适用 + NonNull<()>, + unsafe extern "C" fn(NonNull<()>, usize, AddressSpaceId, usize) -> bool, + unsafe extern "C" fn(NonNull<()>, extern "C" fn(&SharedTaskHandle) -> bool) -> TaskResult, + unsafe extern "C" fn(NonNull<()>, usize) -> bool, +); + +impl SharedPayload { + pub unsafe fn new(base: usize) -> Self { + let mut payload_usize = *(base as *const SharedPayloadAsUsize); + let compiled_offset = payload_usize[0]; + for (i, idx) in payload_usize.iter_mut().enumerate() { + if i == 0 || i == 1 { + continue + } + *idx = idx.wrapping_sub(compiled_offset).wrapping_add(base); + } + let raw_table: SharedPayloadRaw = mem::transmute(payload_usize); + Self { + shared_scheduler: raw_table.2, + shared_add_task: raw_table.3, + shared_peek_task: raw_table.4, + shared_delete_task: raw_table.5, + } + } + + pub unsafe fn add_task(&self, hart_id: usize, address_space_id: AddressSpaceId, task_repr: usize) -> bool { + let f = self.shared_add_task; + f(self.shared_scheduler, hart_id, address_space_id, task_repr) + } + + pub unsafe fn peek_task(&self, should_yield: extern "C" fn(&SharedTaskHandle) -> bool) -> TaskResult { + let f = self.shared_peek_task; + f(self.shared_scheduler, should_yield) + } + + pub unsafe fn delete_task(&self, task_repr: usize) -> bool { + let f = self.shared_delete_task; + f(self.shared_scheduler, task_repr) + } +} diff --git a/tornado-user/src/task.rs b/tornado-user/src/task.rs index 18e923f..425099b 100644 --- a/tornado-user/src/task.rs +++ b/tornado-user/src/task.rs @@ -13,15 +13,12 @@ use core::pin::Pin; use alloc::boxed::Box; use core::future::Future; use core::sync::atomic::{AtomicUsize, Ordering}; -use super::shared::{AddressSpaceId}; /// 临时的用户态任务实现 pub struct UserTask { /// 任务的编号 pub id: UserTaskId, - /// 任务所属的地址空间 - pub asid: AddressSpaceId, /// 任务信息的可变部分 pub inner: Mutex, /// 任务的 future @@ -64,7 +61,6 @@ impl UserTask { Arc::new( UserTask { id, - asid: unsafe { AddressSpaceId::from_raw(crate::ADDRESS_SPACE_ID) }, inner: Mutex::new(UserTaskInner { sleeping: false, finished: false,