// Look in the process table for an UNUSED proc.
// If found, change state to EMBRYO and initialize
// state required to run in the kernel.
// Otherwise return 0.
static struct proc*
allocproc(void)
{
struct proc *p;
char *sp;
//锁住&ptable
acquire(&ptable.lock);
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
if(p->state == UNUSED)//从进程索引表中找到UNUSED进程
goto found;
release(&ptable.lock);
return 0;//若未找到说明分配失败
found:
p->state = EMBRYO;
p->pid = nextpid++;//进程pid
release(&ptable.lock);
// Allocate kernel stack.分配内核栈
if((p->kstack = kalloc()) == 0){//kalloc位于kalloc.c中
//*kalloc()函数的作用是分配一个4096B大小的空间,而在param.h中规定了一个进程的内核栈大小为4096*/
p->state = UNUSED;//分配失败,修改状态,相当于放回索引表
return 0;
}
sp = p->kstack + KSTACKSIZE;//param.h中定义 4096【size of per-process kernel stack】/*sp指针指向最大地址的位置(因为栈的生长方向是至上而下的,也就是说后入栈的元素的地址要更小)*/
// Leave room for trap frame.理解为内核栈
sp -= sizeof *p->tf;//tf是trapframe类型,sizeof即求trapframe的大小
p->tf = (struct trapframe*)sp;//根据trapframe的大小,移动指针后将其赋值p->tf
// Set up new context to start executing at forkret,
// which returns to trapret.
sp -= 4;
*(uint*)sp = (uint)trapret;
sp -= sizeof *p->context;
p->context = (struct context*)sp;
memset(p->context, 0, sizeof *p->context);
p->context->eip = (uint)forkret;
return p;
}
// Set up first user process.
void
userinit(void)
{
struct proc *p;
extern char _binary_initcode_start[], _binary_initcode_size[];
p = allocproc();
initproc = p;//因为userinit此方法只有初始化的时候调用,可以理解为将initproc设置为主进程
if((p->pgdir = setupkvm()) == 0)// Set up kernel part of a page table.可以理解为分配page table分配页表 pgdir页表起始地址
panic("userinit: out of memory?");
inituvm(p->pgdir, _binary_initcode_start, (int)_
struct { struct spinlock lock; struct proc proc[NPROC];} ptable;//进程索引表,64个进程以数组的形式记录static struct proc *initproc;//初始进程,userinit调用中赋值// Look in the process table for an UNUSED proc.// If fo...