Maybe fix two races identified by rtm (thx!):
- during exit(), hold p's parent lock and p's lock across all changes to p and its parent (e.g., reparenting and wakeup1). the lock ordering between concurrent exits of children, parent, and great parent might work out because processes form a tree. - in wakeup1() test and set p->state atomically by asking caller to have p locked. a correctness proof would be desirable.
This commit is contained in:
parent
be88befed7
commit
dabbc348bc
|
@ -288,22 +288,28 @@ fork(void)
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass p's abandoned children to init.
|
// Pass p's abandoned children to init. p and p's parent
|
||||||
void reparent(struct proc *p) {
|
// are locked.
|
||||||
|
void reparent(struct proc *p, struct proc *parent) {
|
||||||
struct proc *pp;
|
struct proc *pp;
|
||||||
|
|
||||||
for(pp = ptable.proc; pp < &ptable.proc[NPROC]; pp++){
|
for(pp = ptable.proc; pp < &ptable.proc[NPROC]; pp++){
|
||||||
acquire(&pp->lock);
|
if (pp != p && pp != parent) {
|
||||||
if(pp->parent == p){
|
acquire(&pp->lock);
|
||||||
pp->parent = initproc;
|
if(pp->parent == p){
|
||||||
if(pp->state == ZOMBIE) {
|
pp->parent = initproc;
|
||||||
|
if(pp->state == ZOMBIE) {
|
||||||
|
acquire(&initproc->lock);
|
||||||
wakeup1(initproc);
|
wakeup1(initproc);
|
||||||
|
release(&initproc->lock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
release(&pp->lock);
|
||||||
}
|
}
|
||||||
release(&pp->lock);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Exit the current process. Does not return.
|
// Exit the current process. Does not return.
|
||||||
// An exited process remains in the zombie state
|
// An exited process remains in the zombie state
|
||||||
// until its parent calls wait().
|
// until its parent calls wait().
|
||||||
|
@ -331,19 +337,20 @@ exit(void)
|
||||||
iput(cwd);
|
iput(cwd);
|
||||||
end_op();
|
end_op();
|
||||||
|
|
||||||
reparent(p);
|
|
||||||
|
|
||||||
acquire(&p->parent->lock);
|
acquire(&p->parent->lock);
|
||||||
|
|
||||||
acquire(&p->lock);
|
acquire(&p->lock);
|
||||||
|
|
||||||
|
reparent(p, p->parent);
|
||||||
|
|
||||||
p->cwd = 0;
|
p->cwd = 0;
|
||||||
p->state = ZOMBIE;
|
p->state = ZOMBIE;
|
||||||
|
|
||||||
release(&p->parent->lock);
|
|
||||||
|
|
||||||
// Parent might be sleeping in wait().
|
// Parent might be sleeping in wait().
|
||||||
wakeup1(p->parent);
|
wakeup1(p->parent);
|
||||||
|
|
||||||
|
release(&p->parent->lock);
|
||||||
|
|
||||||
// Jump into the scheduler, never to return.
|
// Jump into the scheduler, never to return.
|
||||||
sched();
|
sched();
|
||||||
panic("zombie exit");
|
panic("zombie exit");
|
||||||
|
@ -529,7 +536,8 @@ sleep(void *chan, struct spinlock *lk)
|
||||||
}
|
}
|
||||||
|
|
||||||
//PAGEBREAK!
|
//PAGEBREAK!
|
||||||
// Wake up locked parent, used by exit()
|
// Wake up p, used by exit()
|
||||||
|
// Caller should lock p.
|
||||||
static void
|
static void
|
||||||
wakeup1(struct proc *p)
|
wakeup1(struct proc *p)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue