Read curproc from cpu structure, but be careful because after a schedule event

myproc() points to a different thread.

   myproc();
   sched();
   myproc();  // this proc maybe different than the one before sched

Thus, in a function that operates on one thread better to retrieve the
current process once at the start of the function.
This commit is contained in:
Frans Kaashoek 2017-01-31 20:21:14 -05:00
parent abf847a083
commit fbb4c09444
7 changed files with 97 additions and 62 deletions

101
proc.c
View file

@ -26,14 +26,23 @@ pinit(void)
initlock(&ptable.lock, "ptable");
}
// XXX get rid off?
int
cpuid() {
return mycpu()-cpus;
}
void
setproc(struct proc* p) {
mycpu()->proc = p;
// Disable interrupts so that we are not rescheduled
// while reading proc from the cpu structure
struct proc*
myproc(void) {
struct cpu *c;
struct proc *p;
pushcli();
c = mycpu();
p = c->proc;
popcli();
return p;
}
//PAGEBREAK: 32
@ -130,17 +139,18 @@ int
growproc(int n)
{
uint sz;
struct proc *curproc = myproc();
sz = myproc()->sz;
sz = curproc->sz;
if(n > 0){
if((sz = allocuvm(myproc()->pgdir, sz, sz + n)) == 0)
if((sz = allocuvm(curproc->pgdir, sz, sz + n)) == 0)
return -1;
} else if(n < 0){
if((sz = deallocuvm(myproc()->pgdir, sz, sz + n)) == 0)
if((sz = deallocuvm(curproc->pgdir, sz, sz + n)) == 0)
return -1;
}
myproc()->sz = sz;
switchuvm(myproc());
curproc->sz = sz;
switchuvm(curproc);
return 0;
}
@ -152,6 +162,7 @@ fork(void)
{
int i, pid;
struct proc *np;
struct proc *curproc = myproc();
// Allocate process.
if((np = allocproc()) == 0){
@ -159,25 +170,25 @@ fork(void)
}
// Copy process state from proc.
if((np->pgdir = copyuvm(myproc()->pgdir, myproc()->sz)) == 0){
if((np->pgdir = copyuvm(curproc->pgdir, curproc->sz)) == 0){
kfree(np->kstack);
np->kstack = 0;
np->state = UNUSED;
return -1;
}
np->sz = myproc()->sz;
np->parent = myproc();
*np->tf = *myproc()->tf;
np->sz = curproc->sz;
np->parent = curproc;
*np->tf = *curproc->tf;
// Clear %eax so that fork returns 0 in the child.
np->tf->eax = 0;
for(i = 0; i < NOFILE; i++)
if(myproc()->ofile[i])
np->ofile[i] = filedup(myproc()->ofile[i]);
np->cwd = idup(myproc()->cwd);
if(curproc->ofile[i])
np->ofile[i] = filedup(curproc->ofile[i]);
np->cwd = idup(curproc->cwd);
safestrcpy(np->name, myproc()->name, sizeof(myproc()->name));
safestrcpy(np->name, curproc->name, sizeof(curproc->name));
pid = np->pid;
@ -196,33 +207,34 @@ fork(void)
void
exit(void)
{
struct proc *curproc = myproc();
struct proc *p;
int fd;
if(myproc() == initproc)
if(curproc == initproc)
panic("init exiting");
// Close all open files.
for(fd = 0; fd < NOFILE; fd++){
if(myproc()->ofile[fd]){
fileclose(myproc()->ofile[fd]);
myproc()->ofile[fd] = 0;
if(curproc->ofile[fd]){
fileclose(curproc->ofile[fd]);
curproc->ofile[fd] = 0;
}
}
begin_op();
iput(myproc()->cwd);
iput(curproc->cwd);
end_op();
myproc()->cwd = 0;
curproc->cwd = 0;
acquire(&ptable.lock);
// Parent might be sleeping in wait().
wakeup1(myproc()->parent);
wakeup1(curproc->parent);
// Pass abandoned children to init.
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
if(p->parent == myproc()){
if(p->parent == curproc){
p->parent = initproc;
if(p->state == ZOMBIE)
wakeup1(initproc);
@ -230,7 +242,7 @@ exit(void)
}
// Jump into the scheduler, never to return.
myproc()->state = ZOMBIE;
curproc->state = ZOMBIE;
sched();
panic("zombie exit");
}
@ -242,13 +254,14 @@ wait(void)
{
struct proc *p;
int havekids, pid;
struct proc *curproc = myproc();
acquire(&ptable.lock);
for(;;){
// Scan through table looking for exited children.
havekids = 0;
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
if(p->parent != myproc())
if(p->parent != curproc)
continue;
havekids = 1;
if(p->state == ZOMBIE){
@ -268,13 +281,13 @@ wait(void)
}
// No point waiting if we don't have any children.
if(!havekids || myproc()->killed){
if(!havekids || curproc->killed){
release(&ptable.lock);
return -1;
}
// Wait for children to exit. (See wakeup1 call in proc_exit.)
sleep(myproc(), &ptable.lock); //DOC: wait-sleep
sleep(curproc, &ptable.lock); //DOC: wait-sleep
}
}
@ -290,6 +303,7 @@ void
scheduler(void)
{
struct proc *p;
struct cpu *c = mycpu();
for(;;){
// Enable interrupts on this processor.
@ -304,15 +318,18 @@ scheduler(void)
// Switch to chosen process. It is the process's job
// to release ptable.lock and then reacquire it
// before jumping back to us.
setproc(p);
c->proc = p;
switchuvm(p);
p->state = RUNNING;
swtch(&(mycpu()->scheduler), p->context);
p->cpu = c;
// cprintf("%d: switch to %d\n", c-cpus, p->pid);
swtch(&(p->cpu->scheduler), p->context);
switchkvm();
// Process is done running for now.
// It should have changed its p->state before coming back.
setproc(0);
c->proc = 0;
p->cpu = 0;
}
release(&ptable.lock);
@ -330,17 +347,20 @@ void
sched(void)
{
int intena;
struct proc *p = myproc();
if(!holding(&ptable.lock))
panic("sched ptable.lock");
if(mycpu()->ncli != 1)
panic("sched locks");
if(myproc()->state == RUNNING)
if(p->state == RUNNING)
panic("sched running");
if(readeflags()&FL_IF)
panic("sched interruptible");
intena = mycpu()->intena;
swtch(&myproc()->context, mycpu()->scheduler);
// cprintf("%d: before swtch %d %x\n", p->cpu-cpus, p->pid, * (int *) 0x1d);
swtch(&p->context, p->cpu->scheduler);
// cprintf("%d/%d: after swtch %d %x\n", cpuid(), p->cpu-cpus, p->pid, * (int *) 0x1d);
mycpu()->intena = intena;
}
@ -380,7 +400,9 @@ forkret(void)
void
sleep(void *chan, struct spinlock *lk)
{
if(myproc() == 0)
struct proc *p = myproc();
if(p == 0)
panic("sleep");
if(lk == 0)
@ -397,12 +419,15 @@ sleep(void *chan, struct spinlock *lk)
release(lk);
}
// Go to sleep.
myproc()->chan = chan;
myproc()->state = SLEEPING;
p->chan = chan;
p->state = SLEEPING;
// cprintf("sleep %d\n", p->pid);
sched();
// Tidy up.
myproc()->chan = 0;
p->chan = 0;
// Reacquire original lock.
if(lk != &ptable.lock){ //DOC: sleeplock2