From abf847a083888bbed4260ecacf849ea19f23e810 Mon Sep 17 00:00:00 2001 From: Frans Kaashoek Date: Tue, 31 Jan 2017 17:47:16 -0500 Subject: Start of an experiment to remove the use of gs for cpu local variables. --- proc.c | 89 ++++++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 49 insertions(+), 40 deletions(-) (limited to 'proc.c') diff --git a/proc.c b/proc.c index 7d03ad7..bd62e4b 100644 --- a/proc.c +++ b/proc.c @@ -26,6 +26,16 @@ pinit(void) initlock(&ptable.lock, "ptable"); } +int +cpuid() { + return mycpu()-cpus; +} + +void +setproc(struct proc* p) { + mycpu()->proc = p; +} + //PAGEBREAK: 32 // Look in the process table for an UNUSED proc. // If found, change state to EMBRYO and initialize @@ -121,16 +131,16 @@ growproc(int n) { uint sz; - sz = proc->sz; + sz = myproc()->sz; if(n > 0){ - if((sz = allocuvm(proc->pgdir, sz, sz + n)) == 0) + if((sz = allocuvm(myproc()->pgdir, sz, sz + n)) == 0) return -1; } else if(n < 0){ - if((sz = deallocuvm(proc->pgdir, sz, sz + n)) == 0) + if((sz = deallocuvm(myproc()->pgdir, sz, sz + n)) == 0) return -1; } - proc->sz = sz; - switchuvm(proc); + myproc()->sz = sz; + switchuvm(myproc()); return 0; } @@ -148,26 +158,26 @@ fork(void) return -1; } - // Copy process state from p. - if((np->pgdir = copyuvm(proc->pgdir, proc->sz)) == 0){ + // Copy process state from proc. + if((np->pgdir = copyuvm(myproc()->pgdir, myproc()->sz)) == 0){ kfree(np->kstack); np->kstack = 0; np->state = UNUSED; return -1; } - np->sz = proc->sz; - np->parent = proc; - *np->tf = *proc->tf; + np->sz = myproc()->sz; + np->parent = myproc(); + *np->tf = *myproc()->tf; // Clear %eax so that fork returns 0 in the child. np->tf->eax = 0; for(i = 0; i < NOFILE; i++) - if(proc->ofile[i]) - np->ofile[i] = filedup(proc->ofile[i]); - np->cwd = idup(proc->cwd); + if(myproc()->ofile[i]) + np->ofile[i] = filedup(myproc()->ofile[i]); + np->cwd = idup(myproc()->cwd); - safestrcpy(np->name, proc->name, sizeof(proc->name)); + safestrcpy(np->name, myproc()->name, sizeof(myproc()->name)); pid = np->pid; @@ -189,30 +199,30 @@ exit(void) struct proc *p; int fd; - if(proc == initproc) + if(myproc() == initproc) panic("init exiting"); // Close all open files. for(fd = 0; fd < NOFILE; fd++){ - if(proc->ofile[fd]){ - fileclose(proc->ofile[fd]); - proc->ofile[fd] = 0; + if(myproc()->ofile[fd]){ + fileclose(myproc()->ofile[fd]); + myproc()->ofile[fd] = 0; } } begin_op(); - iput(proc->cwd); + iput(myproc()->cwd); end_op(); - proc->cwd = 0; + myproc()->cwd = 0; acquire(&ptable.lock); // Parent might be sleeping in wait(). - wakeup1(proc->parent); + wakeup1(myproc()->parent); // Pass abandoned children to init. for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ - if(p->parent == proc){ + if(p->parent == myproc()){ p->parent = initproc; if(p->state == ZOMBIE) wakeup1(initproc); @@ -220,7 +230,7 @@ exit(void) } // Jump into the scheduler, never to return. - proc->state = ZOMBIE; + myproc()->state = ZOMBIE; sched(); panic("zombie exit"); } @@ -238,7 +248,7 @@ wait(void) // Scan through table looking for exited children. havekids = 0; for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ - if(p->parent != proc) + if(p->parent != myproc()) continue; havekids = 1; if(p->state == ZOMBIE){ @@ -258,13 +268,13 @@ wait(void) } // No point waiting if we don't have any children. - if(!havekids || proc->killed){ + if(!havekids || myproc()->killed){ release(&ptable.lock); return -1; } // Wait for children to exit. (See wakeup1 call in proc_exit.) - sleep(proc, &ptable.lock); //DOC: wait-sleep + sleep(myproc(), &ptable.lock); //DOC: wait-sleep } } @@ -294,15 +304,15 @@ 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. - proc = p; + setproc(p); switchuvm(p); p->state = RUNNING; - swtch(&cpu->scheduler, p->context); + swtch(&(mycpu()->scheduler), p->context); switchkvm(); // Process is done running for now. // It should have changed its p->state before coming back. - proc = 0; + setproc(0); } release(&ptable.lock); @@ -323,15 +333,15 @@ sched(void) if(!holding(&ptable.lock)) panic("sched ptable.lock"); - if(cpu->ncli != 1) + if(mycpu()->ncli != 1) panic("sched locks"); - if(proc->state == RUNNING) + if(myproc()->state == RUNNING) panic("sched running"); if(readeflags()&FL_IF) panic("sched interruptible"); - intena = cpu->intena; - swtch(&proc->context, cpu->scheduler); - cpu->intena = intena; + intena = mycpu()->intena; + swtch(&myproc()->context, mycpu()->scheduler); + mycpu()->intena = intena; } // Give up the CPU for one scheduling round. @@ -339,7 +349,7 @@ void yield(void) { acquire(&ptable.lock); //DOC: yieldlock - proc->state = RUNNABLE; + myproc()->state = RUNNABLE; sched(); release(&ptable.lock); } @@ -370,7 +380,7 @@ forkret(void) void sleep(void *chan, struct spinlock *lk) { - if(proc == 0) + if(myproc() == 0) panic("sleep"); if(lk == 0) @@ -386,14 +396,13 @@ sleep(void *chan, struct spinlock *lk) acquire(&ptable.lock); //DOC: sleeplock1 release(lk); } - // Go to sleep. - proc->chan = chan; - proc->state = SLEEPING; + myproc()->chan = chan; + myproc()->state = SLEEPING; sched(); // Tidy up. - proc->chan = 0; + myproc()->chan = 0; // Reacquire original lock. if(lk != &ptable.lock){ //DOC: sleeplock2 -- cgit v1.2.3 From fbb4c0944422f860484142010bb9f366f3e87bf8 Mon Sep 17 00:00:00 2001 From: Frans Kaashoek Date: Tue, 31 Jan 2017 20:21:14 -0500 Subject: 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. --- proc.c | 101 ++++++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 63 insertions(+), 38 deletions(-) (limited to 'proc.c') diff --git a/proc.c b/proc.c index bd62e4b..4e8f461 100644 --- a/proc.c +++ b/proc.c @@ -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 -- cgit v1.2.3 From ed396c068b881877330f7d40bfce02db9b1199b3 Mon Sep 17 00:00:00 2001 From: Frans Kaashoek Date: Wed, 1 Feb 2017 18:04:13 -0500 Subject: Eliminate code for gs trick to track per-cpu state. We rely on lapiccpunum() to find a per-cpu id with which we locate a cpu's cpu struct. --- proc.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) (limited to 'proc.c') diff --git a/proc.c b/proc.c index 4e8f461..6445725 100644 --- a/proc.c +++ b/proc.c @@ -26,12 +26,29 @@ pinit(void) initlock(&ptable.lock, "ptable"); } -// XXX get rid off? +// Must be called with interrupts disabled int cpuid() { return mycpu()-cpus; } +// Must be called with interrupts disabled +struct cpu* +mycpu(void) +{ + // Would prefer to panic but even printing is chancy here: almost everything, + // including cprintf and panic, calls mycpu(), often indirectly through + // acquire and release. + if(readeflags()&FL_IF){ + static int n; + if(n++ == 0) + cprintf("mycpu called from %x with interrupts enabled\n", + __builtin_return_address(0)); + } + + return &cpus[lapiccpunum()]; +} + // Disable interrupts so that we are not rescheduled // while reading proc from the cpu structure struct proc* @@ -304,7 +321,8 @@ scheduler(void) { struct proc *p; struct cpu *c = mycpu(); - + c->proc = 0; + for(;;){ // Enable interrupts on this processor. sti(); @@ -321,15 +339,13 @@ scheduler(void) c->proc = p; switchuvm(p); p->state = RUNNING; - p->cpu = c; - // cprintf("%d: switch to %d\n", c-cpus, p->pid); - swtch(&(p->cpu->scheduler), p->context); + + swtch(&(c->scheduler), p->context); switchkvm(); // Process is done running for now. // It should have changed its p->state before coming back. c->proc = 0; - p->cpu = 0; } release(&ptable.lock); @@ -358,9 +374,7 @@ sched(void) if(readeflags()&FL_IF) panic("sched interruptible"); intena = mycpu()->intena; - // 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); + swtch(&p->context, mycpu()->scheduler); mycpu()->intena = intena; } @@ -422,8 +436,6 @@ sleep(void *chan, struct spinlock *lk) p->chan = chan; p->state = SLEEPING; - // cprintf("sleep %d\n", p->pid); - sched(); // Tidy up. -- cgit v1.2.3 From 7c00ce8110e045a5d0b7b95194561b71d7c0d2b6 Mon Sep 17 00:00:00 2001 From: Frans Kaashoek Date: Wed, 1 Feb 2017 19:18:47 -0500 Subject: shorten comment --- proc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'proc.c') diff --git a/proc.c b/proc.c index 6445725..9f500f2 100644 --- a/proc.c +++ b/proc.c @@ -36,13 +36,9 @@ cpuid() { struct cpu* mycpu(void) { - // Would prefer to panic but even printing is chancy here: almost everything, - // including cprintf and panic, calls mycpu(), often indirectly through - // acquire and release. if(readeflags()&FL_IF){ - static int n; - if(n++ == 0) - cprintf("mycpu called from %x with interrupts enabled\n", + // Would prefer to panic but panic calls mycpu(). + cprintf("mycpu called from %x with interrupts enabled\n", __builtin_return_address(0)); } -- cgit v1.2.3 From 2e2d14c235b570a6beb222fc1bfa53de85a98de3 Mon Sep 17 00:00:00 2001 From: Frans Kaashoek Date: Wed, 1 Feb 2017 19:21:43 -0500 Subject: use panic --- proc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'proc.c') diff --git a/proc.c b/proc.c index 9f500f2..ca343cb 100644 --- a/proc.c +++ b/proc.c @@ -36,12 +36,8 @@ cpuid() { struct cpu* mycpu(void) { - if(readeflags()&FL_IF){ - // Would prefer to panic but panic calls mycpu(). - cprintf("mycpu called from %x with interrupts enabled\n", - __builtin_return_address(0)); - } - + if(readeflags()&FL_IF) + panic("mycpu called with interrupts enabled\n"); return &cpus[lapiccpunum()]; } -- cgit v1.2.3 From c9fa90f7e514f27fa1ac071cd9795f3830ab6a1b Mon Sep 17 00:00:00 2001 From: Frans Kaashoek Date: Wed, 1 Feb 2017 20:36:41 -0500 Subject: A tiny bit of clean up (e.g., move code searching cpu array from lapic.c into mycpu() in proc.c. --- proc.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'proc.c') diff --git a/proc.c b/proc.c index ca343cb..aac7523 100644 --- a/proc.c +++ b/proc.c @@ -32,13 +32,24 @@ cpuid() { return mycpu()-cpus; } -// Must be called with interrupts disabled +// Must be called with interrupts disabled to avoid the caller being rescheduled +// between reading lapicid and running through the loop. struct cpu* mycpu(void) { + int apicid, i; + if(readeflags()&FL_IF) panic("mycpu called with interrupts enabled\n"); - return &cpus[lapiccpunum()]; + + apicid = lapicid(); + // APIC IDs are not guaranteed to be contiguous. Maybe we should have + // a reverse map, or reserve a register to store &cpus[i]. + for (i = 0; i < ncpu; ++i) { + if (cpus[i].apicid == apicid) + return &cpus[i]; + } + panic("unknown apicid\n"); } // Disable interrupts so that we are not rescheduled -- cgit v1.2.3