kernel/pipe.c

134 lines
1#include "types.h"2#include "riscv.h"3#include "defs.h"4#include "param.h"5#include "spinlock.h"6#include "proc.h"7#include "fs.h"8#include "sleeplock.h"9#include "file.h"1011#define PIPESIZE 5121213struct pipe {14  struct spinlock lock;15  char data[PIPESIZE];16  uint nread;     // number of bytes read17  uint nwrite;    // number of bytes written18  int readopen;   // read fd is still open19  int writeopen;  // write fd is still open20};2122int23pipealloc(struct file **f0, struct file **f1)24{25  struct pipe *pi;2627  pi = 0;28  *f0 = *f1 = 0;29  if((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0)30    goto bad;31  if((pi = (struct pipe*)kalloc()) == 0)32    goto bad;33  pi->readopen = 1;34  pi->writeopen = 1;35  pi->nwrite = 0;36  pi->nread = 0;37  initlock(&pi->lock, "pipe");38  (*f0)->type = FD_PIPE;39  (*f0)->readable = 1;40  (*f0)->writable = 0;41  (*f0)->pipe = pi;42  (*f1)->type = FD_PIPE;43  (*f1)->readable = 0;44  (*f1)->writable = 1;45  (*f1)->pipe = pi;46  return 0;4748 bad:49  if(pi)50    kfree((char*)pi);51  if(*f0)52    fileclose(*f0);53  if(*f1)54    fileclose(*f1);55  return -1;56}5758void59pipeclose(struct pipe *pi, int writable)60{61  acquire(&pi->lock);62  if(writable){63    pi->writeopen = 0;64    wakeup(&pi->nread);65  } else {66    pi->readopen = 0;67    wakeup(&pi->nwrite);68  }69  if(pi->readopen == 0 && pi->writeopen == 0){70    release(&pi->lock);71    kfree((char*)pi);72  } else73    release(&pi->lock);74}7576int77pipewrite(struct pipe *pi, uint64 addr, int n)78{79  int i = 0;80  struct proc *pr = myproc();8182  acquire(&pi->lock);83  while(i < n){84    if(pi->readopen == 0 || killed(pr)){85      release(&pi->lock);86      return -1;87    }88    if(pi->nwrite == pi->nread + PIPESIZE){ //DOC: pipewrite-full89      wakeup(&pi->nread);90      sleep(&pi->nwrite, &pi->lock);91    } else {92      char ch;93      if(copyin(pr->pagetable, &ch, addr + i, 1) == -1)94        break;95      pi->data[pi->nwrite++ % PIPESIZE] = ch;96      i++;97    }98  }99  wakeup(&pi->nread);100  release(&pi->lock);101102  return i;103}104105int106piperead(struct pipe *pi, uint64 addr, int n)107{108  int i;109  struct proc *pr = myproc();110  char ch;111112  acquire(&pi->lock);113  while(pi->nread == pi->nwrite && pi->writeopen){  //DOC: pipe-empty114    if(killed(pr)){115      release(&pi->lock);116      return -1;117    }118    sleep(&pi->nread, &pi->lock); //DOC: piperead-sleep119  }120  for(i = 0; i < n; i++){  //DOC: piperead-copy121    if(pi->nread == pi->nwrite)122      break;123    ch = pi->data[pi->nread % PIPESIZE];124    if(copyout(pr->pagetable, addr + i, &ch, 1) == -1) {125      if(i == 0)126        i = -1;127      break;128    }129    pi->nread++;130  }131  wakeup(&pi->nwrite);  //DOC: piperead-wakeup132  release(&pi->lock);133  return i;134}135