no more big kernel lock

succeeds at usertests.c pipe test
This commit is contained in:
rtm 2006-07-12 01:48:35 +00:00
parent b41b38d0da
commit 4e8f237be8
15 changed files with 202 additions and 95 deletions

49
Notes
View file

@ -85,17 +85,44 @@ test pipe reader closes then write
test two readers, two writers. test two readers, two writers.
test children being inherited by grandparent &c test children being inherited by grandparent &c
kill some sleep()s should be interruptible by kill()
sleep()ing for something
running at user level
running in kernel
ooh, the relevant CPU may never get a clock interrupt
should each cpu have its own clock?
where to check?
loops around sleep()
return from any trap
rules about being killed deep inside a system call
test above cases
cli/sti in acquire/release should nest! cli/sti in acquire/release should nest!
in case you acquire two locks in case you acquire two locks
what would need fixing if we got rid of kernel_lock?
console output
proc_exit() needs lock on proc *array* to deallocate
kill() needs lock on proc *array*
allocator's free list
global fd table (really free-ness)
sys_close() on fd table
fork on proc list, also next pid
hold lock until public slots in proc struct initialized
locks
init_lock
sequences CPU startup
proc_table_lock
also protects next_pid
per-fd lock *just* protects count read-modify-write
also maybe freeness?
memory allocator
printf
wakeup needs proc_table_lock
so we need recursive locks?
or you must hold the lock to call wakeup?
if locks contain proc *, they can't be used at interrupt time
only proc_table_lock will be used at interrupt time?
maybe it doesn't matter if we use curproc?
in general, the table locks protect both free-ness and
public variables of table elements
in many cases you can use table elements w/o a lock
e.g. if you are the process, or you are using an fd
why can't i get a lock in console code?
always triple fault
lock code shouldn't call cprintf...

View file

@ -1,6 +1,9 @@
#include <types.h> #include <types.h>
#include <x86.h> #include <x86.h>
#include "defs.h" #include "defs.h"
#include "spinlock.h"
struct spinlock console_lock;
/* /*
* copy console output to parallel port, which you can tell * copy console output to parallel port, which you can tell
@ -26,6 +29,8 @@ cons_putc(int c)
unsigned short *crt = (unsigned short *) 0xB8000; // base of CGA memory unsigned short *crt = (unsigned short *) 0xB8000; // base of CGA memory
int ind; int ind;
//acquire(&console_lock);
lpt_putc(c); lpt_putc(c);
// cursor position, 16 bits, col + 80*row // cursor position, 16 bits, col + 80*row
@ -56,6 +61,8 @@ cons_putc(int c)
outb(crtport + 1, ind >> 8); outb(crtport + 1, ind >> 8);
outb(crtport, 15); outb(crtport, 15);
outb(crtport + 1, ind); outb(crtport + 1, ind);
//release(&console_lock);
} }
void void

10
defs.h
View file

@ -13,7 +13,7 @@ struct proc;
struct jmpbuf; struct jmpbuf;
void setupsegs(struct proc *); void setupsegs(struct proc *);
struct proc * newproc(void); struct proc * newproc(void);
void swtch(void); void swtch(int);
void sleep(void *); void sleep(void *);
void wakeup(void *); void wakeup(void *);
void scheduler(void); void scheduler(void);
@ -55,10 +55,9 @@ void lapic_enableintr(void);
void lapic_disableintr(void); void lapic_disableintr(void);
// spinlock.c // spinlock.c
extern uint32_t kernel_lock; struct spinlock;
void acquire_spinlock(uint32_t* lock); void acquire(struct spinlock * lock);
void release_spinlock(uint32_t* lock); void release(struct spinlock * lock);
void release_grant_spinlock(uint32_t* lock, int cpu);
// main.c // main.c
void load_icode(struct proc *p, uint8_t *binary, unsigned size); void load_icode(struct proc *p, uint8_t *binary, unsigned size);
@ -77,6 +76,7 @@ struct fd * fd_alloc();
void fd_close(struct fd *); void fd_close(struct fd *);
int fd_read(struct fd *fd, char *addr, int n); int fd_read(struct fd *fd, char *addr, int n);
int fd_write(struct fd *fd, char *addr, int n); int fd_write(struct fd *fd, char *addr, int n);
void fd_reference(struct fd *fd);
// ide.c // ide.c
void ide_init(void); void ide_init(void);

25
fd.c
View file

@ -5,6 +5,9 @@
#include "proc.h" #include "proc.h"
#include "defs.h" #include "defs.h"
#include "fd.h" #include "fd.h"
#include "spinlock.h"
struct spinlock fd_table_lock;
struct fd fds[NFD]; struct fd fds[NFD];
@ -22,18 +25,24 @@ fd_ualloc()
return -1; return -1;
} }
/*
* allocate a file descriptor structure
*/
struct fd * struct fd *
fd_alloc() fd_alloc()
{ {
int i; int i;
acquire(&fd_table_lock);
for(i = 0; i < NFD; i++){ for(i = 0; i < NFD; i++){
if(fds[i].type == FD_CLOSED){ if(fds[i].type == FD_CLOSED){
fds[i].type = FD_NONE; fds[i].type = FD_NONE;
fds[i].count = 1; fds[i].count = 1;
release(&fd_table_lock);
return fds + i; return fds + i;
} }
} }
release(&fd_table_lock);
return 0; return 0;
} }
@ -69,8 +78,11 @@ fd_read(struct fd *fd, char *addr, int n)
void void
fd_close(struct fd *fd) fd_close(struct fd *fd)
{ {
acquire(&fd_table_lock);
if(fd->count < 1 || fd->type == FD_CLOSED) if(fd->count < 1 || fd->type == FD_CLOSED)
panic("fd_close"); panic("fd_close");
fd->count -= 1; fd->count -= 1;
if(fd->count == 0){ if(fd->count == 0){
@ -79,6 +91,19 @@ fd_close(struct fd *fd)
} else { } else {
panic("fd_close"); panic("fd_close");
} }
fd->count = 0;
fd->type = FD_CLOSED; fd->type = FD_CLOSED;
} }
release(&fd_table_lock);
}
void
fd_reference(struct fd *fd)
{
acquire(&fd_table_lock);
if(fd->count < 1 || fd->type == FD_CLOSED)
panic("fd_reference");
fd->count += 1;
release(&fd_table_lock);
} }

View file

@ -10,6 +10,9 @@
#include "param.h" #include "param.h"
#include "types.h" #include "types.h"
#include "defs.h" #include "defs.h"
#include "spinlock.h"
struct spinlock kalloc_lock;
struct run { struct run {
struct run *next; struct run *next;
@ -54,6 +57,8 @@ kfree(char *cp, int len)
for(i = 0; i < len; i++) for(i = 0; i < len; i++)
cp[i] = 1; cp[i] = 1;
acquire(&kalloc_lock);
rr = &freelist; rr = &freelist;
while(*rr){ while(*rr){
struct run *rend = (struct run *) ((char *)(*rr) + (*rr)->len); struct run *rend = (struct run *) ((char *)(*rr) + (*rr)->len);
@ -63,13 +68,13 @@ kfree(char *cp, int len)
p->len = len + (*rr)->len; p->len = len + (*rr)->len;
p->next = (*rr)->next; p->next = (*rr)->next;
*rr = p; *rr = p;
return; goto out;
} }
if(pend < *rr){ if(pend < *rr){
p->len = len; p->len = len;
p->next = *rr; p->next = *rr;
*rr = p; *rr = p;
return; goto out;
} }
if(p == rend){ if(p == rend){
(*rr)->len += len; (*rr)->len += len;
@ -77,13 +82,16 @@ kfree(char *cp, int len)
(*rr)->len += (*rr)->next->len; (*rr)->len += (*rr)->next->len;
(*rr)->next = (*rr)->next->next; (*rr)->next = (*rr)->next->next;
} }
return; goto out;
} }
rr = &((*rr)->next); rr = &((*rr)->next);
} }
p->len = len; p->len = len;
p->next = 0; p->next = 0;
*rr = p; *rr = p;
out:
release(&kalloc_lock);
} }
/* /*
@ -99,20 +107,25 @@ kalloc(int n)
if(n % PAGE) if(n % PAGE)
panic("kalloc"); panic("kalloc");
acquire(&kalloc_lock);
rr = &freelist; rr = &freelist;
while(*rr){ while(*rr){
struct run *r = *rr; struct run *r = *rr;
if(r->len == n){ if(r->len == n){
*rr = r->next; *rr = r->next;
release(&kalloc_lock);
return (char *) r; return (char *) r;
} }
if(r->len > n){ if(r->len > n){
char *p = (char *)r + (r->len - n); char *p = (char *)r + (r->len - n);
r->len -= n; r->len -= n;
release(&kalloc_lock);
return p; return p;
} }
rr = &(*rr)->next; rr = &(*rr)->next;
} }
release(&kalloc_lock);
return 0; return 0;
} }

12
main.c
View file

@ -15,8 +15,6 @@ extern char _binary_user1_start[], _binary_user1_size[];
extern char _binary_usertests_start[], _binary_usertests_size[]; extern char _binary_usertests_start[], _binary_usertests_size[];
extern char _binary_userfs_start[], _binary_userfs_size[]; extern char _binary_userfs_start[], _binary_userfs_size[];
char buf[512];
int int
main() main()
{ {
@ -24,8 +22,6 @@ main()
if (acpu) { if (acpu) {
cprintf("an application processor\n"); cprintf("an application processor\n");
release_spinlock(&kernel_lock);
acquire_spinlock(&kernel_lock);
idtinit(); // CPU's idt idtinit(); // CPU's idt
lapic_init(cpu()); lapic_init(cpu());
lapic_timerinit(); lapic_timerinit();
@ -39,7 +35,6 @@ main()
cprintf("\nxV6\n\n"); cprintf("\nxV6\n\n");
pic_init(); // initialize PIC pic_init(); // initialize PIC
mp_init(); // multiprocessor
kinit(); // physical memory allocator kinit(); // physical memory allocator
tvinit(); // trap vectors tvinit(); // trap vectors
idtinit(); // CPU's idt idtinit(); // CPU's idt
@ -61,11 +56,14 @@ main()
p->ppid = 0; p->ppid = 0;
setupsegs(p); setupsegs(p);
mp_init(); // multiprocessor
// turn on timer and enable interrupts on the local APIC // turn on timer and enable interrupts on the local APIC
lapic_timerinit(); lapic_timerinit();
lapic_enableintr(); lapic_enableintr();
// init disk device // init disk device
ide_init(); //ide_init();
// become interruptable // become interruptable
sti(); sti();
@ -74,7 +72,9 @@ main()
load_icode(p, _binary_usertests_start, (unsigned) _binary_usertests_size); load_icode(p, _binary_usertests_start, (unsigned) _binary_usertests_size);
//load_icode(p, _binary_userfs_start, (unsigned) _binary_userfs_size); //load_icode(p, _binary_userfs_start, (unsigned) _binary_userfs_size);
p->state = RUNNABLE;
cprintf("loaded userfs\n"); cprintf("loaded userfs\n");
scheduler(); scheduler();
return 0; return 0;

4
mp.c
View file

@ -391,15 +391,11 @@ mp_init()
memmove((void *) APBOOTCODE,_binary_bootother_start, memmove((void *) APBOOTCODE,_binary_bootother_start,
(uint32_t) _binary_bootother_size); (uint32_t) _binary_bootother_size);
acquire_spinlock(&kernel_lock);
for(c = 0; c < ncpu; c++){ for(c = 0; c < ncpu; c++){
if (cpus+c == bcpu) continue; if (cpus+c == bcpu) continue;
cprintf ("starting processor %d\n", c); cprintf ("starting processor %d\n", c);
release_grant_spinlock(&kernel_lock, c);
*(unsigned *)(APBOOTCODE-4) = (unsigned) (cpus[c].mpstack) + MPSTACK; // tell it what to use for %esp *(unsigned *)(APBOOTCODE-4) = (unsigned) (cpus[c].mpstack) + MPSTACK; // tell it what to use for %esp
*(unsigned *)(APBOOTCODE-8) = (unsigned)&main; // tell it where to jump to *(unsigned *)(APBOOTCODE-8) = (unsigned)&main; // tell it where to jump to
lapic_startap(cpus + c, (uint32_t) APBOOTCODE); lapic_startap(cpus + c, (uint32_t) APBOOTCODE);
acquire_spinlock(&kernel_lock);
cprintf ("done starting processor %d\n", c);
} }
} }

10
pipe.c
View file

@ -5,6 +5,7 @@
#include "proc.h" #include "proc.h"
#include "defs.h" #include "defs.h"
#include "fd.h" #include "fd.h"
#include "spinlock.h"
#define PIPESIZE 512 #define PIPESIZE 512
@ -13,6 +14,7 @@ struct pipe {
int writeopen; // write fd is still open int writeopen; // write fd is still open
int writep; // next index to write int writep; // next index to write
int readp; // next index to read int readp; // next index to read
struct spinlock lock;
char data[PIPESIZE]; char data[PIPESIZE];
}; };
@ -32,6 +34,7 @@ pipe_alloc(struct fd **fd1, struct fd **fd2)
p->writeopen = 1; p->writeopen = 1;
p->writep = 0; p->writep = 0;
p->readp = 0; p->readp = 0;
memset(&p->lock, 0, sizeof(p->lock));
(*fd1)->type = FD_PIPE; (*fd1)->type = FD_PIPE;
(*fd1)->readable = 1; (*fd1)->readable = 1;
(*fd1)->writeable = 0; (*fd1)->writeable = 0;
@ -74,16 +77,21 @@ pipe_write(struct pipe *p, char *addr, int n)
{ {
int i; int i;
acquire(&p->lock);
for(i = 0; i < n; i++){ for(i = 0; i < n; i++){
while(((p->writep + 1) % PIPESIZE) == p->readp){ while(((p->writep + 1) % PIPESIZE) == p->readp){
if(p->readopen == 0) if(p->readopen == 0)
return -1; return -1;
release(&p->lock);
wakeup(&p->readp); wakeup(&p->readp);
sleep(&p->writep); sleep(&p->writep);
acquire(&p->lock);
} }
p->data[p->writep] = addr[i]; p->data[p->writep] = addr[i];
p->writep = (p->writep + 1) % PIPESIZE; p->writep = (p->writep + 1) % PIPESIZE;
} }
release(&p->lock);
wakeup(&p->readp); wakeup(&p->readp);
return i; return i;
} }
@ -99,12 +107,14 @@ pipe_read(struct pipe *p, char *addr, int n)
sleep(&p->readp); sleep(&p->readp);
} }
acquire(&p->lock);
for(i = 0; i < n; i++){ for(i = 0; i < n; i++){
if(p->readp == p->writep) if(p->readp == p->writep)
break; break;
addr[i] = p->data[p->readp]; addr[i] = p->data[p->readp];
p->readp = (p->readp + 1) % PIPESIZE; p->readp = (p->readp + 1) % PIPESIZE;
} }
release(&p->lock);
wakeup(&p->writep); wakeup(&p->writep);
return i; return i;
} }

67
proc.c
View file

@ -5,6 +5,9 @@
#include "fd.h" #include "fd.h"
#include "proc.h" #include "proc.h"
#include "defs.h" #include "defs.h"
#include "spinlock.h"
struct spinlock proc_table_lock;
struct proc proc[NPROC]; struct proc proc[NPROC];
struct proc *curproc[NCPU]; struct proc *curproc[NCPU];
@ -43,6 +46,7 @@ extern void trapret();
/* /*
* internal fork(). does not copy kernel stack; instead, * internal fork(). does not copy kernel stack; instead,
* sets up the stack to return as if from system call. * sets up the stack to return as if from system call.
* caller must set state to RUNNABLE.
*/ */
struct proc * struct proc *
newproc() newproc()
@ -51,11 +55,18 @@ newproc()
struct proc *op; struct proc *op;
int fd; int fd;
for(np = &proc[1]; np < &proc[NPROC]; np++) acquire(&proc_table_lock);
if(np->state == UNUSED)
for(np = &proc[1]; np < &proc[NPROC]; np++){
if(np->state == UNUSED){
np->state = EMBRYO;
break; break;
if(np >= &proc[NPROC]) }
}
if(np >= &proc[NPROC]){
release(&proc_table_lock);
return 0; return 0;
}
// copy from proc[0] if we're bootstrapping // copy from proc[0] if we're bootstrapping
op = curproc[cpu()]; op = curproc[cpu()];
@ -64,6 +75,9 @@ newproc()
np->pid = next_pid++; np->pid = next_pid++;
np->ppid = op->pid; np->ppid = op->pid;
release(&proc_table_lock);
np->sz = op->sz; np->sz = op->sz;
np->mem = kalloc(op->sz); np->mem = kalloc(op->sz);
if(np->mem == 0) if(np->mem == 0)
@ -72,6 +86,7 @@ newproc()
np->kstack = kalloc(KSTACKSIZE); np->kstack = kalloc(KSTACKSIZE);
if(np->kstack == 0){ if(np->kstack == 0){
kfree(np->mem, op->sz); kfree(np->mem, op->sz);
np->state = UNUSED;
return 0; return 0;
} }
setupsegs(np); setupsegs(np);
@ -91,11 +106,9 @@ newproc()
for(fd = 0; fd < NOFILE; fd++){ for(fd = 0; fd < NOFILE; fd++){
np->fds[fd] = op->fds[fd]; np->fds[fd] = op->fds[fd];
if(np->fds[fd]) if(np->fds[fd])
np->fds[fd]->count += 1; fd_reference(np->fds[fd]);
} }
np->state = RUNNABLE;
cprintf("newproc %x\n", np); cprintf("newproc %x\n", np);
return np; return np;
@ -111,11 +124,20 @@ scheduler(void)
cpus[cpu()].lastproc = &proc[0]; cpus[cpu()].lastproc = &proc[0];
setjmp(&cpus[cpu()].jmpbuf); setjmp(&cpus[cpu()].jmpbuf);
op = curproc[cpu()];
if(op){
if(op->newstate <= 0 || op->newstate > ZOMBIE)
panic("scheduler");
op->state = op->newstate;
op->newstate = -1;
}
// find a runnable process and switch to it // find a runnable process and switch to it
curproc[cpu()] = 0; curproc[cpu()] = 0;
np = cpus[cpu()].lastproc + 1; np = cpus[cpu()].lastproc + 1;
while(1){ while(1){
acquire(&proc_table_lock);
for(i = 0; i < NPROC; i++){ for(i = 0; i < NPROC; i++){
if(np >= &proc[NPROC]) if(np >= &proc[NPROC])
np = &proc[0]; np = &proc[0];
@ -123,20 +145,20 @@ scheduler(void)
break; break;
np++; np++;
} }
if(i < NPROC)
if(i < NPROC){
np->state = RUNNING;
release(&proc_table_lock);
break; break;
// cprintf("swtch %d: nothing to run %d %d\n", }
// cpu(), proc[1].state, proc[2].state);
release_spinlock(&kernel_lock); release(&proc_table_lock);
acquire_spinlock(&kernel_lock);
np = &proc[0]; np = &proc[0];
} }
cpus[cpu()].lastproc = np; cpus[cpu()].lastproc = np;
curproc[cpu()] = np; curproc[cpu()] = np;
np->state = RUNNING;
// h/w sets busy bit in TSS descriptor sometimes, and faults // h/w sets busy bit in TSS descriptor sometimes, and faults
// if it's set in LTR. so clear tss descriptor busy bit. // if it's set in LTR. so clear tss descriptor busy bit.
np->gdt[SEG_TSS].sd_type = STS_T32A; np->gdt[SEG_TSS].sd_type = STS_T32A;
@ -155,11 +177,12 @@ scheduler(void)
// give up the cpu by switching to the scheduler, // give up the cpu by switching to the scheduler,
// which runs on the per-cpu stack. // which runs on the per-cpu stack.
void void
swtch(void) swtch(int newstate)
{ {
struct proc *p = curproc[cpu()]; struct proc *p = curproc[cpu()];
if(p == 0) if(p == 0)
panic("swtch"); panic("swtch");
p->newstate = newstate; // basically an argument to scheduler()
if(setjmp(&p->jmpbuf) == 0) if(setjmp(&p->jmpbuf) == 0)
longjmp(&cpus[cpu()].jmpbuf); longjmp(&cpus[cpu()].jmpbuf);
} }
@ -171,8 +194,7 @@ sleep(void *chan)
if(p == 0) if(p == 0)
panic("sleep"); panic("sleep");
p->chan = chan; p->chan = chan;
p->state = WAITING; swtch(WAITING);
swtch();
} }
void void
@ -180,9 +202,11 @@ wakeup(void *chan)
{ {
struct proc *p; struct proc *p;
acquire(&proc_table_lock);
for(p = proc; p < &proc[NPROC]; p++) for(p = proc; p < &proc[NPROC]; p++)
if(p->state == WAITING && p->chan == chan) if(p->state == WAITING && p->chan == chan)
p->state = RUNNABLE; p->state = RUNNABLE;
release(&proc_table_lock);
} }
// give up the CPU but stay marked as RUNNABLE // give up the CPU but stay marked as RUNNABLE
@ -191,8 +215,7 @@ yield()
{ {
if(curproc[cpu()] == 0 || curproc[cpu()]->state != RUNNING) if(curproc[cpu()] == 0 || curproc[cpu()]->state != RUNNING)
panic("yield"); panic("yield");
curproc[cpu()]->state = RUNNABLE; swtch(RUNNABLE);
swtch();
} }
void void
@ -211,7 +234,7 @@ proc_exit()
} }
} }
cp->state = ZOMBIE; acquire(&proc_table_lock);
// wake up parent // wake up parent
for(p = proc; p < &proc[NPROC]; p++) for(p = proc; p < &proc[NPROC]; p++)
@ -223,6 +246,8 @@ proc_exit()
if(p->ppid == cp->pid) if(p->ppid == cp->pid)
p->pid = 1; p->pid = 1;
acquire(&proc_table_lock);
// switch into scheduler // switch into scheduler
swtch(); swtch(ZOMBIE);
} }

5
proc.h
View file

@ -33,11 +33,14 @@ struct jmpbuf {
int jb_eip; int jb_eip;
}; };
enum proc_state { UNUSED, EMBRYO, WAITING, RUNNABLE, RUNNING, ZOMBIE };
struct proc{ struct proc{
char *mem; // start of process's physical memory char *mem; // start of process's physical memory
unsigned sz; // total size of mem, including kernel stack unsigned sz; // total size of mem, including kernel stack
char *kstack; // kernel stack, separate from mem so it doesn't move char *kstack; // kernel stack, separate from mem so it doesn't move
enum { UNUSED, RUNNABLE, WAITING, ZOMBIE, RUNNING } state; enum proc_state state;
enum proc_state newstate; // desired state after swtch()
int pid; int pid;
int ppid; int ppid;
void *chan; // sleep void *chan; // sleep

View file

@ -2,51 +2,50 @@
#include "defs.h" #include "defs.h"
#include "x86.h" #include "x86.h"
#include "mmu.h" #include "mmu.h"
#include "param.h"
#include "proc.h"
#include "spinlock.h"
#define LOCK_FREE -1
#define DEBUG 0 #define DEBUG 0
uint32_t kernel_lock = LOCK_FREE;
int getcallerpc(void *v) { int getcallerpc(void *v) {
return ((int*)v)[-1]; return ((int*)v)[-1];
} }
// lock = LOCK_FREE if free, else = cpu_id of owner CPU
void void
acquire_spinlock(uint32_t* lock) acquire(struct spinlock * lock)
{ {
int cpu_id = cpu(); struct proc * cp = curproc[cpu()];
// on a real machine there would be a memory barrier here // on a real machine there would be a memory barrier here
if(DEBUG) cprintf("cpu%d: acquiring at %x\n", cpu_id, getcallerpc(&lock)); if(DEBUG) cprintf("cpu%d: acquiring at %x\n", cpu(), getcallerpc(&lock));
cli(); if (cp && lock->p == cp && lock->locked){
if (*lock == cpu_id) lock->count += 1;
panic("recursive lock"); } else {
cli();
while ( cmpxchg(LOCK_FREE, cpu_id, lock) != cpu_id ) { ; } while ( cmpxchg(0, 1, &lock->locked) != 1 ) { ; }
if(DEBUG) cprintf("cpu%d: acquired at %x\n", cpu_id, getcallerpc(&lock)); lock->locker_pc = getcallerpc(&lock);
lock->count = 1;
lock->p = cp;
}
if(DEBUG) cprintf("cpu%d: acquired at %x\n", cpu(), getcallerpc(&lock));
} }
void void
release_spinlock(uint32_t* lock) release(struct spinlock * lock)
{ {
int cpu_id = cpu(); struct proc * cp = curproc[cpu()];
if(DEBUG) cprintf ("cpu%d: releasing at %x\n", cpu_id, getcallerpc(&lock));
if (*lock != cpu_id)
panic("release_spinlock: releasing a lock that i don't own\n");
*lock = LOCK_FREE;
// on a real machine there would be a memory barrier here
sti();
}
void if(DEBUG) cprintf ("cpu%d: releasing at %x\n", cpu(), getcallerpc(&lock));
release_grant_spinlock(uint32_t* lock, int c)
{
int cpu_id = cpu();
if(DEBUG) cprintf ("cpu%d: release_grant to %d at %x\n", cpu_id, c, getcallerpc(&lock));
if (*lock != cpu_id)
panic("release_spinlock: releasing a lock that i don't own\n");
*lock = c;
}
if(lock->p != cp || lock->count < 1 || lock->locked != 1)
panic("release");
lock->count -= 1;
if(lock->count < 1){
lock->p = 0;
cmpxchg(1, 0, &lock->locked);
sti();
// on a real machine there would be a memory barrier here
}
}

View file

@ -6,6 +6,7 @@
#include "x86.h" #include "x86.h"
#include "traps.h" #include "traps.h"
#include "syscall.h" #include "syscall.h"
#include "spinlock.h"
/* /*
* User code makes a system call with INT T_SYSCALL. * User code makes a system call with INT T_SYSCALL.
@ -18,6 +19,8 @@
* Return value? Error indication? Errno? * Return value? Error indication? Errno?
*/ */
extern struct spinlock proc_table_lock;
/* /*
* fetch 32 bits from a user-supplied pointer. * fetch 32 bits from a user-supplied pointer.
* returns 1 if addr was OK, 0 if illegal. * returns 1 if addr was OK, 0 if illegal.
@ -149,6 +152,7 @@ sys_fork()
struct proc *np; struct proc *np;
np = newproc(); np = newproc();
np->state = RUNNABLE;
return np->pid; return np->pid;
} }
@ -170,18 +174,21 @@ sys_wait()
while(1){ while(1){
any = 0; any = 0;
acquire(&proc_table_lock);
for(p = proc; p < &proc[NPROC]; p++){ for(p = proc; p < &proc[NPROC]; p++){
if(p->state == ZOMBIE && p->ppid == cp->pid){ if(p->state == ZOMBIE && p->ppid == cp->pid){
kfree(p->mem, p->sz); kfree(p->mem, p->sz);
kfree(p->kstack, KSTACKSIZE); kfree(p->kstack, KSTACKSIZE);
pid = p->pid; pid = p->pid;
p->state = UNUSED; p->state = UNUSED;
release(&proc_table_lock);
cprintf("%x collected %x\n", cp, p); cprintf("%x collected %x\n", cp, p);
return pid; return pid;
} }
if(p->state != UNUSED && p->ppid == cp->pid) if(p->state != UNUSED && p->ppid == cp->pid)
any = 1; any = 1;
} }
release(&proc_table_lock);
if(any == 0){ if(any == 0){
cprintf("%x nothing to wait for\n", cp); cprintf("%x nothing to wait for\n", cp);
return -1; return -1;
@ -232,14 +239,17 @@ sys_kill()
struct proc *p; struct proc *p;
fetcharg(0, &pid); fetcharg(0, &pid);
acquire(&proc_table_lock);
for(p = proc; p < &proc[NPROC]; p++){ for(p = proc; p < &proc[NPROC]; p++){
if(p->pid == pid && p->state != UNUSED){ if(p->pid == pid && p->state != UNUSED){
p->killed = 1; p->killed = 1;
if(p->state == WAITING) if(p->state == WAITING)
p->state = RUNNABLE; p->state = RUNNABLE;
release(&proc_table_lock);
return 0; return 0;
} }
} }
release(&proc_table_lock);
return -1; return -1;
} }

10
trap.c
View file

@ -5,6 +5,7 @@
#include "defs.h" #include "defs.h"
#include "x86.h" #include "x86.h"
#include "traps.h" #include "traps.h"
#include "syscall.h"
struct Gatedesc idt[256]; struct Gatedesc idt[256];
struct Pseudodesc idt_pd = { 0, sizeof(idt) - 1, (unsigned) &idt }; struct Pseudodesc idt_pd = { 0, sizeof(idt) - 1, (unsigned) &idt };
@ -35,12 +36,6 @@ trap(struct Trapframe *tf)
{ {
int v = tf->tf_trapno; int v = tf->tf_trapno;
if(tf->tf_cs == 0x8 && kernel_lock == cpu())
cprintf("cpu %d: trap %d from %x:%x with lock=%d\n",
cpu(), v, tf->tf_cs, tf->tf_eip, kernel_lock);
acquire_spinlock(&kernel_lock); // released in trapret in trapasm.S
if(v == T_SYSCALL){ if(v == T_SYSCALL){
struct proc *cp = curproc[cpu()]; struct proc *cp = curproc[cpu()];
if(cp == 0) if(cp == 0)
@ -55,7 +50,8 @@ trap(struct Trapframe *tf)
panic("trap ret but not RUNNING"); panic("trap ret but not RUNNING");
if(tf != cp->tf) if(tf != cp->tf)
panic("trap ret wrong tf"); panic("trap ret wrong tf");
if(read_esp() < (unsigned)cp->kstack || read_esp() >= (unsigned)cp->kstack + KSTACKSIZE) if(read_esp() < (unsigned)cp->kstack ||
read_esp() >= (unsigned)cp->kstack + KSTACKSIZE)
panic("trap ret esp wrong"); panic("trap ret esp wrong");
if(cp->killed) if(cp->killed)
proc_exit(); proc_exit();

View file

@ -22,10 +22,6 @@ alltraps:
* expects ESP to point to a Trapframe * expects ESP to point to a Trapframe
*/ */
trapret: trapret:
pushl $kernel_lock
call release_spinlock
addl $0x4, %esp
popal popal
popl %es popl %es
popl %ds popl %ds

View file

@ -93,8 +93,8 @@ preempt()
main() main()
{ {
puts("usertests starting\n"); puts("usertests starting\n");
//pipe1(); pipe1();
preempt(); //preempt();
while(1) while(1)
; ;