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; 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)
{ {