have kill() lock before looking at p->pid
document wait()'s use of np->parent w/o holding lock.
This commit is contained in:
parent
9981bb2270
commit
5eb1685700
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue