进程管理 - 理论讲解

1. 什么是进程?

进程 = 程序 + 执行状态

程序是静态的代码和数据,进程是程序的一次执行实例,包含:

  • 代码段:要执行的指令
  • 数据段:全局变量
  • 栈:函数调用和局部变量
  • 堆:动态分配的内存
  • 寄存器状态:程序计数器(EIP)、栈指针(ESP)等
  • 操作系统管理信息:PID、状态、页表等

2. 进程控制块(PCB)

PCB是操作系统表示进程的核心数据结构:

typedef enum {
    PROCESS_READY,       // 就绪
    PROCESS_RUNNING,     // 运行中
    PROCESS_BLOCKED,     // 等待I/O
    PROCESS_TERMINATED   // 已终止
} process_state_t;
 
typedef struct process {
    uint32_t pid;               // 唯一标识符
    char name[32];              // 进程名
    process_state_t state;      // 当前状态
 
    /* CPU上下文 */
    uint32_t esp;               // 栈指针
    uint32_t eip;               // 指令指针
    uint32_t ebp;               // 基址指针
    uint32_t eflags;            // 标志寄存器
 
    /* 内存 */
    page_directory_t *page_dir; // 独立的地址空间
    uint32_t kernel_stack;      // 内核态栈
    uint32_t user_stack;        // 用户态栈
 
    /* 调度信息 */
    uint32_t priority;          // 优先级
    uint32_t time_slice;        // 剩余时间片
 
    /* 链表 */
    struct process *next;
} process_t;

3. 进程生命周期

创建进程

1. 分配PID
2. 创建PCB
3. 分配内核栈
4. 创建页目录(继承内核映射)
5. 设置初始寄存器状态
6. 将进程加入就绪队列

上下文切换(简化版)

void context_switch(process_t *prev, process_t *next) {
    // 1. 保存当前进程的寄存器到PCB
    // 2. 切换页目录 (CR3)
    // 3. 切换栈指针
    // 4. 恢复下一个进程的寄存器
}

销毁进程

1. 释放页目录和页表
2. 释放用户空间物理帧
3. 释放内核栈
4. 从进程链表中移除
5. 释放PCB

4. 内核栈 vs 用户栈

每个进程有两个栈:

┌──────────────────────┐ 高地址
│     用户栈           │ ← 用户态代码使用
│     (Ring 3)         │
├──────────────────────┤
│     ...             │
├──────────────────────┤
│     内核栈           │ ← 系统调用/中断时使用
│     (Ring 0)         │
└──────────────────────┘ 低地址

为什么需要独立的内核栈?

  • 安全: 用户不能篡改内核栈
  • 隔离: 即使用户栈损坏,内核仍能正常工作

5. 进程链表管理

static process_t *process_list = NULL;  // 所有进程
static process_t *ready_queue = NULL;   // 就绪队列
static process_t *current = NULL;       // 当前运行
static uint32_t next_pid = 1;
 
process_t *process_create(const char *name, void (*entry)(void)) {
    process_t *proc = kmalloc(sizeof(process_t));
    memset(proc, 0, sizeof(process_t));
 
    proc->pid = next_pid++;
    strncpy(proc->name, name, 31);
    proc->state = PROCESS_READY;
 
    // 分配4KB内核栈
    proc->kernel_stack = (uint32_t)kmalloc_aligned(4096) + 4096;
 
    // 设置初始上下文
    proc->eip = (uint32_t)entry;
    proc->esp = proc->kernel_stack;
    proc->eflags = 0x202;  // IF=1 (中断开启)
 
    // 使用内核页目录(简化版,所有进程共享)
    proc->page_dir = vmm_get_directory();
 
    // 加入就绪队列
    proc->next = ready_queue;
    ready_queue = proc;
 
    return proc;
}

6. 第一个进程——idle任务

每个OS都需要一个”什么都不做”的空闲进程:

void idle_task(void) {
    while (1) {
        __asm__ volatile("hlt");
    }
}
 
void process_init(void) {
    // 创建idle进程(PID=0)
    process_t *idle = process_create("idle", idle_task);
    idle->pid = 0;
    current = idle;
    idle->state = PROCESS_RUNNING;
}

下一步

进程结构建好了,但要让多个进程”同时”运行,需要调度器。下一章将实现定时器驱动的任务调度器!