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