summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorFrans Kaashoek <[email protected]>2019-07-06 16:38:41 -0400
committerFrans Kaashoek <[email protected]>2019-07-06 16:38:41 -0400
commitdabbc348bc4edab522901d8473acaabe276cdc45 (patch)
treea46c2e0a275ad9ca48898b23026f131fac85c086 /kernel
parentbe88befed702f7bcbf65212a9dcf9456a7bd2ae1 (diff)
downloadxv6-labs-dabbc348bc4edab522901d8473acaabe276cdc45.tar.gz
xv6-labs-dabbc348bc4edab522901d8473acaabe276cdc45.tar.bz2
xv6-labs-dabbc348bc4edab522901d8473acaabe276cdc45.zip
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.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/proc.c32
1 files 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)
{