提交 504828a0 创建 作者: Frans Kaashoek's avatar Frans Kaashoek

Primitive partitioned memory allocater (no stealing)

Primitive partitioned proc table, per core runq, and non-scalable stealing Panics on two cores, but i should make more frequent checkpoints
上级 a5579e26
......@@ -190,7 +190,7 @@ consoleintr(int (*getc)(void))
while((c = getc()) >= 0){
switch(c){
case C('P'): // Process listing.
procdump(cpunum());
procdumpall();
break;
case C('U'): // Kill line.
while(input.e != input.w &&
......
......@@ -100,6 +100,7 @@ int growproc(int);
int kill(int);
void pinit(void);
void procdump(int);
void procdumpall(void);
void scheduler(void) __attribute__((noreturn));
void sched(void);
void sleep(void*, struct spinlock*);
......
......@@ -19,7 +19,7 @@ exec(char *path, char **argv)
pde_t *pgdir, *oldpgdir;
cprintf("%d: exec %s\n", cpunum(), path);
procdump(cpunum());
procdumpall();
if((ip = namei(path)) == 0)
return -1;
......
......@@ -48,8 +48,8 @@ ideinit(void)
initlock(&idelock, "ide");
picenable(IRQ_IDE);
ioapicenable(IRQ_IDE, ncpu - 1);
// ioapicenable(IRQ_IDE, 0);
// ioapicenable(IRQ_IDE, ncpu - 1);
ioapicenable(IRQ_IDE, 0);
idewait(0);
// Check if disk 1 is present
......
......@@ -7,15 +7,10 @@
#include "param.h"
#include "mmu.h"
#include "spinlock.h"
#include "proc.h"
#include "kalloc.h"
struct run {
struct run *next;
};
struct {
struct spinlock lock;
struct run *freelist;
} kmem;
struct kmem kmems[NCPU];
extern char end[]; // first address after kernel loaded from ELF file
......@@ -23,12 +18,35 @@ extern char end[]; // first address after kernel loaded from ELF file
void
kinit(void)
{
struct run *r;
char *p;
int c;
int n;
int i;
for (c = 0; c < NCPU; c++) {
kmems[c].name[0] = (char) c;
safestrcpy(kmems[c].name+1, "kmem", MAXNAME-1);
initlock(&kmems[c].lock, kmems[c].name);
}
initlock(&kmem.lock, "kmem");
p = (char*)PGROUNDUP((uint)end);
for(; p + PGSIZE <= (char*)PHYSTOP; p += PGSIZE)
kfree(p);
n = (char*)PHYSTOP - p;
cprintf("n = %d\n", n);
n = n / PGSIZE;
cprintf("n = %d\n", n);
for (c = 0; c < NCPU; c++) {
for (i = 0; i < n; i++, p += PGSIZE) {
memset(p, 1, PGSIZE);
r = (struct run*)p;
r->next = kmems[c].freelist;
kmems[c].freelist = r;
}
}
}
//PAGEBREAK: 21
......@@ -47,11 +65,11 @@ kfree(char *v)
// Fill with junk to catch dangling refs.
memset(v, 1, PGSIZE);
acquire(&kmem.lock);
acquire(&kmem->lock);
r = (struct run*)v;
r->next = kmem.freelist;
kmem.freelist = r;
release(&kmem.lock);
r->next = kmem->freelist;
kmem->freelist = r;
release(&kmem->lock);
}
// Allocate one 4096-byte page of physical memory.
......@@ -62,11 +80,14 @@ kalloc(void)
{
struct run *r;
acquire(&kmem.lock);
r = kmem.freelist;
cprintf("%d: kalloc\n", cpunum());
acquire(&kmem->lock);
r = kmem->freelist;
if(r)
kmem.freelist = r->next;
release(&kmem.lock);
kmem->freelist = r->next;
release(&kmem->lock);
if (r == 0)
cprintf("%d: kalloc out\n", cpunum());
return (char*)r;
}
......@@ -58,7 +58,6 @@ mainc(void)
timerinit(); // uniprocessor timer
userinit(); // first user process
bootothers(); // start other processors
// Finish setting up this processor in mpmain.
mpmain();
}
......@@ -75,8 +74,10 @@ mpmain(void)
}
vmenable(); // turn on paging
cprintf("cpu%d: starting\n", cpu->id);
procdumpall();
idtinit(); // load idt register
xchg(&cpu->booted, 1); // tell bootothers() we're up
procdumpall();
scheduler(); // start running processes
}
......
#define NPROC 64 // maximum number of processes
#define KSTACKSIZE 4096 // size of per-process kernel stack
#define NCPU 8 // maximum number of CPUs
#define NCPU 2 // maximum number of CPUs
#define NOFILE 16 // open files per process
#define NFILE 100 // open files per system
#define NBUF 10 // size of disk block cache
......@@ -10,3 +10,4 @@
#define USERTOP 0xA0000 // end of user address space
#define PHYSTOP 0x1000000 // use phys mem up to here as free pool
#define MAXARG 32 // max exec arguments
#define MAXNAME 16 // max string names
......@@ -18,7 +18,12 @@ static void wakeup1(void *chan);
void
pinit(void)
{
initlock(&ptable->lock, "ptable");
int c;
for (c = 0; c < NCPU; c++) {
ptables[c].name[0] = (char) c;
safestrcpy(ptables[c].name+1, "ptable", MAXNAME-1);
initlock(&ptables[c].lock, ptables[c].name);
}
}
//PAGEBREAK: 32
......@@ -41,7 +46,7 @@ allocproc(void)
found:
p->state = EMBRYO;
p->pid = nextpid++;
p->pid = nextpid++; // XXX global var!
release(&ptable->lock);
// Allocate kernel stack if possible.
......@@ -68,6 +73,63 @@ found:
return p;
}
static void
addrun1(struct proc *p)
{
struct proc *q;
cprintf("%d: add to run %d\n", cpu->id, p->pid);
for (q = ptable->runq; q != 0; q = q->next) {
if (q == p) {
cprintf("allready on q\n");
p->state = RUNNABLE;
return;
}
}
p->state = RUNNABLE; // race?
p->next = ptable->runq;
ptable->runq = p;
}
static void
addrun(struct proc *p)
{
acquire(&ptable->lock);
addrun1(p);
release(&ptable->lock);
procdumpall();
}
static void
delrun1(struct ptable *pt, struct proc *proc)
{
struct proc *p = 0;
struct proc *n;
n = pt->runq;
while (n != 0) {
if (n == proc) {
if (p == 0) {
pt->runq = n->next;
} else {
p->next = n->next;
}
n->next = 0;
return;
} else {
p = n;
n = n->next;
}
}
}
void
delrun(struct proc *proc)
{
acquire(&ptable->lock);
delrun1(ptable, proc);
release(&ptable->lock);
}
//PAGEBREAK: 32
// Set up first user process.
void
......@@ -93,8 +155,7 @@ userinit(void)
safestrcpy(p->name, "initcode", sizeof(p->name));
p->cwd = namei("/");
p->state = RUNNABLE;
addrun(p);
}
// Grow current process's memory by n bytes.
......@@ -152,7 +213,7 @@ fork(void)
np->cwd = idup(proc->cwd);
pid = np->pid;
np->state = RUNNABLE;
addrun(np);
safestrcpy(np->name, proc->name, sizeof(proc->name));
return pid;
}
......@@ -180,8 +241,12 @@ exit(void)
iput(proc->cwd);
proc->cwd = 0;
cprintf("%d: exit %s\n", cpunum(), proc->name);
acquire(&ptable->lock);
delrun1(ptable, proc);
// Parent might be sleeping in wait().
wakeup1(proc->parent);
......@@ -243,6 +308,34 @@ wait(void)
}
}
void
steal(void)
{
int c;
struct proc *p;
int r = 0;
for (c = 0; c < NCPU; c++) {
if (c == cpunum())
continue;
acquire(&ptables[c].lock);
for(p = ptables[c].runq; p != 0; p = p->next) {
if (p->state == RUNNABLE) {
cprintf("%d: steal %d from %d\n", cpunum(), p->pid, c);
delrun1(&ptables[c], p);
addrun(p);
r = 1;
break;
}
}
release(&ptables[c].lock);
if (r) {
procdumpall();
return;
}
}
}
//PAGEBREAK: 42
// Per-CPU process scheduler.
// Each CPU calls scheduler() after setting itself up.
......@@ -262,7 +355,7 @@ scheduler(void)
// Loop over process table looking for process to run.
acquire(&ptable->lock);
for(p = ptable->proc; p < &ptable->proc[NPROC]; p++){
for(p = ptable->runq; p != 0; p = p->next) {
if(p->state != RUNNABLE)
continue;
......@@ -272,6 +365,7 @@ scheduler(void)
proc = p;
switchuvm(p);
p->state = RUNNING;
cprintf("%d: running %d\n", cpu->id, p->pid);
swtch(&cpu->scheduler, proc->context);
switchkvm();
......@@ -280,7 +374,7 @@ scheduler(void)
proc = 0;
}
release(&ptable->lock);
steal();
}
}
......@@ -309,7 +403,7 @@ void
yield(void)
{
acquire(&ptable->lock); //DOC: yieldlock
proc->state = RUNNABLE;
proc->state = RUNNABLE; // race? stays in runqueue
sched();
release(&ptable->lock);
}
......@@ -350,6 +444,7 @@ sleep(void *chan, struct spinlock *lk)
// Go to sleep.
proc->chan = chan;
proc->state = SLEEPING;
delrun1(ptable, proc);
sched();
// Tidy up.
......@@ -372,13 +467,14 @@ wakeup1(void *chan)
for(p = ptable->proc; p < &ptable->proc[NPROC]; p++)
if(p->state == SLEEPING && p->chan == chan)
p->state = RUNNABLE;
addrun1(p);
}
// Wake up all processes sleeping on chan.
void
wakeup(void *chan)
{
// XXX should go through all proctables
acquire(&ptable->lock);
wakeup1(chan);
release(&ptable->lock);
......@@ -398,7 +494,7 @@ kill(int pid)
p->killed = 1;
// Wake process from sleep if necessary.
if(p->state == SLEEPING)
p->state = RUNNABLE;
addrun1(p);
release(&ptable->lock);
return 0;
}
......@@ -424,6 +520,7 @@ procdump(int c)
};
int i;
struct proc *p;
struct proc *q;
char *state;
uint pc[10];
......@@ -443,6 +540,22 @@ procdump(int c)
}
cprintf("\n");
}
cprintf("runq: ");
for (q = ptables[c].runq; q != 0; q = q->next) {
if(q->state >= 0 && q->state < NELEM(states) && states[q->state])
state = states[q->state];
else
state = "???";
cprintf("%d %s %s, ", q->pid, state, q->name);
}
cprintf("\n");
}
void
procdumpall(void)
{
int c;
for (c = 0; c < NCPU; c++) {
procdump(c);
}
}
......@@ -45,6 +45,7 @@ struct proc {
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
char name[16]; // Process name (debugging)
struct proc *next;
};
// Process memory is laid out contiguously, low addresses first:
......@@ -67,11 +68,14 @@ struct cpu {
struct cpu *cpu;
struct proc *proc; // The currently-running process.
struct ptable *ptable; // The per-core proc table
struct kmem *kmem; // The per-core proc table
};
struct ptable {
char name[MAXNAME];
struct spinlock lock;
struct proc proc[NPROC];
struct proc *runq;
};
extern struct ptable ptables[NCPU];
......@@ -89,3 +93,4 @@ extern int ncpu;
extern struct cpu *cpu asm("%gs:0"); // &cpus[cpunum()]
extern struct proc *proc asm("%gs:4"); // cpus[cpunum()].proc
extern struct ptable *ptable asm("%gs:8"); // &ptables[cpunum()]
extern struct kmem *kmem asm("%gs:12"); // &kmems[cpunum()]
......@@ -6,6 +6,7 @@
#include "spinlock.h"
#include "proc.h"
#include "elf.h"
#include "kalloc.h"
extern char data[]; // defined in data.S
......@@ -36,8 +37,8 @@ seginit(void)
c->gdt[SEG_UCODE] = SEG(STA_X|STA_R, 0, 0xffffffff, DPL_USER);
c->gdt[SEG_UDATA] = SEG(STA_W, 0, 0xffffffff, DPL_USER);
// Map cpu, curproc, and ptable
c->gdt[SEG_KCPU] = SEG(STA_W, &c->cpu, 12, 0);
// Map cpu, curproc, ptable, kmem
c->gdt[SEG_KCPU] = SEG(STA_W, &c->cpu, 16, 0);
lgdt(c->gdt, sizeof(c->gdt));
loadgs(SEG_KCPU << 3);
......@@ -46,6 +47,7 @@ seginit(void)
cpu = c;
proc = 0;
ptable = &ptables[cpunum()];
kmem = &kmems[cpunum()];
}
// Return the address of the PTE in page table pgdir
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论