Avoid two cores selecting the same process to run
This commit is contained in:
parent
67702cf706
commit
da51735980
2
Makefile
2
Makefile
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue