diff options
author | rtm <rtm> | 2006-07-11 17:39:45 +0000 |
---|---|---|
committer | rtm <rtm> | 2006-07-11 17:39:45 +0000 |
commit | b548df152b5a53ea8cfcb2d94fbdee07884d8050 (patch) | |
tree | b1eec270a0892fad7a256ae809ebedbbcfaeb720 | |
parent | 5ce9751cab960e3b226eb0720e781e793a0be4ed (diff) | |
download | xv6-labs-b548df152b5a53ea8cfcb2d94fbdee07884d8050.tar.gz xv6-labs-b548df152b5a53ea8cfcb2d94fbdee07884d8050.tar.bz2 xv6-labs-b548df152b5a53ea8cfcb2d94fbdee07884d8050.zip |
pre-empt both user and kernel, in clock interrupt
usertest.c tests pre-emption
kill()
-rw-r--r-- | Notes | 30 | ||||
-rw-r--r-- | defs.h | 2 | ||||
-rw-r--r-- | kalloc.c | 2 | ||||
-rw-r--r-- | main.c | 7 | ||||
-rw-r--r-- | proc.c | 42 | ||||
-rw-r--r-- | proc.h | 1 | ||||
-rw-r--r-- | spinlock.c | 4 | ||||
-rw-r--r-- | syscall.c | 48 | ||||
-rw-r--r-- | syscall.h | 1 | ||||
-rw-r--r-- | trap.c | 11 | ||||
-rw-r--r-- | usertests.c | 49 | ||||
-rw-r--r-- | usys.S | 2 |
12 files changed, 152 insertions, 47 deletions
@@ -80,16 +80,22 @@ trap() ought to lgdt on return, since currently only done in swtch() protect hardware interrupt vectors from user INT instructions? -i'm getting a curious interrupt when jumping into user space. maybe -it's IRQ 0, but it comes at a weird and changing vector (e.g. 119) if -you don't initialize the PIC. why doesn't jos see this? if i -initialize the PIC with IRQ_OFFSET 32, the interrupt arrives at vector -32. - test out-of-fd cases for creating pipe. -test pipe circular buffer -test pipe writer or reader closes while other active or waiting -test exit vs fd reference counts -test write of more than PIPESIZE -test reader goes first vs writer goes first -test streaming of a lot of data +test pipe reader closes then write +test two readers, two writers. +test children being inherited by grandparent &c + +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! + in case you acquire two locks @@ -17,6 +17,8 @@ void swtch(void); void sleep(void *); void wakeup(void *); void scheduler(void); +void proc_exit(void); +void yield(void); // swtch.S struct jmpbuf; @@ -158,6 +158,4 @@ ktest() if(p1 == 0) panic("ktest2"); kfree(p1, PAGE * 20); - - cprintf("ktest ok\n"); } @@ -66,11 +66,12 @@ main() ide_init(); // become interruptable - write_eflags(read_eflags() | FL_IF); + sti(); p = newproc(); - // load_icode(p, _binary_usertests_start, (unsigned) _binary_usertests_size); - load_icode(p, _binary_userfs_start, (unsigned) _binary_userfs_size); + + load_icode(p, _binary_usertests_start, (unsigned) _binary_usertests_size); + //load_icode(p, _binary_userfs_start, (unsigned) _binary_userfs_size); cprintf("loaded userfs\n"); scheduler(); @@ -184,3 +184,45 @@ wakeup(void *chan) if(p->state == WAITING && p->chan == chan) p->state = RUNNABLE; } + +// give up the CPU but stay marked as RUNNABLE +void +yield() +{ + if(curproc[cpu()] == 0 || curproc[cpu()]->state != RUNNING) + panic("yield"); + curproc[cpu()]->state = RUNNABLE; + swtch(); +} + +void +proc_exit() +{ + struct proc *p; + struct proc *cp = curproc[cpu()]; + int fd; + + cprintf("exit %x\n", cp); + + for(fd = 0; fd < NOFILE; fd++){ + if(cp->fds[fd]){ + fd_close(cp->fds[fd]); + cp->fds[fd] = 0; + } + } + + cp->state = ZOMBIE; + + // wake up parent + for(p = proc; p < &proc[NPROC]; p++) + if(p->pid == cp->ppid) + wakeup(p); + + // abandon children + for(p = proc; p < &proc[NPROC]; p++) + if(p->ppid == cp->pid) + p->pid = 1; + + // switch into scheduler + swtch(); +} @@ -41,6 +41,7 @@ struct proc{ int pid; int ppid; void *chan; // sleep + int killed; struct fd *fds[NOFILE]; struct Taskstate ts; // only to give cpu address of kernel stack @@ -20,7 +20,7 @@ acquire_spinlock(uint32_t* lock) // on a real machine there would be a memory barrier here if(DEBUG) cprintf("cpu%d: acquiring at %x\n", cpu_id, getcallerpc(&lock)); - write_eflags(read_eflags() & ~FL_IF); + cli(); if (*lock == cpu_id) panic("recursive lock"); @@ -37,7 +37,7 @@ release_spinlock(uint32_t* lock) 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 - write_eflags(read_eflags() | FL_IF); + sti(); } void @@ -155,32 +155,7 @@ sys_fork() int sys_exit() { - struct proc *p; - struct proc *cp = curproc[cpu()]; - int fd; - - for(fd = 0; fd < NOFILE; fd++){ - if(cp->fds[fd]){ - fd_close(cp->fds[fd]); - cp->fds[fd] = 0; - } - } - - cp->state = ZOMBIE; - - // wake up parent - for(p = proc; p < &proc[NPROC]; p++) - if(p->pid == cp->ppid) - wakeup(p); - - // abandon children - for(p = proc; p < &proc[NPROC]; p++) - if(p->ppid == cp->pid) - p->pid = 1; - - // switch into scheduler - swtch(); - + proc_exit(); return 0; } @@ -250,6 +225,24 @@ sys_block(void) return 0; } +int +sys_kill() +{ + int pid; + struct proc *p; + + fetcharg(0, &pid); + for(p = proc; p < &proc[NPROC]; p++){ + if(p->pid == pid && p->state != UNUSED){ + p->killed = 1; + if(p->state == WAITING) + p->state = RUNNABLE; + return 0; + } + } + return -1; +} + void syscall() { @@ -286,6 +279,9 @@ syscall() case SYS_block: ret = sys_block(); break; + case SYS_kill: + ret = sys_kill(); + break; default: cprintf("unknown sys call %d\n", num); // XXX fault @@ -7,3 +7,4 @@ #define SYS_read 7 #define SYS_close 8 #define SYS_block 9 +#define SYS_kill 10 @@ -45,6 +45,8 @@ trap(struct Trapframe *tf) struct proc *cp = curproc[cpu()]; if(cp == 0) panic("syscall with no proc"); + if(cp->killed) + proc_exit(); cp->tf = tf; syscall(); if(cp != curproc[cpu()]) @@ -55,11 +57,20 @@ trap(struct Trapframe *tf) panic("trap ret wrong tf"); if(read_esp() < (unsigned)cp->kstack || read_esp() >= (unsigned)cp->kstack + KSTACKSIZE) panic("trap ret esp wrong"); + if(cp->killed) + proc_exit(); return; } if(v == (IRQ_OFFSET + IRQ_TIMER)){ + struct proc *cp = curproc[cpu()]; lapic_timerintr(); + if(cp){ + sti(); + if(cp->killed) + proc_exit(); + yield(); + } return; } if(v == (IRQ_OFFSET + IRQ_IDE)){ diff --git a/usertests.c b/usertests.c index 37540db..2f688ca 100644 --- a/usertests.c +++ b/usertests.c @@ -1,7 +1,7 @@ -// simple fork and pipe read/write - char buf[2048]; +// simple fork and pipe read/write + void pipe1() { @@ -47,9 +47,54 @@ pipe1() puts("pipe1 ok\n"); } +// meant to be run w/ at most two CPUs +void +preempt() +{ + int pid1, pid2, pid3; + int pfds[2]; + + pid1 = fork(); + if(pid1 == 0) + while(1) + ; + + pid2 = fork(); + if(pid2 == 0) + while(1) + ; + + pipe(pfds); + pid3 = fork(); + if(pid3 == 0){ + close(pfds[0]); + if(write(pfds[1], "x", 1) != 1) + puts("preempt write error"); + close(pfds[1]); + while(1) + ; + } + + close(pfds[1]); + if(read(pfds[0], buf, sizeof(buf)) != 1){ + puts("preempt read error"); + return; + } + close(pfds[0]); + kill(pid1); + kill(pid2); + kill(pid3); + wait(); + wait(); + wait(); + puts("preempt ok\n"); +} + main() { + puts("usertests starting\n"); pipe1(); + //preempt(); while(1) ; @@ -10,9 +10,11 @@ STUB(fork) STUB(exit) +STUB(wait) STUB(cons_putc) STUB(pipe) STUB(read) STUB(write) STUB(close) STUB(block) +STUB(kill) |