have kill() lock before looking at p->pid

document wait()'s use of np->parent w/o holding lock.
This commit is contained in:
Robert Morris 2019-07-10 09:24:50 -04:00
parent 9981bb2270
commit 5eb1685700
3 changed files with 32 additions and 36 deletions

View file

@ -367,19 +367,24 @@ wait(void)
// Scan through table looking for exited children. // Scan through table looking for exited children.
havekids = 0; havekids = 0;
for(np = proc; np < &proc[NPROC]; np++){ for(np = proc; np < &proc[NPROC]; np++){
if(np->parent != p) // this code uses np->parent without holding np->lock.
continue; // acquiring the lock first would cause a deadlock,
acquire(&np->lock); // since np might be an ancestor, and we already hold p->lock.
havekids = 1; if(np->parent == p){
if(np->state == ZOMBIE){ // np->parent can't change here because only the parent
// Found one. // changes it, and we're the parent.
pid = np->pid; acquire(&np->lock);
freeproc(np); havekids = 1;
if(np->state == ZOMBIE){
// Found one.
pid = np->pid;
freeproc(np);
release(&np->lock);
release(&p->lock);
return pid;
}
release(&np->lock); release(&np->lock);
release(&p->lock);
return pid;
} }
release(&np->lock);
} }
// No point waiting if we don't have any children. // No point waiting if we don't have any children.
@ -397,10 +402,10 @@ wait(void)
// Per-CPU process scheduler. // Per-CPU process scheduler.
// Each CPU calls scheduler() after setting itself up. // Each CPU calls scheduler() after setting itself up.
// Scheduler never returns. It loops, doing: // Scheduler never returns. It loops, doing:
// - choose a process to run // - choose a process to run.
// - swtch to start running that process // - swtch to start running that process.
// - eventually that process transfers control // - eventually that process transfers control
// via swtch back to the scheduler. // via swtch back to the scheduler.
void void
scheduler(void) scheduler(void)
{ {
@ -409,7 +414,7 @@ scheduler(void)
c->proc = 0; c->proc = 0;
for(;;){ for(;;){
// Enable interrupts on this processor. // Give devices a brief chance to interrupt.
intr_on(); intr_on();
for(p = proc; p < &proc[NPROC]; p++) { for(p = proc; p < &proc[NPROC]; p++) {
@ -508,7 +513,7 @@ sleep(void *chan, struct spinlock *lk)
// change p->state and then call sched. // change p->state and then call sched.
// Once we hold p->lock, we can be // Once we hold p->lock, we can be
// guaranteed that we won't miss any wakeup // guaranteed that we won't miss any wakeup
// (wakeup runs with p->lock locked), // (wakeup locks p->lock),
// so it's okay to release lk. // so it's okay to release lk.
if(lk != &p->lock){ //DOC: sleeplock0 if(lk != &p->lock){ //DOC: sleeplock0
acquire(&p->lock); //DOC: sleeplock1 acquire(&p->lock); //DOC: sleeplock1
@ -559,24 +564,24 @@ wakeup(void *chan)
// Kill the process with the given pid. // Kill the process with the given pid.
// Process won't exit until it returns // Process won't exit until it returns
// to user space (see trap in trap.c). // to user space (see usertrap() in trap.c).
int int
kill(int pid) kill(int pid)
{ {
struct proc *p; struct proc *p;
for(p = proc; p < &proc[NPROC]; p++){ for(p = proc; p < &proc[NPROC]; p++){
acquire(&p->lock);
if(p->pid == pid){ if(p->pid == pid){
acquire(&p->lock);
if(p->pid != pid)
panic("kill");
p->killed = 1; p->killed = 1;
// Wake process from sleep if necessary. if(p->state == SLEEPING){
if(p->state == SLEEPING) // Wake process from sleep().
p->state = RUNNABLE; p->state = RUNNABLE;
}
release(&p->lock); release(&p->lock);
return 0; return 0;
} }
release(&p->lock);
} }
return -1; return -1;
} }

View file

@ -163,8 +163,8 @@ static uint64 (*syscalls[])(void) = {
[SYS_close] sys_close, [SYS_close] sys_close,
}; };
static void void
dosyscall(void) syscall(void)
{ {
int num; int num;
struct proc *p = myproc(); struct proc *p = myproc();
@ -180,15 +180,3 @@ dosyscall(void)
p->tf->a0 = -1; p->tf->a0 = -1;
} }
} }
void
syscall()
{
if(myproc()->killed)
exit();
dosyscall();
if(myproc()->killed)
exit();
return;
}

View file

@ -53,6 +53,9 @@ usertrap(void)
if(r_scause() == 8){ if(r_scause() == 8){
// system call // system call
if(p->killed)
exit();
// sepc points to the ecall instruction, // sepc points to the ecall instruction,
// but we want to return to the next instruction. // but we want to return to the next instruction.
p->tf->epc += 4; p->tf->epc += 4;