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];
else
state = "???";
printf("%d %s %s", p->pid, state, p->name);
printf("\n");
}
}
OK,proc.c和proc.h的讲解到此结束啦!!!