Avoid two cores selecting the same process to run

This commit is contained in:
Frans Kaashoek 2019-07-02 13:40:33 -04:00
parent 67702cf706
commit da51735980
5 changed files with 53 additions and 30 deletions

View file

@ -54,7 +54,7 @@ OBJCOPY = $(TOOLPREFIX)objcopy
OBJDUMP = $(TOOLPREFIX)objdump OBJDUMP = $(TOOLPREFIX)objdump
# CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -ggdb -Werror -fno-omit-frame-pointer -O # CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -ggdb -Werror -fno-omit-frame-pointer -O
CFLAGS = -Wall -Werror -O -fno-omit-frame-pointer -ggdb CFLAGS = -Wall -Werror -O0 -fno-omit-frame-pointer -ggdb
CFLAGS += -mcmodel=medany CFLAGS += -mcmodel=medany
CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax
CFLAGS += -I. CFLAGS += -I.

View file

@ -297,15 +297,16 @@ exit(void)
panic("zombie exit"); panic("zombie exit");
} }
void tellparent(struct proc *p, struct proc *parent) { void reparent(struct proc *p) {
struct proc *pp; struct proc *pp;
struct proc *parent = p->parent;
acquire(&parent->lock); acquire(&parent->lock);
// Parent might be sleeping in wait(). // Parent might be sleeping in wait().
wakeup1(parent); wakeup1(parent);
// Pass abandoned children to init. // Pass p's abandoned children to init.
for(pp = ptable.proc; pp < &ptable.proc[NPROC]; pp++){ for(pp = ptable.proc; pp < &ptable.proc[NPROC]; pp++){
if(pp->parent == p){ if(pp->parent == p){
pp->parent = initproc; pp->parent = initproc;
@ -329,8 +330,6 @@ wait(void)
int havekids, pid; int havekids, pid;
struct proc *p = myproc(); struct proc *p = myproc();
// should p lock!
acquire(&p->lock); acquire(&p->lock);
for(;;){ for(;;){
// Scan through table looking for exited children. // Scan through table looking for exited children.
@ -367,11 +366,27 @@ wait(void)
return -1; return -1;
} }
// Wait for children to exit. (See wakeup1 call in tellparent.) // Wait for children to exit. (See wakeup1 call in reparent.)
sleep(p, &p->lock); //DOC: wait-sleep sleep(p, &p->lock); //DOC: wait-sleep
} }
} }
// Loop over process table looking for process to run.
struct proc *find_runnable() {
struct proc *p;
acquire(&ptable.lock);
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) {
acquire(&p->lock);
if(p->state == RUNNABLE) {
release(&ptable.lock);
return p;
}
release(&p->lock);
}
release(&ptable.lock);
return 0;
}
//PAGEBREAK: 42 //PAGEBREAK: 42
// Per-CPU process scheduler. // Per-CPU process scheduler.
// Each CPU calls scheduler() after setting itself up. // Each CPU calls scheduler() after setting itself up.
@ -391,15 +406,7 @@ scheduler(void)
// Enable interrupts on this processor. // Enable interrupts on this processor.
intr_on(); intr_on();
// Loop over process table looking for process to run. if((p = find_runnable()) != 0){
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) {
acquire(&p->lock);
if(p->state != RUNNABLE) {
release(&p->lock);
continue;
}
// Switch to chosen process. It is the process's job // Switch to chosen process. It is the process's job
// to release its lock and then reacquire it // to release its lock and then reacquire it
// before jumping back to us. // before jumping back to us.
@ -412,11 +419,9 @@ scheduler(void)
// It should have changed its p->state before coming back. // It should have changed its p->state before coming back.
c->proc = 0; c->proc = 0;
release(&p->lock); release(&p->lock);
if(p->state == ZOMBIE) { if(p->state == ZOMBIE) {
tellparent(p, p->parent); reparent(p);
} }
} }
} }
} }
@ -485,7 +490,9 @@ forkret(void)
void void
sleep(void *chan, struct spinlock *lk) sleep(void *chan, struct spinlock *lk)
{ {
if(myproc() == 0) struct proc *p = myproc();
if(p == 0)
panic("sleep"); panic("sleep");
if(lk == 0) if(lk == 0)
@ -497,29 +504,29 @@ sleep(void *chan, struct spinlock *lk)
// guaranteed that we won't miss any wakeup // guaranteed that we won't miss any wakeup
// (wakeup runs with p->lock locked), // (wakeup runs with p->lock locked),
// so it's okay to release lk. // so it's okay to release lk.
if(lk != &myproc()->lock){ //DOC: sleeplock0 if(lk != &p->lock){ //DOC: sleeplock0
acquire(&myproc()->lock); //DOC: sleeplock1 acquire(&p->lock); //DOC: sleeplock1
release(lk); release(lk);
} }
// Go to sleep. // Go to sleep.
myproc()->chan = chan; p->chan = chan;
myproc()->state = SLEEPING; p->state = SLEEPING;
sched(); sched();
// Tidy up. // Tidy up.
myproc()->chan = 0; p->chan = 0;
// Reacquire original lock. // Reacquire original lock.
if(lk != &myproc()->lock){ //DOC: sleeplock2 if(lk != &p->lock){ //DOC: sleeplock2
release(&myproc()->lock); release(&p->lock);
acquire(lk); acquire(lk);
} }
} }
//PAGEBREAK! //PAGEBREAK!
// Wake up all processes sleeping on chan, // Wake up all processes sleeping on chan,
// where chan is a proc. // where chan is a proc, which is locked.
static void static void
wakeup1(struct proc *chan) wakeup1(struct proc *chan)
{ {

View file

@ -304,6 +304,15 @@ w_tp(uint64 x)
asm volatile("mv tp, %0" : : "r" (x)); asm volatile("mv tp, %0" : : "r" (x));
} }
static inline uint64
r_ra()
{
uint64 x;
asm volatile("mv %0, ra" : "=r" (x) );
return x;
}
#define PGSIZE 4096 // bytes per page #define PGSIZE 4096 // bytes per page
#define PGSHIFT 12 // bits of offset within a page #define PGSHIFT 12 // bits of offset within a page

View file

@ -20,7 +20,7 @@ initlock(struct spinlock *lk, char *name)
// Loops (spins) until the lock is acquired. // Loops (spins) until the lock is acquired.
// Holding a lock for a long time may cause // Holding a lock for a long time may cause
// other CPUs to waste time spinning to acquire it. // other CPUs to waste time spinning to acquire it.
void //__attribute__ ((noinline)) void
acquire(struct spinlock *lk) acquire(struct spinlock *lk)
{ {
push_off(); // disable interrupts to avoid deadlock. push_off(); // disable interrupts to avoid deadlock.
@ -44,14 +44,19 @@ acquire(struct spinlock *lk)
} }
// Release the lock. // Release the lock.
void //__attribute__ ((noinline)) void
release(struct spinlock *lk) release(struct spinlock *lk)
{ {
uint64 x;
asm volatile("mv %0, ra" : "=r" (x) );
if(!holding(lk)) { if(!holding(lk)) {
printf("%p: !holding %s %p\n", mycpu(), lk->name, lk->cpu); printf("%p: !holding %d %s %p %p %p %p\n", mycpu(), lk->locked, lk->name, lk->cpu,
lk->last_release, lk->last_pc, x);
panic("release"); panic("release");
} }
lk->last_release = lk->cpu;
lk->last_pc = x;
lk->cpu = 0; lk->cpu = 0;
// Tell the C compiler and the CPU to not move loads or stores // Tell the C compiler and the CPU to not move loads or stores

View file

@ -5,5 +5,7 @@ struct spinlock {
// For debugging: // For debugging:
char *name; // Name of lock. char *name; // Name of lock.
struct cpu *cpu; // The cpu holding the lock. struct cpu *cpu; // The cpu holding the lock.
struct cpu *last_release;
uint64 last_pc;
}; };