Skip to content
Snippets Groups Projects
Commit b548df15 authored by rtm's avatar rtm
Browse files

pre-empt both user and kernel, in clock interrupt

usertest.c tests pre-emption
kill()
parent 5ce9751c
No related branches found
No related tags found
No related merge requests found
...@@ -80,16 +80,22 @@ trap() ought to lgdt on return, since currently only done in swtch() ...@@ -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
...@@ -17,6 +17,8 @@ void swtch(void); ...@@ -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;
......
...@@ -158,6 +158,4 @@ ktest() ...@@ -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");
} }
...@@ -66,11 +66,12 @@ main() ...@@ -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();
......
...@@ -184,3 +184,45 @@ wakeup(void *chan) ...@@ -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();
}
...@@ -41,6 +41,7 @@ struct proc{ ...@@ -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
......
...@@ -20,7 +20,7 @@ acquire_spinlock(uint32_t* lock) ...@@ -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) ...@@ -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
......
...@@ -155,32 +155,7 @@ sys_fork() ...@@ -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) ...@@ -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() ...@@ -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
......
...@@ -7,3 +7,4 @@ ...@@ -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
...@@ -45,6 +45,8 @@ trap(struct Trapframe *tf) ...@@ -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) ...@@ -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)){
......
// 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() ...@@ -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)
; ;
......
...@@ -10,9 +10,11 @@ ...@@ -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)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment