xref: /xv6-public/pipe.c (revision abf847a0)
1 #include "types.h"
2 #include "defs.h"
3 #include "param.h"
4 #include "mmu.h"
5 #include "proc.h"
6 #include "fs.h"
7 #include "spinlock.h"
8 #include "sleeplock.h"
9 #include "file.h"
10 
11 #define PIPESIZE 512
12 
13 struct pipe {
14   struct spinlock lock;
15   char data[PIPESIZE];
16   uint nread;     // number of bytes read
17   uint nwrite;    // number of bytes written
18   int readopen;   // read fd is still open
19   int writeopen;  // write fd is still open
20 };
21 
22 int
pipealloc(struct file ** f0,struct file ** f1)23 pipealloc(struct file **f0, struct file **f1)
24 {
25   struct pipe *p;
26 
27   p = 0;
28   *f0 = *f1 = 0;
29   if((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0)
30     goto bad;
31   if((p = (struct pipe*)kalloc()) == 0)
32     goto bad;
33   p->readopen = 1;
34   p->writeopen = 1;
35   p->nwrite = 0;
36   p->nread = 0;
37   initlock(&p->lock, "pipe");
38   (*f0)->type = FD_PIPE;
39   (*f0)->readable = 1;
40   (*f0)->writable = 0;
41   (*f0)->pipe = p;
42   (*f1)->type = FD_PIPE;
43   (*f1)->readable = 0;
44   (*f1)->writable = 1;
45   (*f1)->pipe = p;
46   return 0;
47 
48 //PAGEBREAK: 20
49  bad:
50   if(p)
51     kfree((char*)p);
52   if(*f0)
53     fileclose(*f0);
54   if(*f1)
55     fileclose(*f1);
56   return -1;
57 }
58 
59 void
pipeclose(struct pipe * p,int writable)60 pipeclose(struct pipe *p, int writable)
61 {
62   acquire(&p->lock);
63   if(writable){
64     p->writeopen = 0;
65     wakeup(&p->nread);
66   } else {
67     p->readopen = 0;
68     wakeup(&p->nwrite);
69   }
70   if(p->readopen == 0 && p->writeopen == 0){
71     release(&p->lock);
72     kfree((char*)p);
73   } else
74     release(&p->lock);
75 }
76 
77 //PAGEBREAK: 40
78 int
pipewrite(struct pipe * p,char * addr,int n)79 pipewrite(struct pipe *p, char *addr, int n)
80 {
81   int i;
82 
83   acquire(&p->lock);
84   for(i = 0; i < n; i++){
85     while(p->nwrite == p->nread + PIPESIZE){  //DOC: pipewrite-full
86       if(p->readopen == 0 || myproc()->killed){
87         release(&p->lock);
88         return -1;
89       }
90       wakeup(&p->nread);
91       sleep(&p->nwrite, &p->lock);  //DOC: pipewrite-sleep
92     }
93     p->data[p->nwrite++ % PIPESIZE] = addr[i];
94   }
95   wakeup(&p->nread);  //DOC: pipewrite-wakeup1
96   release(&p->lock);
97   return n;
98 }
99 
100 int
piperead(struct pipe * p,char * addr,int n)101 piperead(struct pipe *p, char *addr, int n)
102 {
103   int i;
104 
105   acquire(&p->lock);
106   while(p->nread == p->nwrite && p->writeopen){  //DOC: pipe-empty
107     if(myproc()->killed){
108       release(&p->lock);
109       return -1;
110     }
111     sleep(&p->nread, &p->lock); //DOC: piperead-sleep
112   }
113   for(i = 0; i < n; i++){  //DOC: piperead-copy
114     if(p->nread == p->nwrite)
115       break;
116     addr[i] = p->data[p->nread++ % PIPESIZE];
117   }
118   wakeup(&p->nwrite);  //DOC: piperead-wakeup
119   release(&p->lock);
120   return i;
121 }
122