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:
Frans Kaashoek 2019-07-06 16:38:41 -04:00
parent be88befed7
commit dabbc348bc

View file

@ -288,22 +288,28 @@ fork(void)
return pid;
}
// Pass p's abandoned children to init.
void reparent(struct proc *p) {
// Pass p's abandoned children to init. p and p's parent
// are locked.
void reparent(struct proc *p, struct proc *parent) {
struct proc *pp;
for(pp = ptable.proc; pp < &ptable.proc[NPROC]; pp++){
acquire(&pp->lock);
if(pp->parent == p){
pp->parent = initproc;
if(pp->state == ZOMBIE) {
if (pp != p && pp != parent) {
acquire(&pp->lock);
if(pp->parent == p){
pp->parent = initproc;
if(pp->state == ZOMBIE) {
acquire(&initproc->lock);
wakeup1(initproc);
release(&initproc->lock);
}
}
release(&pp->lock);
}
release(&pp->lock);
}
}
// Exit the current process. Does not return.
// An exited process remains in the zombie state
// until its parent calls wait().
@ -331,19 +337,20 @@ exit(void)
iput(cwd);
end_op();
reparent(p);
acquire(&p->parent->lock);
acquire(&p->lock);
reparent(p, p->parent);
p->cwd = 0;
p->state = ZOMBIE;
release(&p->parent->lock);
// Parent might be sleeping in wait().
wakeup1(p->parent);
release(&p->parent->lock);
// Jump into the scheduler, never to return.
sched();
panic("zombie exit");
@ -529,7 +536,8 @@ sleep(void *chan, struct spinlock *lk)
}
//PAGEBREAK!
// Wake up locked parent, used by exit()
// Wake up p, used by exit()
// Caller should lock p.
static void
wakeup1(struct proc *p)
{