summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrtm <rtm>2006-07-11 17:39:45 +0000
committerrtm <rtm>2006-07-11 17:39:45 +0000
commitb548df152b5a53ea8cfcb2d94fbdee07884d8050 (patch)
treeb1eec270a0892fad7a256ae809ebedbbcfaeb720
parent5ce9751cab960e3b226eb0720e781e793a0be4ed (diff)
downloadxv6-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--Notes30
-rw-r--r--defs.h2
-rw-r--r--kalloc.c2
-rw-r--r--main.c7
-rw-r--r--proc.c42
-rw-r--r--proc.h1
-rw-r--r--spinlock.c4
-rw-r--r--syscall.c48
-rw-r--r--syscall.h1
-rw-r--r--trap.c11
-rw-r--r--usertests.c49
-rw-r--r--usys.S2
12 files changed, 152 insertions, 47 deletions
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)