pre-empt both user and kernel, in clock interrupt
usertest.c tests pre-emption kill()
This commit is contained in:
		
							parent
							
								
									5ce9751cab
								
							
						
					
					
						commit
						b548df152b
					
				
					 12 changed files with 152 additions and 47 deletions
				
			
		
							
								
								
									
										30
									
								
								Notes
									
										
									
									
									
								
							
							
						
						
									
										30
									
								
								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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								defs.h
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								kalloc.c
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								kalloc.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -158,6 +158,4 @@ ktest()
 | 
			
		|||
  if(p1 == 0)
 | 
			
		||||
    panic("ktest2");
 | 
			
		||||
  kfree(p1, PAGE * 20);
 | 
			
		||||
 | 
			
		||||
  cprintf("ktest ok\n");
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										7
									
								
								main.c
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								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();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										42
									
								
								proc.c
									
										
									
									
									
								
							
							
						
						
									
										42
									
								
								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();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								proc.h
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										48
									
								
								syscall.c
									
										
									
									
									
								
							
							
						
						
									
										48
									
								
								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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,3 +7,4 @@
 | 
			
		|||
#define SYS_read 7
 | 
			
		||||
#define SYS_close 8
 | 
			
		||||
#define SYS_block 9
 | 
			
		||||
#define SYS_kill 10
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										11
									
								
								trap.c
									
										
									
									
									
								
							
							
						
						
									
										11
									
								
								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)){
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										49
									
								
								usertests.c
									
										
									
									
									
								
							
							
						
						
									
										49
									
								
								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)
 | 
			
		||||
    ;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								usys.S
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue