Skip to content

Commit

Permalink
pre-empt both user and kernel, in clock interrupt
Browse files Browse the repository at this point in the history
usertest.c tests pre-emption
kill()
  • Loading branch information
rtm committed Jul 11, 2006
1 parent 5ce9751 commit b548df1
Show file tree
Hide file tree
Showing 12 changed files with 152 additions and 47 deletions.
30 changes: 18 additions & 12 deletions Notes
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 2 additions & 0 deletions defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 0 additions & 2 deletions kalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,4 @@ ktest()
if(p1 == 0)
panic("ktest2");
kfree(p1, PAGE * 20);

cprintf("ktest ok\n");
}
7 changes: 4 additions & 3 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
42 changes: 42 additions & 0 deletions proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 change: 1 addition & 0 deletions proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions spinlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand All @@ -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
Expand Down
48 changes: 22 additions & 26 deletions syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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()
{
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
#define SYS_read 7
#define SYS_close 8
#define SYS_block 9
#define SYS_kill 10
11 changes: 11 additions & 0 deletions trap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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()])
Expand All @@ -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)){
Expand Down
49 changes: 47 additions & 2 deletions usertests.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// simple fork and pipe read/write

char buf[2048];

// simple fork and pipe read/write

void
pipe1()
{
Expand Down Expand Up @@ -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)
;
Expand Down
2 changes: 2 additions & 0 deletions usys.S
Original file line number Diff line number Diff line change
Expand Up @@ -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)

0 comments on commit b548df1

Please sign in to comment.