diff options
| author | rtm <rtm> | 2006-07-11 17:39:45 +0000 | 
|---|---|---|
| committer | rtm <rtm> | 2006-07-11 17:39:45 +0000 | 
| commit | b548df152b5a53ea8cfcb2d94fbdee07884d8050 (patch) | |
| tree | b1eec270a0892fad7a256ae809ebedbbcfaeb720 | |
| parent | 5ce9751cab960e3b226eb0720e781e793a0be4ed (diff) | |
| download | xv6-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-- | Notes | 30 | ||||
| -rw-r--r-- | defs.h | 2 | ||||
| -rw-r--r-- | kalloc.c | 2 | ||||
| -rw-r--r-- | main.c | 7 | ||||
| -rw-r--r-- | proc.c | 42 | ||||
| -rw-r--r-- | proc.h | 1 | ||||
| -rw-r--r-- | spinlock.c | 4 | ||||
| -rw-r--r-- | syscall.c | 48 | ||||
| -rw-r--r-- | syscall.h | 1 | ||||
| -rw-r--r-- | trap.c | 11 | ||||
| -rw-r--r-- | usertests.c | 49 | ||||
| -rw-r--r-- | usys.S | 2 | 
12 files changed, 152 insertions, 47 deletions
| @@ -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 @@ -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; @@ -158,6 +158,4 @@ ktest()    if(p1 == 0)      panic("ktest2");    kfree(p1, PAGE * 20); - -  cprintf("ktest ok\n");  } @@ -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(); @@ -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(); +} @@ -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 @@ -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 @@ -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 @@ -7,3 +7,4 @@  #define SYS_read 7  #define SYS_close 8  #define SYS_block 9 +#define SYS_kill 10 @@ -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)      ; @@ -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) | 
