pre-empt both user and kernel, in clock interrupt

usertest.c tests pre-emption
kill()
This commit is contained in:
rtm 2006-07-11 17:39:45 +00:00
parent 5ce9751cab
commit b548df152b
12 changed files with 152 additions and 47 deletions

30
Notes
View file

@ -80,16 +80,22 @@ trap() ought to lgdt on return, since currently only done in swtch()
protect hardware interrupt vectors from user INT instructions? 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 out-of-fd cases for creating pipe.
test pipe circular buffer test pipe reader closes then write
test pipe writer or reader closes while other active or waiting test two readers, two writers.
test exit vs fd reference counts test children being inherited by grandparent &c
test write of more than PIPESIZE
test reader goes first vs writer goes first kill
test streaming of a lot of data 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

2
defs.h
View file

@ -17,6 +17,8 @@ void swtch(void);
void sleep(void *); void sleep(void *);
void wakeup(void *); void wakeup(void *);
void scheduler(void); void scheduler(void);
void proc_exit(void);
void yield(void);
// swtch.S // swtch.S
struct jmpbuf; struct jmpbuf;

View file

@ -158,6 +158,4 @@ ktest()
if(p1 == 0) if(p1 == 0)
panic("ktest2"); panic("ktest2");
kfree(p1, PAGE * 20); kfree(p1, PAGE * 20);
cprintf("ktest ok\n");
} }

7
main.c
View file

@ -66,11 +66,12 @@ main()
ide_init(); ide_init();
// become interruptable // become interruptable
write_eflags(read_eflags() | FL_IF); sti();
p = newproc(); 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"); cprintf("loaded userfs\n");
scheduler(); scheduler();

42
proc.c
View file

@ -184,3 +184,45 @@ wakeup(void *chan)
if(p->state == WAITING && p->chan == chan) if(p->state == WAITING && p->chan == chan)
p->state = RUNNABLE; 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();
}

1
proc.h
View file

@ -41,6 +41,7 @@ struct proc{
int pid; int pid;
int ppid; int ppid;
void *chan; // sleep void *chan; // sleep
int killed;
struct fd *fds[NOFILE]; struct fd *fds[NOFILE];
struct Taskstate ts; // only to give cpu address of kernel stack struct Taskstate ts; // only to give cpu address of kernel stack

View file

@ -20,7 +20,7 @@ acquire_spinlock(uint32_t* lock)
// 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_id, getcallerpc(&lock));
write_eflags(read_eflags() & ~FL_IF); cli();
if (*lock == cpu_id) if (*lock == cpu_id)
panic("recursive lock"); panic("recursive lock");
@ -37,7 +37,7 @@ release_spinlock(uint32_t* lock)
panic("release_spinlock: releasing a lock that i don't own\n"); panic("release_spinlock: releasing a lock that i don't own\n");
*lock = LOCK_FREE; *lock = LOCK_FREE;
// on a real machine there would be a memory barrier here // on a real machine there would be a memory barrier here
write_eflags(read_eflags() | FL_IF); sti();
} }
void void

View file

@ -155,32 +155,7 @@ sys_fork()
int int
sys_exit() sys_exit()
{ {
struct proc *p; proc_exit();
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();
return 0; return 0;
} }
@ -250,6 +225,24 @@ sys_block(void)
return 0; 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 void
syscall() syscall()
{ {
@ -286,6 +279,9 @@ syscall()
case SYS_block: case SYS_block:
ret = sys_block(); ret = sys_block();
break; break;
case SYS_kill:
ret = sys_kill();
break;
default: default:
cprintf("unknown sys call %d\n", num); cprintf("unknown sys call %d\n", num);
// XXX fault // XXX fault

View file

@ -7,3 +7,4 @@
#define SYS_read 7 #define SYS_read 7
#define SYS_close 8 #define SYS_close 8
#define SYS_block 9 #define SYS_block 9
#define SYS_kill 10

11
trap.c
View file

@ -45,6 +45,8 @@ trap(struct Trapframe *tf)
struct proc *cp = curproc[cpu()]; struct proc *cp = curproc[cpu()];
if(cp == 0) if(cp == 0)
panic("syscall with no proc"); panic("syscall with no proc");
if(cp->killed)
proc_exit();
cp->tf = tf; cp->tf = tf;
syscall(); syscall();
if(cp != curproc[cpu()]) if(cp != curproc[cpu()])
@ -55,11 +57,20 @@ trap(struct Trapframe *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)
proc_exit();
return; return;
} }
if(v == (IRQ_OFFSET + IRQ_TIMER)){ if(v == (IRQ_OFFSET + IRQ_TIMER)){
struct proc *cp = curproc[cpu()];
lapic_timerintr(); lapic_timerintr();
if(cp){
sti();
if(cp->killed)
proc_exit();
yield();
}
return; return;
} }
if(v == (IRQ_OFFSET + IRQ_IDE)){ if(v == (IRQ_OFFSET + IRQ_IDE)){

View file

@ -1,7 +1,7 @@
// simple fork and pipe read/write
char buf[2048]; char buf[2048];
// simple fork and pipe read/write
void void
pipe1() pipe1()
{ {
@ -47,9 +47,54 @@ pipe1()
puts("pipe1 ok\n"); 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() main()
{ {
puts("usertests starting\n");
pipe1(); pipe1();
//preempt();
while(1) while(1)
; ;

2
usys.S
View file

@ -10,9 +10,11 @@
STUB(fork) STUB(fork)
STUB(exit) STUB(exit)
STUB(wait)
STUB(cons_putc) STUB(cons_putc)
STUB(pipe) STUB(pipe)
STUB(read) STUB(read)
STUB(write) STUB(write)
STUB(close) STUB(close)
STUB(block) STUB(block)
STUB(kill)