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?
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

2
defs.h
View file

@ -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;

View file

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

7
main.c
View file

@ -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();

42
proc.c
View file

@ -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();
}

1
proc.h
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -7,3 +7,4 @@
#define SYS_read 7
#define SYS_close 8
#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()];
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)){

View file

@ -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)
;

2
usys.S
View file

@ -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)