- Objective: To provide core process management system calls for applications.
- Implementation:
- Added
sys_*functions inuser/src/lib.rsto translate system calls intoecallinstructions. - Wrapped these
sys_*functions in theusrlibrary to provide familiar interfaces likefork,exec,waitpid,getpid, andread.
- Added
- Objective: To provide a basic user-space environment and test kernel functionalities.
- Implementation:
- Created several applications in
user/src/bin, includinginitproc.rsanduser_shell.rs, for both testing and core functionality.
- Created several applications in
- Objective: To load ELF executables by their names instead of a numeric ID.
- Implementation:
- Updated the
link_app.Sformat to include application names. - Provided a
get_app_data_by_nameinterface to retrieve application ELF data.
- Updated the
- Objective: To reduce coupling by separating the responsibilities of the task manager.
- Implementation:
- The
Processornow manages the currently executing task on a specific CPU. - The
ProcessManageris now only responsible for managing the state of all tasks (e.g., the ready queue).
- The
- Objective: To store additional process-related information such as PID, kernel stack, and parent-child relationships.
- Implementation:
- Evolved the
TaskControlBlockinto aPCB(Process Control Block) to support the full process model.
- Evolved the
- Objective: To select the next process to run during a context switch.
- Implementation:
- Implemented
ProcessManager::fetch(), which returns the next runnable process from the ready queue.
- Implemented
- Objective: To implement the
forkandexecsystem calls. - Implementation:
- Implemented the
sys_forkandsys_exechandlers inos/src/syscall/process.rs. - These handlers call the underlying logic in the
PCBimplementation.
- Implemented the
- Objective: To release resources after a process exits.
- Implementation:
- Partial resources are reclaimed in
exit_current_and_run_nextwhen a process exits and becomes a zombie. - All remaining resources are freed when the parent process calls
waitpidand collects the exit code.
- Partial resources are reclaimed in
- Objective: To allow the
user_shellto read user input from the keyboard. - Implementation:
- Implemented the
sys_readsystem call inos/src/syscall/fs.rs.
- Implemented the
Below, we introduce the key data structures for process management: the Process Control Block (PCB), the Process Context (TaskContext), and the CPU state manager (Processor).
The PCB is the central data structure for managing a process.
pub struct PCB {
/// Process ID
pub pid: PidHandle,
/// Kernel stack for this process
pub kernel_stack: KernelStack,
/// Inner mutable data
inner: UPSafeCell<PCBInner>,
}The PCBInner struct contains the mutable parts of the process's state:
pub struct PCBInner {
/// Process priority
pub prio: u8,
/// Pass value for Stride Scheduling
pub pass: Pass,
/// Physical page number of the trap context
pub trap_cx_ppn: PhysPageNum,
/// Size of the application's initial data, heap, and stack
pub base_size: usize,
/// Task context for context switching
pub task_cx: TaskContext,
/// Current execution status of the process
pub process_status: ProcessStatus,
/// The memory set (address space) of the process
pub memory_set: MemorySet,
/// Parent of the current process
pub parent: Option<Weak<PCB>>,
/// Children of the current process
pub children: Vec<Arc<PCB>>,
/// Exit code, set when the process exits
pub exit_code: i32,
}The TaskContext stores the minimal set of registers that need to be saved and restored during a context switch.
pub struct TaskContext {
/// Return address (e.g., to __restore)
ra: usize,
/// Kernel stack pointer for the application
sp: usize,
/// Callee-saved registers s0-s11
s: [usize; 12],
}For details on the scheduling algorithm, see Stride Scheduling.
The Processor struct tracks the state of a single CPU core.
pub struct Processor {
/// The process currently executing on this processor
current: Option<Arc<PCB>>,
/// The task context for this processor's idle control flow
idle_task_cx: TaskContext,
}add_initproc(): Adds the initialinitprocprocess to the task manager. This is called once during kernel initialization.add_process(pcb: Arc<PCB>): Adds a new process to the process manager's ready queue.current_proc() -> Option<Arc<PCB>>: Returns a reference-counted pointer to the currently executing process'sPCB.current_trap_cx() -> &'static mut TrapContext: Gets a mutable reference to the trap context of the current task.current_user_token() -> usize: Gets the token (root physical page number) of the current application's address space.exit_current_and_run_next(exit_code: i32): Terminates the current process with an exit code and schedules the next one.run_tasks(): Starts the scheduler by switching to the idle control flow, which then picks the first process to run.schedule(switched_task_cx_ptr: *mut TaskContext): Switches from the current task to the idle control flow to schedule a new task.suspend_current_and_run_next(): Suspends the current task (placing it back in the ready queue) and runs the next available task.take_current_proc() -> Option<Arc<PCB>>: Removes and returns the currently executing process from theProcessor.