Move task state into shared task handle
This commit is contained in:
parent
f607542369
commit
a873416449
4
justfile
4
justfile
|
@ -1,6 +1,6 @@
|
|||
target := "riscv64imac-unknown-none-elf"
|
||||
mode := "debug"
|
||||
user-mode := "release"
|
||||
user-mode := "debug"
|
||||
build-path := "target/" + target + "/" + mode + "/"
|
||||
app-path := "target/" + target + "/" + user-mode + "/"
|
||||
|
||||
|
@ -48,7 +48,7 @@ size: build
|
|||
@{{size}} -A -x {{kernel-elf}}
|
||||
@{{size}} -A -x {{shared-elf}}
|
||||
|
||||
debug app: build build-shared
|
||||
debug app: build build-shared (build-user app)
|
||||
@qemu-system-riscv64 \
|
||||
-machine virt \
|
||||
-nographic \
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
use alloc::collections::LinkedList;
|
||||
|
||||
pub struct FifoScheduler<T> {
|
||||
pool: LinkedList<T>,
|
||||
}
|
||||
|
||||
impl<T> FifoScheduler<T> {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
pool: LinkedList::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> Scheduler<T> for FifoScheduler<T> {
|
||||
fn insert(&mut self, task: T) {
|
||||
self.pool.push_back(task)
|
||||
}
|
||||
fn peek(&self) -> Option<&T> {
|
||||
self.pool.front()
|
||||
}
|
||||
fn peek_mut(&mut self) -> Option<&mut T> {
|
||||
self.pool.front_mut()
|
||||
}
|
||||
fn pop(&mut self) -> Option<T> {
|
||||
self.pool.pop_front()
|
||||
}
|
||||
fn remove(&mut self, task: &T) -> Option<T> {
|
||||
self.pool.drain_filter(|t| t == task).next()
|
||||
}
|
||||
}
|
||||
|
||||
/// 调度器实例需要实现的 Trait
|
||||
///
|
||||
pub trait Scheduler<T> {
|
||||
/// 向调度器中添加一个任务
|
||||
fn insert(&mut self, task: T);
|
||||
/// 获取下一个任务的引用,但不弹出任务
|
||||
fn peek(&self) -> Option<&T>;
|
||||
/// 获取下一个任务的可变引用,但不弹出任务
|
||||
fn peek_mut(&mut self) -> Option<&mut T>;
|
||||
/// 弹出下一个任务
|
||||
fn pop(&mut self) -> Option<T>;
|
||||
/// 移除一个任务
|
||||
fn remove(&mut self, task: &T) -> Option<T>;
|
||||
}
|
|
@ -20,12 +20,19 @@ mod task;
|
|||
mod mm;
|
||||
|
||||
use buddy_system_allocator::LockedHeap;
|
||||
use core::ptr::NonNull;
|
||||
use crate::task::{SharedTaskHandle, FfiOption, TaskResult, SharedScheduler, SHARED_SCHEDULER, shared_add_task, shared_pop_task};
|
||||
use core::{mem::MaybeUninit, ptr::NonNull};
|
||||
use crate::task::{
|
||||
SharedTaskHandle, TaskResult, TaskRepr, SharedScheduler, SHARED_SCHEDULER,
|
||||
shared_add_task, shared_peek_task, shared_delete_task,
|
||||
};
|
||||
use crate::mm::AddressSpaceId;
|
||||
|
||||
#[global_allocator]
|
||||
static HEAP: LockedHeap = LockedHeap::empty();
|
||||
|
||||
const HEAP_SIZE: usize = 128 * 1024;
|
||||
static HEAP_MEMORY: MaybeUninit<[u8; HEAP_SIZE]> = core::mem::MaybeUninit::uninit();
|
||||
|
||||
#[cfg_attr(not(test), panic_handler)]
|
||||
pub fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! {
|
||||
println!("[shared scheduler] panic: {:?}", panic_info);
|
||||
|
@ -45,14 +52,16 @@ pub static SHARED_RAW_TABLE: (
|
|||
&'static u8, // 载荷编译时的基地址
|
||||
unsafe extern "C" fn() -> PageList, // 初始化函数,执行完之后,内核将函数指针置空
|
||||
&'static SharedScheduler, // 共享调度器的地址
|
||||
unsafe extern "C" fn(NonNull<()>, SharedTaskHandle) -> FfiOption<SharedTaskHandle>,
|
||||
unsafe extern "C" fn(NonNull<()>, usize, AddressSpaceId, TaskRepr) -> bool,
|
||||
unsafe extern "C" fn(NonNull<()>, extern "C" fn(&SharedTaskHandle) -> bool) -> TaskResult,
|
||||
unsafe extern "C" fn(NonNull<()>, TaskRepr) -> bool,
|
||||
) = (
|
||||
unsafe { &payload_compiled_start },
|
||||
init_payload_environment,
|
||||
&SHARED_SCHEDULER,
|
||||
shared_add_task,
|
||||
shared_pop_task,
|
||||
shared_peek_task,
|
||||
shared_delete_task,
|
||||
);
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
|
@ -72,6 +81,9 @@ extern "C" {
|
|||
unsafe extern "C" fn init_payload_environment() -> PageList {
|
||||
// 初始化零初始段,每次写入一个u32类型的零内存
|
||||
r0::zero_bss(&mut sbss, &mut ebss);
|
||||
// 初始化堆
|
||||
let heap_start = HEAP_MEMORY.as_ptr() as usize;
|
||||
HEAP.lock().init(heap_start, HEAP_SIZE);
|
||||
// 返回一个表,表示本共享载荷应当保护的地址范围
|
||||
PageList {
|
||||
rodata: [&srodata_page, &erodata_page], // 只读
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
//! 共享任务调度器
|
||||
use crate::algorithm::{Scheduler, RingFifoScheduler};
|
||||
use crate::mm::AddressSpaceId;
|
||||
use core::{ptr::NonNull, usize};
|
||||
use core::ptr::NonNull;
|
||||
use spin::Mutex;
|
||||
use alloc::sync::Arc;
|
||||
|
||||
/// 共享调度器返回的结果
|
||||
// 不应该移除,这对FFI是安全的,我们只考虑Rust用户,其它语言自己想办法
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub enum TaskResult {
|
||||
/// 应当立即执行特定任务
|
||||
Task(SharedTaskHandle),
|
||||
/// 应当立即执行特定任务,里面是表示形式
|
||||
// 如果不释放任务,再次执行,还是会得到相同的任务,必须释放任务
|
||||
Task(TaskRepr),
|
||||
/// 其他地址空间的任务要运行,应当让出时间片
|
||||
/// 并返回下一个地址空间的编号
|
||||
ShouldYield(usize),
|
||||
|
@ -18,6 +20,11 @@ pub enum TaskResult {
|
|||
Finished
|
||||
}
|
||||
|
||||
/// 任务的表示形式
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct TaskRepr(usize);
|
||||
|
||||
/// 共享调度器的类型
|
||||
pub type SharedScheduler = Mutex<RingFifoScheduler<SharedTaskHandle, 100>>;
|
||||
|
||||
|
@ -26,7 +33,7 @@ pub type SharedScheduler = Mutex<RingFifoScheduler<SharedTaskHandle, 100>>;
|
|||
pub static SHARED_SCHEDULER: SharedScheduler = Mutex::new(RingFifoScheduler::new());
|
||||
|
||||
/// 共享任务的句柄
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
#[repr(C)]
|
||||
pub struct SharedTaskHandle {
|
||||
/// 运行此任务的硬件线程编号
|
||||
|
@ -34,7 +41,34 @@ pub struct SharedTaskHandle {
|
|||
/// 地址空间的编号
|
||||
pub(crate) address_space_id: AddressSpaceId,
|
||||
// 元数据指针,由所在的地址空间解释
|
||||
_task_ptr: usize,
|
||||
task_repr: TaskRepr,
|
||||
// 内部变量,仅供调度器使用,类型为Option<Arc<()>>
|
||||
owned_ref_counter: usize,
|
||||
}
|
||||
|
||||
impl Clone for SharedTaskHandle {
|
||||
fn clone(&self) -> Self {
|
||||
let counter = self.owned_ref_counter as *const ();
|
||||
let arc = unsafe { Arc::from_raw(counter) };
|
||||
let arc2 = arc.clone();
|
||||
// let (s, w) = (Arc::strong_count(&arc), Arc::weak_count(&arc));
|
||||
core::mem::forget(arc);
|
||||
// println!("After clone: {:p}, strong: {}, weak: {}", counter, s, w);
|
||||
SharedTaskHandle {
|
||||
owned_ref_counter: Arc::into_raw(arc2) as usize,
|
||||
..*self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SharedTaskHandle {
|
||||
fn drop(&mut self) {
|
||||
let counter = self.owned_ref_counter as *const ();
|
||||
let arc = unsafe { Arc::from_raw(counter) };
|
||||
// let (s, w) = (Arc::strong_count(&arc), Arc::weak_count(&arc));
|
||||
drop(arc);
|
||||
// println!("After drop: {:p}, strong: {}, weak: {}", counter, s, w);
|
||||
}
|
||||
}
|
||||
|
||||
/// 给共享调度器添加任务
|
||||
|
@ -42,51 +76,74 @@ pub struct SharedTaskHandle {
|
|||
/// 在内核态和用户态都可以调用
|
||||
pub unsafe extern "C" fn shared_add_task(
|
||||
shared_scheduler: NonNull<()>,
|
||||
handle: SharedTaskHandle
|
||||
) -> FfiOption<SharedTaskHandle> { // 如果未来有FFI-safe core::option::Option,换掉这个返回值
|
||||
hart_id: usize,
|
||||
address_space_id: AddressSpaceId,
|
||||
task_repr: TaskRepr,
|
||||
) -> bool { // 本次比赛的设计比较简单,true表示成功,false表示失败
|
||||
// println!("[Shared add task] {:p} {} {:?} {:x?}", shared_scheduler, hart_id, address_space_id, task_repr);
|
||||
let s: NonNull<SharedScheduler> = shared_scheduler.cast();
|
||||
let handle = prepare_handle(hart_id, address_space_id, task_repr);
|
||||
let mut scheduler = s.as_ref().lock();
|
||||
scheduler.add_task(handle).into()
|
||||
scheduler.add_task(handle).is_none()
|
||||
}
|
||||
|
||||
/// 从共享调度器中弹出一个任务
|
||||
#[inline] unsafe fn prepare_handle(
|
||||
hart_id: usize,
|
||||
address_space_id: AddressSpaceId,
|
||||
task_repr: TaskRepr,
|
||||
) -> SharedTaskHandle {
|
||||
let counter = Arc::new(());
|
||||
let ptr = Arc::into_raw(counter);
|
||||
SharedTaskHandle {
|
||||
hart_id,
|
||||
address_space_id,
|
||||
task_repr,
|
||||
owned_ref_counter: ptr as usize
|
||||
}
|
||||
}
|
||||
|
||||
/// 从共享调度器中找到下一个任务
|
||||
///
|
||||
/// 在内核态和用户态都可以调用
|
||||
pub unsafe extern "C" fn shared_pop_task(
|
||||
pub unsafe extern "C" fn shared_peek_task(
|
||||
shared_scheduler: NonNull<()>,
|
||||
should_switch: extern "C" fn(&SharedTaskHandle) -> bool
|
||||
) -> TaskResult {
|
||||
// 得到共享调度器的引用
|
||||
// println!("[Shared peek task] {:p} {:x}", shared_scheduler, should_switch as usize);
|
||||
let mut s: NonNull<SharedScheduler> = shared_scheduler.cast();
|
||||
let mut scheduler = s.as_mut().lock();
|
||||
let scheduler = s.as_mut().lock();
|
||||
if let Some(task) = scheduler.peek_next_task() {
|
||||
// println!("Pop task {:x?}!", task);
|
||||
if should_switch(task) {
|
||||
// 如果需要跳转到其他地址空间,则不弹出任务,返回需要跳转到的地址空间编号
|
||||
return TaskResult::ShouldYield(task.address_space_id.into_inner())
|
||||
}
|
||||
// 从共享调度器弹出任务交给调用者
|
||||
let next_task = scheduler.next_task().unwrap();
|
||||
// 直接把任务交给调用者
|
||||
let task_repr = task.task_repr;
|
||||
drop(scheduler); // 释放锁
|
||||
return TaskResult::Task(next_task)
|
||||
return TaskResult::Task(task_repr)
|
||||
// 调用者拿到任务后,执行此任务,然后必须销毁任务,否则任务会被重新拿出来再执行一次
|
||||
} else {
|
||||
// 没有任务了,返回已完成
|
||||
return TaskResult::Finished;
|
||||
}
|
||||
}
|
||||
|
||||
// 跨FFI边界安全的Option枚举结构
|
||||
#[repr(C)]
|
||||
pub enum FfiOption<T> {
|
||||
None,
|
||||
Some(T),
|
||||
}
|
||||
|
||||
impl<T> From<Option<T>> for FfiOption<T> {
|
||||
fn from(src: Option<T>) -> FfiOption<T> {
|
||||
if let Some(t) = src {
|
||||
FfiOption::Some(t)
|
||||
/// 删除一个共享调度器中的任务
|
||||
pub unsafe extern "C" fn shared_delete_task(
|
||||
shared_scheduler: NonNull<()>,
|
||||
task_repr: TaskRepr,
|
||||
) -> bool {
|
||||
let mut s: NonNull<SharedScheduler> = shared_scheduler.cast();
|
||||
let mut scheduler = s.as_mut().lock();
|
||||
let next_handle = scheduler.next_task();
|
||||
if let Some(handle) = next_handle {
|
||||
if handle.task_repr == task_repr {
|
||||
return true
|
||||
} else {
|
||||
FfiOption::None
|
||||
return false // panic!("delete a previous task is not currently supported")
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
|
@ -6,9 +6,17 @@ kernel-elf := build-path + "tornado-kernel"
|
|||
kernel-bin := build-path + "tornado-kernel.bin"
|
||||
|
||||
objcopy := "rust-objcopy --binary-architecture=riscv64"
|
||||
objdump := "riscv64-unknown-elf-objdump"
|
||||
size := "rust-size"
|
||||
|
||||
build: kernel
|
||||
@{{objcopy}} {{kernel-elf}} --strip-all -O binary {{kernel-bin}}
|
||||
|
||||
kernel:
|
||||
@cargo build --target={{target}}
|
||||
|
||||
asm: build
|
||||
@{{objdump}} -D {{kernel-elf}} | less
|
||||
|
||||
size: build
|
||||
@{{size}} -A -x {{kernel-elf}}
|
||||
|
|
|
@ -101,6 +101,8 @@ pub extern "C" fn rust_main(hart_id: usize) -> ! {
|
|||
let shared_payload = unsafe { task::SharedPayload::load(0x8600_0000) };
|
||||
|
||||
let process = task::Process::new(kernel_memory).expect("create process 1");
|
||||
let hart_id = crate::hart::KernelHartInfo::hart_id();
|
||||
let address_space_id = process.address_space_id();
|
||||
let stack_handle = process.alloc_stack().expect("alloc initial stack");
|
||||
let task_1 = task::KernelTask::new(task_1(), process.clone());
|
||||
let task_2 = task::KernelTask::new(task_2(), process.clone());
|
||||
|
@ -109,14 +111,14 @@ pub extern "C" fn rust_main(hart_id: usize) -> ! {
|
|||
println!("task_2: {:?}", task_2);
|
||||
println!("task_3: {:?}", task_3);
|
||||
unsafe {
|
||||
shared_payload.add_task(task_1.shared_task_handle());
|
||||
shared_payload.add_task(task_2.shared_task_handle());
|
||||
shared_payload.add_task(task_3.shared_task_handle());
|
||||
shared_payload.add_task(hart_id, address_space_id, task_1.task_repr());
|
||||
shared_payload.add_task(hart_id, address_space_id, task_2.task_repr());
|
||||
shared_payload.add_task(hart_id, address_space_id, task_3.task_repr());
|
||||
}
|
||||
|
||||
task::run_until_idle(
|
||||
|| unsafe { shared_payload.pop_task(task::kernel_should_switch) },
|
||||
|handle| unsafe { shared_payload.add_task(handle) }
|
||||
|| unsafe { shared_payload.peek_task(task::kernel_should_switch) },
|
||||
|task_repr| unsafe { shared_payload.delete_task(task_repr) },
|
||||
);
|
||||
|
||||
// 进入用户态
|
||||
|
|
|
@ -131,8 +131,8 @@ impl MemorySet {
|
|||
let mut mapping = Mapping::new_alloc()?;
|
||||
let allocated_pairs = Vec::new();
|
||||
|
||||
let va_range = VirtualAddress(0)..VirtualAddress(PAGE_SIZE * 20);
|
||||
let pa_range = PhysicalAddress(base)..PhysicalAddress(base + PAGE_SIZE * 20);
|
||||
let va_range = VirtualAddress(0)..VirtualAddress(PAGE_SIZE * 200);
|
||||
let pa_range = PhysicalAddress(base)..PhysicalAddress(base + PAGE_SIZE * 200);
|
||||
mapping.map_defined(&va_range, &pa_range, Flags::EXECUTABLE | Flags::READABLE | Flags::WRITABLE | Flags::USER);
|
||||
|
||||
// 映射 _swap_frame
|
||||
|
@ -152,8 +152,8 @@ impl MemorySet {
|
|||
|
||||
// 映射共享运行时段
|
||||
// 目前共享运行时写死在 0x86000000 这个物理地址上
|
||||
let va_range = VirtualAddress(0x8600_0000)..VirtualAddress(0x8640_0000);
|
||||
let pa_range = PhysicalAddress(0x8600_0000)..PhysicalAddress(0x8640_0000);
|
||||
let va_range = VirtualAddress(0x8600_0000)..VirtualAddress(0x8680_0000);
|
||||
let pa_range = PhysicalAddress(0x8600_0000)..PhysicalAddress(0x8680_0000);
|
||||
mapping.map_defined(&va_range, &pa_range, Flags::WRITABLE | Flags::READABLE | Flags::EXECUTABLE | Flags::USER);
|
||||
|
||||
let address_space_id = crate::hart::KernelHartInfo::alloc_address_space_id()?; // todo: 释放asid
|
||||
|
|
|
@ -14,6 +14,7 @@ pub fn init() {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[repr(C)]
|
||||
pub struct AddressSpaceId(u16); // in Sv39, [0, 2^16)
|
||||
|
||||
impl AddressSpaceId {
|
||||
|
|
|
@ -47,7 +47,7 @@ pub extern "C" fn user_trap_handler() {
|
|||
}
|
||||
trap::switch_to_user(swap_cx, user_satp.inner())
|
||||
}
|
||||
_ => todo!("scause: {:?}, sepc: {:#x}, stval: {:#x}", scause::read().cause(), sepc::read(), stval::read())
|
||||
_ => todo!("scause: {:?}, sepc: {:#x}, stval: {:#x}, {:x?}", scause::read().cause(), sepc::read(), stval::read(), swap_cx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,27 +8,17 @@ use core::{mem, task::{Poll, Context}};
|
|||
切换上下文时,要把上下文保存好,最终还是要回到切换的地方继续运行。
|
||||
*/
|
||||
|
||||
pub fn run_until_idle<F, G>(pop_task: F, push_task: G)
|
||||
where
|
||||
F: Fn() -> TaskResult,
|
||||
G: Fn(SharedTaskHandle) -> Option<SharedTaskHandle>
|
||||
{
|
||||
pub fn run_until_idle(
|
||||
peek_task: impl Fn() -> TaskResult,
|
||||
delete_task: impl Fn(usize) -> bool,
|
||||
) {
|
||||
loop {
|
||||
let task = pop_task();
|
||||
if let TaskResult::Task(handle) = task {
|
||||
let task: Arc<KernelTask> = unsafe { Arc::from_raw(handle.task_ptr as *mut _) };
|
||||
if task.is_sleeping() {
|
||||
mem::forget(task); // 不要释放内存
|
||||
push_task(handle);
|
||||
continue
|
||||
}
|
||||
mem::forget(task); // 不要释放内存
|
||||
}
|
||||
println!(">>> next task = {:x?}", task);
|
||||
let task = peek_task();
|
||||
println!(">>> kernel executor: next task = {:x?}", task);
|
||||
match task {
|
||||
TaskResult::Task(handle) => {
|
||||
TaskResult::Task(task_repr) => {
|
||||
// 在相同的(内核)地址空间里面
|
||||
let task: Arc<KernelTask> = unsafe { Arc::from_raw(handle.task_ptr as *mut _) };
|
||||
let task: Arc<KernelTask> = unsafe { Arc::from_raw(task_repr as *mut _) };
|
||||
task.mark_sleep();
|
||||
// make a waker for our task
|
||||
let waker = waker_ref(&task);
|
||||
|
@ -39,8 +29,10 @@ where
|
|||
// println!("Ret = {:?}", ret);
|
||||
if let Poll::Pending = ret {
|
||||
mem::forget(task); // 不要释放task的内存,它将继续保存在内存中被使用
|
||||
push_task(handle);
|
||||
} // 否则,释放task的内存。这里相当于drop(task)
|
||||
} else { // 否则,释放task的内存
|
||||
delete_task(task_repr);
|
||||
// drop(task)
|
||||
}
|
||||
},
|
||||
TaskResult::ShouldYield(next_asid) => {
|
||||
todo!("切换到 next_asid (= {}) 对应的地址空间", next_asid)
|
||||
|
|
|
@ -77,12 +77,8 @@ impl KernelTask {
|
|||
/// 转换到共享的任务编号
|
||||
///
|
||||
/// note(unsafe): 创建了一个没有边界的生命周期
|
||||
pub unsafe fn shared_task_handle(self: Arc<Self>) -> SharedTaskHandle {
|
||||
SharedTaskHandle {
|
||||
hart_id: KernelHartInfo::hart_id(),
|
||||
address_space_id: self.process.address_space_id(),
|
||||
task_ptr: Arc::into_raw(self) as usize
|
||||
}
|
||||
pub unsafe fn task_repr(self: Arc<Self>) -> usize {
|
||||
Arc::into_raw(self) as usize
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ pub use shared::{
|
|||
#[allow(dead_code)] // value is constructed elsewhere
|
||||
pub enum TaskResult {
|
||||
/// 应当立即执行特定任务
|
||||
Task(SharedTaskHandle),
|
||||
Task(usize),
|
||||
/// 其它地址空间的任务要运行,应当让出时间片
|
||||
ShouldYield(usize),
|
||||
/// 队列已空,所有任务已经结束
|
||||
|
|
|
@ -40,6 +40,8 @@ pub struct SharedTaskHandle {
|
|||
/// 对每个虚拟空间来说,task_ptr是Arc<Task>相应的虚拟地址
|
||||
/// 比如内核中是内核虚拟地址,用户中是用户的虚拟地址
|
||||
pub(crate) task_ptr: usize,
|
||||
// 不关心
|
||||
_owned_ref_counter: usize,
|
||||
}
|
||||
|
||||
pub extern "C" fn kernel_should_switch(handle: &SharedTaskHandle) -> bool {
|
||||
|
@ -51,22 +53,20 @@ pub extern "C" fn kernel_should_switch(handle: &SharedTaskHandle) -> bool {
|
|||
#[repr(C)]
|
||||
pub struct SharedPayload {
|
||||
shared_scheduler: NonNull<()>,
|
||||
shared_add_task: unsafe extern "C" fn(
|
||||
shared_scheduler: NonNull<()>, handle: SharedTaskHandle
|
||||
) -> FfiOption<SharedTaskHandle>,
|
||||
shared_pop_task: unsafe extern "C" fn(
|
||||
shared_scheduler: NonNull<()>, should_switch: extern "C" fn(&SharedTaskHandle) -> bool
|
||||
) -> TaskResult
|
||||
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; 5]; // 编译时基地址,初始化函数,共享调度器地址,添加函数,弹出函数
|
||||
type SharedPayloadAsUsize = [usize; 6]; // 编译时基地址,初始化函数,共享调度器地址,添加函数,弹出函数
|
||||
type InitFunction = unsafe extern "C" fn() -> PageList;
|
||||
type SharedPayloadRaw = (
|
||||
usize, // 编译时基地址,转换后类型占位,不使用
|
||||
usize, // 初始化函数,执行完之后,内核将函数指针置空
|
||||
NonNull<()>,
|
||||
unsafe extern "C" fn(NonNull<()>, SharedTaskHandle) -> FfiOption<SharedTaskHandle>,
|
||||
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 {
|
||||
|
@ -93,47 +93,30 @@ impl SharedPayload {
|
|||
Self {
|
||||
shared_scheduler: raw_table.2,
|
||||
shared_add_task: raw_table.3,
|
||||
shared_pop_task: raw_table.4
|
||||
shared_peek_task: raw_table.4,
|
||||
shared_delete_task: raw_table.5,
|
||||
}
|
||||
}
|
||||
|
||||
/// 往共享调度器中添加任务
|
||||
pub unsafe fn add_task(&self, handle: SharedTaskHandle) -> Option<SharedTaskHandle> {
|
||||
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, handle).into()
|
||||
// println!("Add = {:x}, p1 = {:p}, p2 = {:x}, p3 = {:?}, p4 = {:x}", f as usize, self.shared_scheduler,
|
||||
// hart_id, address_space_id, task_repr);
|
||||
f(self.shared_scheduler, hart_id, address_space_id, task_repr)
|
||||
}
|
||||
|
||||
/// 从共享调度器中弹出任务
|
||||
pub unsafe fn pop_task(&self, should_yield: extern "C" fn(&SharedTaskHandle) -> bool) -> TaskResult {
|
||||
let f = self.shared_pop_task;
|
||||
/// 从共享调度器中得到下一个任务
|
||||
pub unsafe fn peek_task(&self, should_yield: extern "C" fn(&SharedTaskHandle) -> bool) -> TaskResult {
|
||||
let f = self.shared_peek_task;
|
||||
// println!("Peek = {:x}, p1 = {:p}, p2 = {:x}", f as usize, self.shared_scheduler, should_yield as usize);
|
||||
f(self.shared_scheduler, should_yield)
|
||||
}
|
||||
}
|
||||
|
||||
// 跨FFI边界安全的Option枚举结构
|
||||
#[repr(C)]
|
||||
pub enum FfiOption<T> {
|
||||
None,
|
||||
Some(T),
|
||||
}
|
||||
|
||||
impl<T> From<Option<T>> for FfiOption<T> {
|
||||
fn from(src: Option<T>) -> FfiOption<T> {
|
||||
if let Some(t) = src {
|
||||
FfiOption::Some(t)
|
||||
} else {
|
||||
FfiOption::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<FfiOption<T>> for Option<T> {
|
||||
fn from(src: FfiOption<T>) -> Option<T> {
|
||||
if let FfiOption::Some(t) = src {
|
||||
Some(t)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
/// 从共享调度器中删除任务
|
||||
pub unsafe fn delete_task(&self, task_repr: usize) -> bool {
|
||||
let f = self.shared_delete_task;
|
||||
f(self.shared_scheduler, task_repr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,10 +40,11 @@ pub fn first_enter_user(kernel_stack_top: usize) -> ! {
|
|||
// 往 SwapContext 写东西
|
||||
// 目前通过 tp 寄存器把地址空间编号传给用户,后面可能会修改
|
||||
*swap_cx = trap::SwapContext::new_to_user(
|
||||
kernel_satp, 0, user_asid, kernel_stack_top, user_stack_top, crate::syscall::user_trap_handler as usize
|
||||
kernel_satp, 0, user_asid, kernel_stack_top, user_stack_top,
|
||||
crate::trap::trap_vector as usize
|
||||
);
|
||||
|
||||
// 在这里把共享运行时中 raw_table 的地址通过 gp 寄存器传给用户
|
||||
swap_cx.set_gp(0x8600_0000);
|
||||
trap::switch_to_user(swap_cx, user_satp)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
target := "riscv64imac-unknown-none-elf"
|
||||
mode := "release"
|
||||
mode := "debug"
|
||||
build-path := "../target/" + target + "/" + mode + "/"
|
||||
|
||||
user-elf := build-path + "tornado-user"
|
||||
user-bin := build-path + "tornado-user.bin"
|
||||
|
||||
objcopy := "rust-objcopy --binary-architecture=riscv64"
|
||||
objdump := "riscv64-linux-gnu-objdump"
|
||||
objdump := "riscv64-unknown-elf-objdump"
|
||||
size := "rust-size"
|
||||
|
||||
build app: elf
|
||||
@{{objcopy}} {{build-path}}/{{app}} --strip-all -O binary {{build-path}}/{{app}}.bin
|
||||
|
||||
elf:
|
||||
@cargo build --target={{target}} --{{mode}} --bins
|
||||
@cargo build --target={{target}} --bins
|
||||
|
||||
asm app: elf
|
||||
@{{objdump}} -D {{build-path}}/{{app}} | less
|
||||
|
||||
size app: elf
|
||||
@{{size}} -A -x {{build-path}}/{{app}}
|
||||
@{{size}} -A -x {{build-path}}/{{app}}
|
||||
|
|
@ -30,11 +30,12 @@ fn main() -> ! {
|
|||
let shared_payload = unsafe { shared::SharedPayload::new(0x8600_0000) };
|
||||
let task = task::UserTask::new(FibonacciFuture::new(6));
|
||||
unsafe {
|
||||
shared_payload.add_task(task.shared_task_handle());
|
||||
/* todo: hart_id, asid */
|
||||
shared_payload.add_task(0, tornado_user::shared::AddressSpaceId::from_raw(tornado_user::ADDRESS_SPACE_ID), task.task_repr());
|
||||
}
|
||||
let ret = shared::run_until_ready(
|
||||
|| unsafe { shared_payload.pop_task(shared::user_should_switch) },
|
||||
|handle| unsafe { shared_payload.add_task(handle) }
|
||||
|| unsafe { shared_payload.peek_task(shared::user_should_switch) },
|
||||
|task_repr| unsafe { shared_payload.delete_task(task_repr) }
|
||||
);
|
||||
assert_eq!(ret, Some(8));
|
||||
// 用户态退出的系统调用
|
||||
|
|
|
@ -39,15 +39,6 @@ pub fn handle_alloc_error(_layout: core::alloc::Layout) -> ! {
|
|||
#[no_mangle]
|
||||
#[link_section = ".text.entry"]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
extern "C" {
|
||||
fn sbss(); fn ebss();
|
||||
}
|
||||
unsafe { r0::zero_bss(&mut sbss as *mut _ as *mut u64, &mut ebss as *mut _ as *mut u64) };
|
||||
unsafe {
|
||||
HEAP.lock().init(HEAP_SPACE.as_ptr() as usize, USER_HEAP_SIZE);
|
||||
}
|
||||
|
||||
|
||||
let mut ret: usize;
|
||||
unsafe {
|
||||
// 从 gp 寄存器里面取出 shared_raw_table 的地址
|
||||
|
@ -57,6 +48,15 @@ pub extern "C" fn _start() -> ! {
|
|||
asm!("mv {}, tp", out(reg) ret, options(nomem, nostack));
|
||||
ADDRESS_SPACE_ID = ret;
|
||||
}
|
||||
extern "C" {
|
||||
fn sbss(); fn ebss();
|
||||
}
|
||||
unsafe {
|
||||
r0::zero_bss(&mut sbss as *mut _ as *mut u32, &mut ebss as *mut _ as *mut u32);
|
||||
}
|
||||
unsafe {
|
||||
HEAP.lock().init(HEAP_SPACE.as_ptr() as usize, USER_HEAP_SIZE);
|
||||
}
|
||||
main()
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ mod syscall {
|
|||
}
|
||||
|
||||
pub fn sys_exit(exit_code: i32) -> SyscallResult {
|
||||
syscall_0(USER_EXIT, exit_code as usize)
|
||||
syscall_0(USER_EXIT, exit_code as usize) // 暂时放着,写法不规范
|
||||
}
|
||||
|
||||
pub fn sys_yield(next_asid: usize) -> SyscallResult {
|
||||
|
|
|
@ -21,7 +21,9 @@ SECTIONS
|
|||
*(.data .data.*)
|
||||
}
|
||||
.bss : {
|
||||
sbss = .;
|
||||
*(.bss .bss.*)
|
||||
ebss = .;
|
||||
}
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame)
|
||||
|
|
|
@ -16,13 +16,17 @@ pub struct SharedTaskHandle {
|
|||
pub(crate) address_space_id: AddressSpaceId,
|
||||
/// task_ptr 是 Arc<Task> 的虚拟地址
|
||||
pub(crate) task_ptr: usize,
|
||||
// 留给调度器使用,用户不应使用
|
||||
_private: usize,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[repr(C)]
|
||||
pub struct AddressSpaceId(u16);
|
||||
|
||||
impl AddressSpaceId {
|
||||
pub(crate) unsafe fn from_raw(asid: usize) -> AddressSpaceId {
|
||||
// todo: 可见性
|
||||
pub unsafe fn from_raw(asid: usize) -> AddressSpaceId {
|
||||
AddressSpaceId(asid as u16)
|
||||
}
|
||||
}
|
||||
|
@ -31,26 +35,16 @@ pub extern "C" fn user_should_switch(_handle: &SharedTaskHandle) -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
pub fn run_until_ready<F, G>(pop_task: F, push_task: G) -> Option<usize>
|
||||
where
|
||||
F: Fn() -> TaskResult,
|
||||
G: Fn(SharedTaskHandle) -> Option<SharedTaskHandle>
|
||||
{
|
||||
pub fn run_until_ready(
|
||||
peek_task: impl Fn() -> TaskResult,
|
||||
delete_task: impl Fn(usize) -> bool,
|
||||
) -> Option<usize> {
|
||||
loop {
|
||||
let task = pop_task();
|
||||
if let TaskResult::Task(handle) = task {
|
||||
let task: Arc<UserTask> = unsafe { Arc::from_raw(handle.task_ptr as *mut _) };
|
||||
// if task.is_sleeping() {
|
||||
// mem::forget(task); // 不要释放内存
|
||||
// push_task(handle);
|
||||
// continue
|
||||
// }
|
||||
mem::forget(task); // 不要释放内存
|
||||
}
|
||||
let task = peek_task();
|
||||
match task {
|
||||
TaskResult::Task(handle) => {
|
||||
TaskResult::Task(task_repr) => {
|
||||
// 在相同的(内核)地址空间里面
|
||||
let task: Arc<UserTask> = unsafe { Arc::from_raw(handle.task_ptr as *mut _) };
|
||||
let task: Arc<UserTask> = unsafe { Arc::from_raw(task_repr as *mut _) };
|
||||
task.mark_sleep();
|
||||
// make a waker for our task
|
||||
let waker = waker_ref(&task);
|
||||
|
@ -59,11 +53,10 @@ where
|
|||
|
||||
let ret = task.future.lock().as_mut().poll(&mut context);
|
||||
if let Poll::Ready(x) = ret {
|
||||
delete_task(task_repr);
|
||||
return Some(x);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
mem::forget(task); // 不要释放task的内存,它将继续保存在内存中被使用
|
||||
push_task(handle);
|
||||
}
|
||||
},
|
||||
TaskResult::ShouldYield(next_asid) => {
|
||||
|
@ -79,21 +72,19 @@ where
|
|||
#[repr(C)]
|
||||
pub struct SharedPayload {
|
||||
shared_scheduler: NonNull<()>,
|
||||
shared_add_task: unsafe extern "C" fn(
|
||||
shared_scheduler: NonNull<()>, handle: SharedTaskHandle
|
||||
) -> FfiOption<SharedTaskHandle>,
|
||||
shared_pop_task: unsafe extern "C" fn(
|
||||
shared_scheduler: NonNull<()>, should_switch: extern "C" fn(&SharedTaskHandle) -> bool
|
||||
) -> TaskResult
|
||||
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; 5]; // 编译时基地址,(已清空)初始化函数,共享调度器地址,添加函数,弹出函数
|
||||
type SharedPayloadAsUsize = [usize; 6]; // 编译时基地址,(已清空)初始化函数,共享调度器地址,添加函数,弹出函数
|
||||
type SharedPayloadRaw = (
|
||||
usize, // 编译时基地址,转换后类型占位,不使用
|
||||
usize, // 初始化函数已清空,不适用
|
||||
NonNull<()>,
|
||||
unsafe extern "C" fn(NonNull<()>, SharedTaskHandle) -> FfiOption<SharedTaskHandle>,
|
||||
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 {
|
||||
|
@ -110,44 +101,23 @@ impl SharedPayload {
|
|||
Self {
|
||||
shared_scheduler: raw_table.2,
|
||||
shared_add_task: raw_table.3,
|
||||
shared_pop_task: raw_table.4
|
||||
shared_peek_task: raw_table.4,
|
||||
shared_delete_task: raw_table.5,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn add_task(&self, handle: SharedTaskHandle) -> Option<SharedTaskHandle> {
|
||||
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, handle).into()
|
||||
f(self.shared_scheduler, hart_id, address_space_id, task_repr)
|
||||
}
|
||||
|
||||
pub unsafe fn pop_task(&self, should_yield: extern "C" fn(&SharedTaskHandle) -> bool) -> TaskResult {
|
||||
let f = self.shared_pop_task;
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// 跨FFI边界安全的Option枚举结构
|
||||
#[repr(C)]
|
||||
pub enum FfiOption<T> {
|
||||
None,
|
||||
Some(T),
|
||||
}
|
||||
|
||||
impl<T> From<Option<T>> for FfiOption<T> {
|
||||
fn from(src: Option<T>) -> FfiOption<T> {
|
||||
if let Some(t) = src {
|
||||
FfiOption::Some(t)
|
||||
} else {
|
||||
FfiOption::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<FfiOption<T>> for Option<T> {
|
||||
fn from(src: FfiOption<T>) -> Option<T> {
|
||||
if let FfiOption::Some(t) = src {
|
||||
Some(t)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
pub unsafe fn delete_task(&self, task_repr: usize) -> bool {
|
||||
let f = self.shared_delete_task;
|
||||
f(self.shared_scheduler, task_repr)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,13 +79,8 @@ impl UserTask {
|
|||
/// 转换到共享的任务编号
|
||||
/// 危险:创建了一个没有边界的生命周期
|
||||
|
||||
pub unsafe fn shared_task_handle(self: Arc<Self>) -> SharedTaskHandle {
|
||||
SharedTaskHandle {
|
||||
hart_id: 0,
|
||||
// todo: 地址空间编号
|
||||
address_space_id: self.asid,
|
||||
task_ptr: Arc::into_raw(self) as usize
|
||||
}
|
||||
pub unsafe fn task_repr(self: Arc<Self>) -> usize {
|
||||
Arc::into_raw(self) as usize
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,9 +107,9 @@ impl woke::Woke for UserTask {
|
|||
#[derive(Debug)]
|
||||
pub enum TaskResult {
|
||||
/// 应当立即执行特定任务
|
||||
Task(SharedTaskHandle),
|
||||
Task(usize),
|
||||
/// 其它地址空间的任务要运行,应当让出时间片
|
||||
ShouldYield(usize),
|
||||
/// 队列已空,所有任务已经结束
|
||||
Finished,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue