// 各个cpu状态.
struct cpu {
struct proc *proc; // 正在该cpu上运行的进程,若该指针为空则空闲.
struct context context; // cpu当前的上下文/语境,进程调度由scheduler在此操作.
int noff; // Depth of push_off() nesting.
int intena; // Were interrupts enabled before push_off()?
};
这些信息被保存在CPUS中,方便查询。数目上限为NCPU(=8)。
extern struct cpu cpus[NCPU];
陷阱帧(trapframe)
进程(process)
接下来的部分为本节最后也是最为关键的部分——process。
一个process需要提供以下内容:
便于识别与区分的身份信息:id号码...
掌握的内存资源:代码的运行空间,使用的文件,占用大小,当前内存指向...;
进程的状态以及相互关系:进程状态,父进程,是否被杀死...;
调度接口:上下文,等待链,返回状态,锁...
/*
Per-process state(处理进程状态)
xv6 使用结构体 struct proc 来维护一个进程的众多状态。
*/
struct proc {
struct spinlock lock;
// p->lock must be held when using these:
enum procstate state; // Process state(指示了进程的状态:新建、准备运行、运行、等待 I/O 或退出状态中。)
void *chan; // If non-zero, sleeping on chan
int killed; // If non-zero, have been killed
int xstate; // Exit status to be returned to parent's wait
int pid; // Process ID(pid,进程号)
// proc_tree_lock must be held when using this:
struct proc *parent; // Parent process
// these are private to the process, so p->lock need not be held.
// 每个进程有两个栈:用户栈和内核栈(kstack)。当进程在执行用户指令时,只有它的用户栈在使用,而它的内核栈是空的。
// 当进程进入内核时(为了系统调用或中断),内核代码在进程的内核栈上执行;
// 当进程在内核中时,它的用户栈仍然包含保存的数据,但不被主动使用。
// 进程的线程在用户栈和内核栈中交替执行。内核栈是独立的(并且受到保护,不受用户代码的影响),所以即使一个进程用户栈被破坏了,内核也可以执行。
uint64 kstack; // Virtual address of kernel stack(内核栈的虚拟地址)
uint64 sz; // Size of process memory (bytes)
pagetable_t pagetable; // User page table
struct trapframe *trapframe; // data page for trampoline.S
struct context context; // swtch() here to run process
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
char name[16]; // Process name (debugging)
};