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 |
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 |
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 |
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 |
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 |