00001 #include "types.h"
00002 #include "defs.h"
00003 #include "param.h"
00004 #include "mmu.h"
00005 #include "proc.h"
00006 #include "fs.h"
00007 #include "file.h"
00008 #include "spinlock.h"
00009
00010 #define PIPESIZE 512
00011
00012 struct pipe {
00013 struct spinlock lock;
00014 char data[PIPESIZE];
00015 uint nread;
00016 uint nwrite;
00017 int readopen;
00018 int writeopen;
00019 };
00020
00021 int
00022 pipealloc(struct file **f0, struct file **f1)
00023 {
00024 struct pipe *p;
00025
00026 p = 0;
00027 *f0 = *f1 = 0;
00028 if((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0)
00029 goto bad;
00030 if((p = (struct pipe*)kalloc(PAGE)) == 0)
00031 goto bad;
00032 p->readopen = 1;
00033 p->writeopen = 1;
00034 p->nwrite = 0;
00035 p->nread = 0;
00036 initlock(&p->lock, "pipe");
00037 (*f0)->type = FD_PIPE;
00038 (*f0)->readable = 1;
00039 (*f0)->writable = 0;
00040 (*f0)->pipe = p;
00041 (*f1)->type = FD_PIPE;
00042 (*f1)->readable = 0;
00043 (*f1)->writable = 1;
00044 (*f1)->pipe = p;
00045 return 0;
00046
00047 bad:
00048 if(p)
00049 kfree((char*)p, PAGE);
00050 if(*f0)
00051 fileclose(*f0);
00052 if(*f1)
00053 fileclose(*f1);
00054 return -1;
00055 }
00056
00057 void
00058 pipeclose(struct pipe *p, int writable)
00059 {
00060 acquire(&p->lock);
00061 if(writable){
00062 p->writeopen = 0;
00063 wakeup(&p->nread);
00064 } else {
00065 p->readopen = 0;
00066 wakeup(&p->nwrite);
00067 }
00068 if(p->readopen == 0 && p->writeopen == 0) {
00069 release(&p->lock);
00070 kfree((char*)p, PAGE);
00071 } else
00072 release(&p->lock);
00073 }
00074
00075 int
00076 pipewrite(struct pipe *p, char *addr, int n)
00077 {
00078 int i;
00079
00080 acquire(&p->lock);
00081 for(i = 0; i < n; i++){
00082 while(p->nwrite == p->nread + PIPESIZE) {
00083 if(p->readopen == 0 || proc->killed){
00084 release(&p->lock);
00085 return -1;
00086 }
00087 wakeup(&p->nread);
00088 sleep(&p->nwrite, &p->lock);
00089 }
00090 p->data[p->nwrite++ % PIPESIZE] = addr[i];
00091 }
00092 wakeup(&p->nread);
00093 release(&p->lock);
00094 return n;
00095 }
00096
00097 int
00098 piperead(struct pipe *p, char *addr, int n)
00099 {
00100 int i;
00101
00102 acquire(&p->lock);
00103 while(p->nread == p->nwrite && p->writeopen){
00104 if(proc->killed){
00105 release(&p->lock);
00106 return -1;
00107 }
00108 sleep(&p->nread, &p->lock);
00109 }
00110 for(i = 0; i < n; i++){
00111 if(p->nread == p->nwrite)
00112 break;
00113 addr[i] = p->data[p->nread++ % PIPESIZE];
00114 }
00115 wakeup(&p->nwrite);
00116 release(&p->lock);
00117 return i;
00118 }