#include "types.h" #include "defs.h" #include "param.h" #include "mmu.h" #include "proc.h" #include "fs.h" #include "file.h" #include "spinlock.h" #define PIPESIZE 512 #define __ncode __code # struct pipe { struct spinlock lock; char data[PIPESIZE]; uint nread; // number of bytes read uint nwrite; // number of bytes written int readopen; // read fd is still open int writeopen; // write fd is still open }; int pipealloc(struct file **f0, struct file **f1) { struct pipe *p; p = 0; *f0 = *f1 = 0; if((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0) { goto bad; } if((p = kmalloc (get_order(sizeof(*p)))) == 0) { goto bad; } p->readopen = 1; p->writeopen = 1; p->nwrite = 0; p->nread = 0; initlock(&p->lock, "pipe"); (*f0)->type = FD_PIPE; (*f0)->readable = 1; (*f0)->writable = 0; (*f0)->pipe = p; (*f1)->type = FD_PIPE; (*f1)->readable = 0; (*f1)->writable = 1; (*f1)->pipe = p; return 0; //PAGEBREAK: 20 bad: if(p) { kfree (p, get_order(sizeof*p)); } if(*f0) { fileclose(*f0); } if(*f1) { fileclose(*f1); } return -1; } void pipeclose(struct pipe *p, int writable) { acquire(&p->lock); if(writable){ p->writeopen = 0; wakeup(&p->nread); } else { p->readopen = 0; wakeup(&p->nwrite); } if(p->readopen == 0 && p->writeopen == 0){ release(&p->lock); kfree (p, get_order(sizeof(*p))); } else { release(&p->lock); } } //PAGEBREAK: 40 int pipewrite(struct pipe *p, char *addr, int n) { int i; acquire(&p->lock); for(i = 0; i < n; i++){ while(p->nwrite == p->nread + PIPESIZE){ //DOC: pipewrite-full if(p->readopen == 0 /*|| proc->killed*/){ release(&p->lock); return -1; } wakeup(&p->nread); sleep(&p->nwrite, &p->lock); //DOC: pipewrite-sleep } p->data[p->nwrite++ % PIPESIZE] = addr[i]; } wakeup(&p->nread); //DOC: pipewrite-wakeup1 release(&p->lock); return n; } __ncode cbc_piperead3(){ struct pipe *p = proc->cbc_arg.cbc_console_arg.p; int i = proc->cbc_arg.cbc_console_arg.i; __code(*next)(int ret) = proc->cbc_arg.cbc_console_arg.next; release(&p->lock); goto next(i); } __ncode cbc_piperead2(){ int i = proc->cbc_arg.cbc_console_arg.i; int n = proc->cbc_arg.cbc_console_arg.n; struct pipe *p = proc->cbc_arg.cbc_console_arg.p; char *addr = proc->cbc_arg.cbc_console_arg.addr; if (i < n && !(p->nread == p->nwrite)) { addr[i] = p->data[p->nread++ % PIPESIZE]; i ++; proc->cbc_arg.cbc_console_arg.i = i; proc->cbc_arg.cbc_console_arg.p = p; proc->cbc_arg.cbc_console_arg.addr = addr; goto cbc_piperead2(); } proc->cbc_arg.cbc_console_arg.p = p; goto cbc_wakeup(&p->nwrite, cbc_piperead3); //DOC: piperead-wakeup } __ncode cbc_piperead1(){ struct pipe *p = proc->cbc_arg.cbc_console_arg.p; __code(*next)(int ret) = proc->cbc_arg.cbc_console_arg.next; if (p->nread == p->nwrite && p->writeopen){ if(proc->killed){ release(&p->lock); goto next(-1); } proc->cbc_arg.cbc_console_arg.p = p; goto cbc_sleep(&p->nread, &p->lock, cbc_piperead1); } int i = 0; proc->cbc_arg.cbc_console_arg.i = i; proc->cbc_arg.cbc_console_arg.p = p; goto cbc_piperead2(); } __ncode cbc_piperead(struct pipe *p, char *addr, int n, __code (*next)(int ret)) { acquire(&p->lock); proc->cbc_arg.cbc_console_arg.n = n; proc->cbc_arg.cbc_console_arg.p = p; proc->cbc_arg.cbc_console_arg.addr = addr; proc->cbc_arg.cbc_console_arg.next = next; goto cbc_piperead1(); } int piperead(struct pipe *p, char *addr, int n) { int i; acquire(&p->lock); while(p->nread == p->nwrite && p->writeopen){ //DOC: pipe-empty if(proc->killed){ release(&p->lock); return -1; } sleep(&p->nread, &p->lock); //DOC: piperead-sleep*/ } for(i = 0; i < n; i++){ //DOC: piperead-copy if(p->nread == p->nwrite) { break; } addr[i] = p->data[p->nread++ % PIPESIZE]; } wakeup(&p->nwrite); //DOC: piperead-wakeup release(&p->lock); return i; }