xv6源码分析 011
今天我们结束proc.h
和proc.c
这一块。
wakeup(void *chan)
这个函数用于唤醒所有在这个channel结构上睡眠的进程,类似于我们c++中的notify_all()
。
void
wakeup(void *chan)
{struct proc *p;for(p = proc; p < &proc[NPROC]; p++) {acquire(&p->lock);if(p->state == SLEEPING && p->chan == chan) {p->state = RUNNABLE;}release(&p->lock);}
}
wakeup1(struct proc *p)
唤醒指定的进程
static void
wakeup1(struct proc *p)
{if(!holding(&p->lock))panic("wakeup1");if(p->chan == p && p->state == SLEEPING) {p->state = RUNNABLE;}
}
为什么要先检查进程的进程锁是否已经被获取呢?我们上一集看过sleep的代码,在sleep中,进程首先获取进程锁,为了防止唤醒信号的丢失;然后释放 chan 对应的锁,并在这个chan上睡眠;这里检查进程锁是否被获取,看起来有点多余哈哈哈,而且是因为如果没有检测结果为false的化就会panic,这个在正常的系统中肯定是不被允许的。
kill(int pid)
我们看看注释:
受害者(victim,指被杀死的进程)并不会马上退出知道它尝试从内核态返回在用户态。
也就是说,进程不会在用户空间中接收到kill信号。也可以这样理解,kill的作用具有延迟性,在进程由于中断或者系统调用陷入内核时,kill才起作用。
int
kill(int pid)
{struct proc *p;for(p = proc; p < &proc[NPROC]; p++){acquire(&p->lock);if(p->pid == pid){p->killed = 1;if(p->state == SLEEPING){// Wake process from sleep().p->state = RUNNABLE;}release(&p->lock);return 0;}release(&p->lock);}return -1;
}
然后是两个copy函数,比较简单
int
either_copyout(int user_dst, uint64 dst, void *src, uint64 len)
{struct proc *p = myproc();if(user_dst){return copyout(p->pagetable, dst, src, len);} else {memmove((char *)dst, src, len);return 0;}
}int
either_copyin(void *dst, int user_src, uint64 src, uint64 len)
{struct proc *p = myproc();if(user_src){return copyin(p->pagetable, dst, src, len);} else {memmove(dst, (char*)src, len);return 0;}
}
最后提供了一个进程监控函数,看名字就知道了
procdump(void)
void
procdump(void)
{static char *states[] = {[UNUSED] "unused",[SLEEPING] "sleep ",[RUNNABLE] "runble",[RUNNING] "run ",[ZOMBIE] "zombie"};struct proc *p;char *state;printf("\n");for(p = proc; p < &proc[NPROC]; p++){if(p->state == UNUSED)continue;if(p->state >= 0 && p->state < NELEM(states) && states[p->state])state = states[p->state];elsestate = "???";printf("%d %s %s", p->pid, state, p->name);printf("\n");}
}
OK,proc.c和proc.h的讲解到此结束啦!!!