From dabbc348bc4edab522901d8473acaabe276cdc45 Mon Sep 17 00:00:00 2001 From: Frans Kaashoek Date: Sat, 6 Jul 2019 16:38:41 -0400 Subject: [PATCH] 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. --- kernel/proc.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/kernel/proc.c b/kernel/proc.c index 9c64c4a..2266ca6 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -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) {