Skip to content

Latest commit

 

History

History
98 lines (82 loc) · 4.86 KB

进程调度-进程管理.md

File metadata and controls

98 lines (82 loc) · 4.86 KB

进程管理

进程是操作系统为任务分配资源的基本单位,而线程是操作系统调度的基本单位。FTL OS设计上进程可以被多线程所有,所有线程都是对等的,只有所有线程全部退出或执行了exit系统调用才会释放进程。这两种途径不会完全释放进程的内存,因为进程退出后需要留下为父进程留下必要的信息,进程还需要被父进程持有。因此进程的所有权树如下:

image-20220527000108143

每个线程被所在的异步Future持有,Future将不断地被调度器执行poll,直到返回了Ready后被释放。线程将不断则进行用户循环:

// kernel/src/process/userloop.rs
async fn userloop(thread: Arc<Thread>) {
    // Future从参数捕获了thread
    loop {
        // 进入用户态
        ...
        // 离开用户态处理陷阱
        ...
        if exit {
            break; // 线程在这里离开的主循环
        }
    }
    // 执行到这后poll会返回Ready(()), thread将被释放
}

每个进程都具有唯一标识符pid,目前FTL OS不支持进程生成额外的线程,因此pid在全局分配并通过pid获取线程的tidtidpid相同。但在支持多线程后需要改变获取pid的方式,先有线程获取tid,再从tid获取pidtid分配的唯一性保证了pid的唯一性。但初始线程tid的回收应该在进程释放时进行,因为初始线程释放后进程可能还被其他线程持有,此时如果立刻释放tid则下次产生的线程对应的进程会和旧进程拥有一样的pid并导致一系列错误。

FTL OS目前阶段的线程只携带了用户地址空间的上下文信息,定义如下:

pub struct Thread {
    // never change
    pub tid: Tid,
    pub process: Arc<Process>,
    // thread local
    inner: UnsafeCell<ThreadInner>,
}
pub struct ThreadInner {
    pub stack_id: StackID,
    pub set_child_tid: UserInOutPtr<u32>,
    pub clear_child_tid: UserInOutPtr<u32>,
    pub signal_mask: SignalSet,
    uk_context: Box<UKContext>,
}

ThreadInner包含了线程的局部信息。这部分信息被定义为只有线程自身才能访问,因此不需要加锁。目前线程局部信息只有uk_context被使用,其他字段处于保留状态。uk_context处于内核态时保存了用户态的上下文,处于用户态时保存了内核态的上下文,是用户态和内核态的上下文交换区。

FTL OS的进程控制块定义如下:

pub struct Process {
    pid: PidHandle,
    pub pgid: AtomicUsize,
    pub event_bus: Arc<EventBus>,
    pub alive: Mutex<Option<AliveProcess>>,
    pub exit_code: AtomicI32,
}
pub struct AliveProcess {
    pub user_space: UserSpace,
    pub cwd: Arc<VfsInode>,
    pub exec_path: String,
    pub envp: Vec<String>,
    pub parent: Option<Weak<Process>>,
    pub children: ChildrenSet,
    pub threads: ThreadGroup,
    pub fd_table: FdTable,
    pub signal_queue: LinkedList<SignalPack>,
}

可以看到进程控制块被分为了ProcessAliveProcess两个部分,Process包含了进程的不可变信息,获取这部分信息不需要加锁。AliveProcess只有在进程退出之前才有效,进程退出时会变为None并在析构函数中释放所有持有的句柄。

Process的各个字段定义如下:

字段 描述
PidHandle 进程ID句柄,析构时自动回收
pgid 进程组ID
event_bus 事件总线,其他进程访问此进程的唯一途径
alive 进程运行信息,只能被所在进程访问
exit_code 进程退出码,只有进程退出后才有效

AliveProcess的各个字段定义如下:

字段 描述
user_space 进程地址空间管理器,持有进程页表
cwd 当前命令行所在的目录
exec_path 程序执行时的目录
envp 程序执行时的环境变量
parent 此进程的父进程,如果为空说明是初始化进程
children 子进程集合
threads 运行在此进程的全部线程
fd_table 所有打开文件的映射表
signal_queue 信号队列,尚未启用

FTL OS的事件总线能够从根本上防止死锁并提高效率,但目前还没有实现全部功能,仍然允许其他进程在退出时访问AliveProcess字段。但即使只允许当前进程访问自身AliveProcess然需要被锁保护,因为进程可以拥有多个线程。