进程管理 API¶
本文档介绍 NoobKernel 进程管理模块的主要 API。
CPU 管理¶
#include <task/proc.h>
// 初始化 CPU
void init_cpu(u64 id);
// 获取当前 CPU 结构
struct cpu *thiscpu(void);
示例:
// 获取当前 CPU
struct cpu *c = thiscpu();
infof("Current process: %s", c->proc ? c->proc->comm : "idle");
进程分配¶
#include <task/proc.h>
// 分配进程结构
struct proc *alloc_proc(void);
// 释放进程结构
void free_proc(struct proc *p);
// 分配 PID
pid_t alloc_pid(void);
示例:
struct proc *p = alloc_proc();
if (!p) {
return -ENOMEM;
}
infof("Created process pid=%d", p->pid);
// 释放进程
free_proc(p);
进程状态¶
#define PROC_UNUSED 0
#define PROC_IDLE 1
#define PROC_RUNNABLE 2
#define PROC_RUNNING 3
#define PROC_SLEEPING 4
#define PROC_ZOMBIE 5
调度器¶
#include <task/sched.h>
// 初始化运行队列
void init_runq(void);
// 加入运行队列
void enqueue_proc(int hartid, struct proc *p);
// 从运行队列取出
struct proc *dequeue_proc(int hartid);
// 让出 CPU
void sched_yield(void);
// 检查运行队列是否空
bool is_runq_empty(int hartid);
示例:
// 让出 CPU
sched_yield();
// 检查运行队列
if (is_runq_empty(0)) {
infof("No processes to run");
}
上下文切换¶
// 切换上下文
void context_switch(struct context *old, struct context *new);
// 切换到指定上下文
void context_switch_to(struct context *new);
内核线程¶
#include <task/kthread.h>
// 创建内核线程
struct proc *kthread_create(void (*func)(void *), void *arg);
// 退出内核线程
void kthread_exit(void);
示例:
void my_thread(void *arg) {
infof("Thread started");
while (1) {
// 执行任务
...
sched_yield();
}
}
// 创建线程
struct proc *thread = kthread_create(my_thread, NULL);
if (!thread) {
return -ENOMEM;
}
// 加入运行队列
enqueue_proc(0, thread);
进程结构¶
struct proc {
char comm[16]; // 进程名
pid_t pid; // 进程 ID
pid_t tgid; // 线程组 ID
pagetable_t pagetable; // 页表
struct list_head vma; // VMA 链表
struct context ctx; // 上下文
struct ktrapframe ktf; // 内核 trapframe
void *kstack; // 内核栈
int state; // 状态
struct list_head runq; // 运行队列节点
struct proc *parent; // 父进程
struct list_head children; // 子进程
struct list_head sibling; // 兄弟进程
struct fd_table *fd_table; // 文件描述符表
struct dentry *pwd; // 工作目录
spinlock_t lock; // 进程锁
};
进程操作¶
// 获取进程锁
spinlock_acquire(&p->lock);
// 修改进程状态
p->state = PROC_SLEEPING;
// 释放进程锁
spinlock_release(&p->lock);
CPU 结构¶
struct cpu {
struct proc *proc; // 当前进程
struct proc idle; // idle 进程
u64 intr_state; // 中断状态
int intr_depth; // 中断嵌套深度
bool need_resched; // 需要调度
u8 idle_stack[IDLE_STACK_SIZE]; // idle 栈
};
上下文结构¶
struct context {
u64 ra; // 返回地址
u64 sp; // 栈指针
u64 gp; // 全局指针
u64 s0-s11; // callee-saved 寄存器
u64 sstatus; // CSR
};
最佳实践¶
持锁时间要短¶
// 正确
spinlock_acquire(&p->lock);
p->state = PROC_RUNNABLE;
spinlock_release(&p->lock);
// 错误:持锁时调度
spinlock_acquire(&p->lock);
sched_yield(); // 可能死锁
spinlock_release(&p->lock);
检查进程状态¶
if (p->state == PROC_ZOMBIE) {
// 进程已退出
free_proc(p);
}
正确使用调度¶
// 在中断上下文中设置标志
thiscpu()->need_resched = true;
// 在 kerneltrap 中检查
if (thiscpu()->need_resched) {
sched_yield();
}