Move task state into shared task handle

This commit is contained in:
luojia65 2021-04-24 00:38:39 +08:00
parent f607542369
commit a873416449
20 changed files with 262 additions and 195 deletions

View File

@ -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 \

View File

@ -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>;
}

View File

@ -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], // 只读

View File

@ -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
}

View File

@ -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}}

View File

@ -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) },
);
// 进入用户态

View File

@ -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

View File

@ -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 {

View File

@ -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)
}
}

View File

@ -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)

View File

@ -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
}
}

View File

@ -20,7 +20,7 @@ pub use shared::{
#[allow(dead_code)] // value is constructed elsewhere
pub enum TaskResult {
/// 应当立即执行特定任务
Task(SharedTaskHandle),
Task(usize),
/// 其它地址空间的任务要运行,应当让出时间片
ShouldYield(usize),
/// 队列已空,所有任务已经结束

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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}}

View File

@ -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));
// 用户态退出的系统调用

View File

@ -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 {

View File

@ -21,7 +21,9 @@ SECTIONS
*(.data .data.*)
}
.bss : {
sbss = .;
*(.bss .bss.*)
ebss = .;
}
/DISCARD/ : {
*(.eh_frame)

View File

@ -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)
}
}

View File

@ -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,
}
}