diff options
| author | rtm <rtm> | 2006-06-27 14:35:53 +0000 | 
|---|---|---|
| committer | rtm <rtm> | 2006-06-27 14:35:53 +0000 | 
| commit | c41f1de5d41a527a3fa2d1e94215766130eac456 (patch) | |
| tree | 86f6a467be8b42aec42a05299789f39ace9cc5e2 | |
| parent | b61c2547b8b489cab16984c0940a1cb6593a2a3d (diff) | |
| download | xv6-labs-c41f1de5d41a527a3fa2d1e94215766130eac456.tar.gz xv6-labs-c41f1de5d41a527a3fa2d1e94215766130eac456.tar.bz2 xv6-labs-c41f1de5d41a527a3fa2d1e94215766130eac456.zip  | |
file descriptors
pipes
| -rw-r--r-- | Makefile | 18 | ||||
| -rw-r--r-- | Notes | 8 | ||||
| -rw-r--r-- | defs.h | 16 | ||||
| -rw-r--r-- | fd.c | 80 | ||||
| -rw-r--r-- | fd.h | 9 | ||||
| -rw-r--r-- | main.c | 8 | ||||
| -rw-r--r-- | param.h | 2 | ||||
| -rw-r--r-- | pipe.c | 100 | ||||
| -rw-r--r-- | proc.c | 9 | ||||
| -rw-r--r-- | proc.h | 1 | ||||
| -rw-r--r-- | syscall.c | 93 | ||||
| -rw-r--r-- | syscall.h | 3 | ||||
| -rw-r--r-- | trap.c | 4 | ||||
| -rw-r--r-- | ulib.c | 44 | ||||
| -rw-r--r-- | user1.c | 38 | ||||
| -rw-r--r-- | usertests.c | 30 | 
16 files changed, 424 insertions, 39 deletions
@@ -1,5 +1,5 @@  OBJS = main.o console.o string.o kalloc.o proc.o trapasm.o trap.o vectors.o \ -       syscall.o ide.o picirq.o mp.o spinlock.o +       syscall.o ide.o picirq.o mp.o spinlock.o fd.o pipe.o  CC = i386-jos-elf-gcc  LD = i386-jos-elf-ld @@ -20,22 +20,30 @@ bootblock : bootasm.S bootmain.c  	$(OBJCOPY) -S -O binary bootblock.o bootblock  	./sign.pl bootblock -kernel : $(OBJS) bootother.S user1 +kernel : $(OBJS) bootother.S user1 usertests  	$(CC) -nostdinc -I. -c bootother.S  	$(LD) -N -e start -Ttext 0x7000 -o bootother.out bootother.o  	$(OBJCOPY) -S -O binary bootother.out bootother  	$(OBJDUMP) -S bootother.o > bootother.asm -	$(LD) -Ttext 0x100000 -e main -o kernel $(OBJS) -b binary bootother user1 +	$(LD) -Ttext 0x100000 -e main -o kernel $(OBJS) -b binary bootother user1 usertests  	$(OBJDUMP) -S kernel > kernel.asm  vectors.S : vectors.pl  	perl vectors.pl > vectors.S -user1 : user1.c +user1 : user1.c ulib.o  	$(CC) -nostdinc -I. -c user1.c -	$(LD) -N -e main -Ttext 0 -o user1 user1.o +	$(LD) -N -e main -Ttext 0 -o user1 user1.o ulib.o  	$(OBJDUMP) -S user1 > user1.asm +usertests : usertests.c ulib.o +	$(CC) -nostdinc -I. -c usertests.c +	$(LD) -N -e main -Ttext 0 -o usertests usertests.o ulib.o +	$(OBJDUMP) -S usertests > usertests.asm + +ulib.o : ulib.c +	$(CC) -nostdinc -I. -c ulib.c +  -include *.d  clean :  @@ -83,3 +83,11 @@ 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 @@ -37,6 +37,7 @@ void pic_init(void);  void mp_init(void);  int cpu(void);  int mp_isbcpu(void); +void lapic_init(int c);  // spinlock.c  extern uint32_t kernel_lock; @@ -46,3 +47,18 @@ void release_grant_spinlock(uint32_t* lock, int cpu);  // main.c  void load_icode(struct proc *p, uint8_t *binary, unsigned size); + +// pipe.c +struct pipe; +struct fd; +int pipe_alloc(struct fd **fd1, struct fd **fd2); +void pipe_close(struct pipe *p, int writeable); +int pipe_write(struct pipe *p, char *addr, int n); +int pipe_read(struct pipe *p, char *addr, int n); + +// fd.c +int fd_ualloc(); +struct fd * fd_alloc(); +void fd_close(struct fd *); +int fd_read(struct fd *fd, char *addr, int n); +int fd_write(struct fd *fd, char *addr, int n); @@ -0,0 +1,80 @@ +#include "types.h" +#include "param.h" +#include "x86.h" +#include "mmu.h" +#include "proc.h" +#include "defs.h" +#include "fd.h" + +struct fd fds[NFD]; + +/* + * allocate a file descriptor number for curproc. + */ +int +fd_ualloc() +{ +  int fd; +  struct proc *p = curproc[cpu()]; +  for(fd = 0; fd < NOFILE; fd++) +    if(p->fds[fd] == 0) +      return fd; +  return -1; +} + +struct fd * +fd_alloc() +{ +  int i; + +  for(i = 0; i < NFD; i++){ +    if(fds[i].type == FD_CLOSED){ +      fds[i].type = FD_NONE; +      fds[i].count = 1; +      return fds + i; +    } +  } +  return 0; +} + +void +fd_close(struct fd *fd) +{ +  if(fd->type == FD_CLOSED || fd->count <= 0) +    panic("fd_close"); +  fd->count -= 1; +  if(fd->count == 0){ +    if(fd->type == FD_PIPE) +      pipe_close(fd->pipe, fd->writeable); +    fd->type = FD_CLOSED; +  } +} + +/* + * addr is a kernel address, pointing into some process's p->mem. + */ +int +fd_write(struct fd *fd, char *addr, int n) +{ +  if(fd->writeable == 0) +    return -1; +  if(fd->type == FD_PIPE){ +    return pipe_write(fd->pipe, addr, n); +  } else { +    panic("fd_write"); +    return -1; +  } +} + +int +fd_read(struct fd *fd, char *addr, int n) +{ +  if(fd->readable == 0) +    return -1; +  if(fd->type == FD_PIPE){ +    return pipe_read(fd->pipe, addr, n); +  } else { +    panic("fd_read"); +    return -1; +  } +} @@ -0,0 +1,9 @@ +struct fd { +  enum { FD_CLOSED, FD_NONE, FD_PIPE } type; +  int count; // reference count +  char readable; +  char writeable; +  struct pipe *pipe; +}; + +extern struct fd fds[NFD]; @@ -11,8 +11,8 @@  extern char edata[], end[];  extern int acpu; -extern char _binary_user1_start[]; -extern char _binary_user1_size[]; +extern char _binary_user1_start[], _binary_user1_size[]; +extern char _binary_usertests_start[], _binary_usertests_size[];  char buf[512]; @@ -25,7 +25,7 @@ main()      cprintf("an application processor\n");      release_spinlock(&kernel_lock);      acquire_spinlock(&kernel_lock); -    idtinit(); +    idtinit(); // CPU's idt      lapic_init(cpu());      curproc[cpu()] = &proc[0]; // XXX      swtch(); @@ -70,7 +70,7 @@ main()  #if 1    p = newproc(); -  load_icode(p, _binary_user1_start, (unsigned) _binary_user1_size); +  load_icode(p, _binary_usertests_start, (unsigned) _binary_usertests_size);  #endif  #if 0 @@ -2,3 +2,5 @@  #define PAGE 4096  #define KSTACKSIZE PAGE  #define NCPU 8 +#define NOFILE 16 // file descriptors per process +#define NFD 100 // file descriptors per system @@ -0,0 +1,100 @@ +#include "types.h" +#include "param.h" +#include "x86.h" +#include "mmu.h" +#include "proc.h" +#include "defs.h" +#include "fd.h" + +#define PIPESIZE 512 + +struct pipe { +  int readopen; // read fd is still open +  int writeopen; // write fd is still open +  int writep; // next index to write +  int readp;  // next index to read +  char data[PIPESIZE]; +}; + +int +pipe_alloc(struct fd **fd1, struct fd **fd2) +{ +  *fd1 = *fd2 = 0; +  struct pipe *p = 0; + +  if((*fd1 = fd_alloc()) == 0) +    goto oops; +  if((*fd2 = fd_alloc()) == 0) +    goto oops; +  if((p = (struct pipe *) kalloc(PAGE)) == 0) +    goto oops; +  (*fd1)->type = FD_PIPE; +  (*fd1)->readable = 1; +  (*fd1)->writeable = 0; +  (*fd1)->pipe = p; +  (*fd2)->type = FD_PIPE; +  (*fd2)->readable = 0; +  (*fd2)->writeable = 1; +  (*fd2)->pipe = p; +  return 0; + oops: +  if(p) +    kfree((char *) p, PAGE); +  if(*fd1){ +    (*fd1)->type = FD_NONE; +    fd_close(*fd1); +  } +  if(*fd2){ +    (*fd2)->type = FD_NONE; +    fd_close(*fd2); +  } +  return -1; +} + +void +pipe_close(struct pipe *p, int writeable) +{ +  if(writeable) +    p->writeopen = 0; +  else +    p->readopen = 0; +  if(p->readopen == 0 && p->writeopen == 0) +    kfree((char *) p, PAGE); +} + +int +pipe_write(struct pipe *p, char *addr, int n) +{ +  int i; + +  for(i = 0; i < n; i++){ +    while(((p->writep + 1) % PIPESIZE) == p->readp){ +      if(p->readopen == 0) +        return -1; +      sleep(&p->writep); +    } +    p->data[p->writep] = addr[i]; +    p->writep = (p->writep + 1) % PIPESIZE; +  } +  return i; +} + +int +pipe_read(struct pipe *p, char *addr, int n) +{ +  int i; + +  while(p->readp == p->writep){ +    if(p->writeopen == 0) +      return 0; +    sleep(&p->readp); +  } + +  for(i = 0; i < n; i++){ +    if(p->readp == p->writep) +      break; +    addr[i] = p->data[p->readp]; +    p->readp = (p->readp + 1) % PIPESIZE; +  } +  return i; +} @@ -2,6 +2,7 @@  #include "mmu.h"  #include "x86.h"  #include "param.h" +#include "fd.h"  #include "proc.h"  #include "defs.h" @@ -49,6 +50,7 @@ newproc()    struct proc *np;    struct proc *op = curproc[cpu()];    unsigned *sp; +  int fd;    for(np = &proc[1]; np < &proc[NPROC]; np++)      if(np->state == UNUSED) @@ -80,6 +82,13 @@ newproc()    np->esp = (unsigned) sp;    np->ebp = (unsigned) sp; +  // copy file descriptors +  for(fd = 0; fd < NOFILE; fd++){ +    np->fds[fd] = op->fds[fd]; +    if(np->fds[fd]) +      np->fds[fd]->count += 1; +  } +    np->state = RUNNABLE;    cprintf("newproc %x\n", np); @@ -24,6 +24,7 @@ struct proc{    int pid;    int ppid;    void *chan; // sleep +  struct fd *fds[NOFILE];    struct Taskstate ts;  // only to give cpu address of kernel stack    struct Segdesc gdt[NSEGS]; @@ -43,6 +43,88 @@ fetcharg(int argno, int *ip)  }  int +putint(struct proc *p, unsigned addr, int ip) +{ +  if(addr > p->sz - 4) +    return 0; +  memcpy(p->mem + addr, &ip, 4); +  return 1; +} + +int +sys_pipe() +{ +  struct fd *rfd = 0, *wfd = 0; +  int f1 = -1, f2 = -1; +  struct proc *p = curproc[cpu()]; +  unsigned fdp; + +  if(pipe_alloc(&rfd, &wfd) < 0) +    goto oops; +  if((f1 = fd_ualloc()) < 0) +    goto oops; +  p->fds[f1] = rfd; +  if((f2 = fd_ualloc()) < 0) +    goto oops; +  p->fds[f2] = wfd; +  if(fetcharg(0, &fdp) < 0) +    goto oops; +  if(putint(p, fdp, f1) < 0) +    goto oops; +  if(putint(p, fdp+4, f2) < 0) +    goto oops; +  return 0; + + oops: +  cprintf("sys_pipe failed\n"); +  if(rfd) +    fd_close(rfd); +  if(wfd) +    fd_close(wfd); +  if(f1 >= 0) +    p->fds[f1] = 0; +  if(f2 >= 0) +    p->fds[f2] = 0; +  return -1; +} + +int +sys_write() +{ +  int fd, n; +  unsigned addr; +  struct proc *p = curproc[cpu()]; + +  if(fetcharg(0, &fd) < 0 || fetcharg(1, &addr) < 0 || fetcharg(2, &n) < 0) +    return -1; +  if(fd < 0 || fd >= NOFILE) +    return -1; +  if(p->fds[fd] == 0) +    return -1; +  if(addr + n > p->sz) +    return -1; +  return fd_write(p->fds[fd], p->mem + addr, n); +} + +int +sys_read() +{ +  int fd, n; +  unsigned addr; +  struct proc *p = curproc[cpu()]; + +  if(fetcharg(0, &fd) < 0 || fetcharg(1, &addr) < 0 || fetcharg(2, &n) < 0) +    return -1; +  if(fd < 0 || fd >= NOFILE) +    return -1; +  if(p->fds[fd] == 0) +    return -1; +  if(addr + n > p->sz) +    return -1; +  return fd_read(p->fds[fd], p->mem + addr, n); +} + +int  sys_fork()  {    struct proc *np; @@ -122,7 +204,7 @@ syscall()    int num = cp->tf->tf_regs.reg_eax;    int ret = -1; -  cprintf("%x sys %d\n", cp, num); +  //cprintf("%x sys %d\n", cp, num);    switch(num){    case SYS_fork:      ret = sys_fork(); @@ -136,6 +218,15 @@ syscall()    case SYS_cons_putc:      ret = sys_cons_putc();      break; +  case SYS_pipe: +    ret = sys_pipe(); +    break; +  case SYS_write: +    ret = sys_write(); +    break; +  case SYS_read: +    ret = sys_read(); +    break;    default:      cprintf("unknown sys call %d\n", num);      // XXX fault @@ -2,3 +2,6 @@  #define SYS_exit 2  #define SYS_wait 3  #define SYS_cons_putc 4 +#define SYS_pipe 5 +#define SYS_write 6 +#define SYS_read 7 @@ -37,14 +37,14 @@ trap(struct Trapframe *tf)    acquire_spinlock(&kernel_lock); // released in trapret in trapasm.S -  cprintf("trap %d eip %x:%x\n", tf->tf_trapno, tf->tf_cs, tf->tf_eip); -    if(v == T_SYSCALL){      curproc[cpu()]->tf = tf;      syscall();      return;    } +  cprintf("trap %d eip %x:%x\n", tf->tf_trapno, tf->tf_cs, tf->tf_eip); +    if(v == 32){      // probably clock      return; @@ -0,0 +1,44 @@ +int +fork() +{ +  asm("mov $1, %eax"); +  asm("int $48"); +} + +void +cons_putc(int c) +{ +  asm("mov $4, %eax"); +  asm("int $48"); +} + +int +puts(char *s) +{ +  int i; + +  for(i = 0; s[i]; i++) +    cons_putc(s[i]); +  return i; +} + +int +pipe(int fds[]) +{ +  asm("mov $5, %eax"); +  asm("int $48"); +} + +int +read(int fd, char *buf, int n) +{ +  asm("mov $7, %eax"); +  asm("int $48"); +} + +int +write(int fd, char *buf, int n) +{ +  asm("mov $6, %eax"); +  asm("int $48"); +} @@ -1,35 +1,19 @@ -int -fork() -{ -  asm("mov $1, %eax"); -  asm("int $48"); -} - -void -cons_putc(int c) -{ -  asm("mov $4, %eax"); -  asm("int $48"); -} - -int -puts(char *s) -{ -  int i; - -  for(i = 0; s[i]; i++) -    cons_putc(s[i]); -  return i; -} +char buf[32];  main()  { -  int pid; +  int pid, fds[2], n; + +  pipe(fds);    pid = fork(); -  if(pid == 0){ -    cons_putc('C'); +  if(pid > 0){ +    write(fds[1], "xyz", 4); +    puts("w");    } else { -    cons_putc('P'); +    n = read(fds[0], buf, sizeof(buf)); +    puts("r: "); +    puts(buf); +    puts("\n");    }    while(1)      ; diff --git a/usertests.c b/usertests.c new file mode 100644 index 0000000..62eefda --- /dev/null +++ b/usertests.c @@ -0,0 +1,30 @@ +// simple fork and pipe read/write + +char buf[32]; + +void +pipe1() +{ +  int fds[2], pid; + +  pipe(fds); +  pid = pipe(); +  if(pid == 0){ +    write(fds[1], "xyz", 4); +  } else { +    read(fds[0], buf, sizeof(buf)); +    if(buf[0] != 'x' || buf[1] != 'y'){ +      puts("pipe1 oops\n"); +      return; +    } +  } +  puts("pipe1 ok\n"); +} + +main() +{ +  pipe1(); + +  while(1) +    ; +}  | 
