Skip to content

Latest commit

 

History

History
151 lines (116 loc) · 5.93 KB

File metadata and controls

151 lines (116 loc) · 5.93 KB

Process Management

Module Design Flow

1. Add System Call Support

  • Objective: To provide core process management system calls for applications.
  • Implementation:
    • Added sys_* functions in user/src/lib.rs to translate system calls into ecall instructions.
    • Wrapped these sys_* functions in the usr library to provide familiar interfaces like fork, exec, waitpid, getpid, and read.

2. Implement User-space Applications

  • Objective: To provide a basic user-space environment and test kernel functionalities.
  • Implementation:
    • Created several applications in user/src/bin, including initproc.rs and user_shell.rs, for both testing and core functionality.

3. Support Loading ELF Files by Name

  • Objective: To load ELF executables by their names instead of a numeric ID.
  • Implementation:
    • Updated the link_app.S format to include application names.
    • Provided a get_app_data_by_name interface to retrieve application ELF data.

4. Refactor Task Management Architecture

  • Objective: To reduce coupling by separating the responsibilities of the task manager.
  • Implementation:
    • The Processor now manages the currently executing task on a specific CPU.
    • The ProcessManager is now only responsible for managing the state of all tasks (e.g., the ready queue).

5. Extend the Process Control Block (PCB)

  • Objective: To store additional process-related information such as PID, kernel stack, and parent-child relationships.
  • Implementation:
    • Evolved the TaskControlBlock into a PCB (Process Control Block) to support the full process model.

6. Process Scheduling Mechanism

  • 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.

7. Process Creation Mechanism

  • Objective: To implement the fork and exec system calls.
  • Implementation:
    • Implemented the sys_fork and sys_exec handlers in os/src/syscall/process.rs.
    • These handlers call the underlying logic in the PCB implementation.

8. Process Resource Reclamation

  • Objective: To release resources after a process exits.
  • Implementation:
    • Partial resources are reclaimed in exit_current_and_run_next when a process exits and becomes a zombie.
    • All remaining resources are freed when the parent process calls waitpid and collects the exit code.

9. Process I/O Input Mechanism

  • Objective: To allow the user_shell to read user input from the keyboard.
  • Implementation:
    • Implemented the sys_read system call in os/src/syscall/fs.rs.

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

Process Control Block (PCB)

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

Process Context

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

Process Scheduling and Management

For details on the scheduling algorithm, see Stride Scheduling.

CPU Execution State

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

Major API Interfaces

  • add_initproc(): Adds the initial initproc process 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's PCB.
  • 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 the Processor.