进程管理

2024-05-27

最后编辑于:2024-09-15

    #OS
    #RISC-V
    #Fusion

进程管理

Fusion使用无栈协程来进行任务管理和调度。利用Rust语言的异步机制,可以改进操作系统内核的模块结构,优化操作系统内核的并发性能。

无栈协程

任务/协程: 是Fusion中最基本的调度单位。根据任务切换的时机可以分为:

  • 抢占式:随时可能切换(时钟中断),需要保存较多状态,切换开销大
  • 协作式:调用特定操作时发生切换,保存状态少,切换开销小

无栈体现在,协程的局部变量不保存在栈上,切换时只会切换状态机指向和部分寄存器

协程在执行时进行状态机转移。每个线程内可以有多个协程。编译器会将async标记的代码块转化为一个状态机,而状态机的大小在编译器即可以确定。

使用无栈协程的优势

  • 不需要为每个协程分配独立的堆栈空间。
  • 协程只可能在有限的await处切换,硬刺只需保存和恢复少量的状态信息,相比于传统的线程上下文切换,任务切换开销更低。

async函数嵌套使用时,调用者的状态机会包含对被调用者的状态机的引用,并在适当的时候await这个状态机。每个状态机只负责自身的状态,不需要嵌套在其他状态机中,从而避免了深层次嵌套带来的内存开销。在进行任务切换时,执行器只需改变对应状态机的指针。

任务结构的设计

Fusion将任务分为两块,信息部分和状态部分。 任务部分对外共享,可以被其他任务访问。状态部分对任务私有,只能由该任务内部访问

为了让任务支持异步执行,定义了TaskFut并实现了Future trait

#[pin_project]
pub struct TaskFut<F> {
	virt: Pin<Arsc<Virt>>,
	#[pin]
	fut: F,
}

任务在创建分配资源之后,传递给执行器进行调度

let fut = TaskFut::new(ts.virt.clone(), user_loop(ts, self.tf));
executor().spawn(fut).detach();

其中任务运行在user_loop中。在此循环中,任务按照以下流程执行

  • 处理信号
  • 切换至用户态
  • 处理scause(中断、异常、系统调用)

在内核启动时,完成硬件初始化后便会启动run_art异步运行时

任务调度

Fusion的任务调度基于async-task的调用实现,支持多核心、软抢占和任务窃取。 调度器为每一个调度核心维护一个FIFO任务队列一个抢占槽。每个调度核心的任务获取按照以下优先级顺序

  1. 抢占槽
  2. 自身调度队列
  3. 其他调度队列

参考资料