diff --git a/Notes b/Notes index 63eb0c7..d8f4869 100644 --- a/Notes +++ b/Notes @@ -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 diff --git a/defs.h b/defs.h index 9e10bee..6a13ad2 100644 --- a/defs.h +++ b/defs.h @@ -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; diff --git a/kalloc.c b/kalloc.c index 1944508..b14a69a 100644 --- a/kalloc.c +++ b/kalloc.c @@ -158,6 +158,4 @@ ktest() if(p1 == 0) panic("ktest2"); kfree(p1, PAGE * 20); - - cprintf("ktest ok\n"); } diff --git a/main.c b/main.c index b711640..ce29af3 100644 --- a/main.c +++ b/main.c @@ -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(); diff --git a/proc.c b/proc.c index bdff377..d7fc638 100644 --- a/proc.c +++ b/proc.c @@ -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(); +} diff --git a/proc.h b/proc.h index b5cf015..86ba0eb 100644 --- a/proc.h +++ b/proc.h @@ -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 diff --git a/spinlock.c b/spinlock.c index 8d40258..d73faff 100644 --- a/spinlock.c +++ b/spinlock.c @@ -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 diff --git a/syscall.c b/syscall.c index 03fe608..4ecb31c 100644 --- a/syscall.c +++ b/syscall.c @@ -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 diff --git a/syscall.h b/syscall.h index 0378c53..6a76893 100644 --- a/syscall.h +++ b/syscall.h @@ -7,3 +7,4 @@ #define SYS_read 7 #define SYS_close 8 #define SYS_block 9 +#define SYS_kill 10 diff --git a/trap.c b/trap.c index d177d04..d7739f7 100644 --- a/trap.c +++ b/trap.c @@ -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) ; diff --git a/usys.S b/usys.S index c399d62..53958c1 100644 --- a/usys.S +++ b/usys.S @@ -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)