cae36a52 |
1 | #include <u.h> |
2 | #include <libc.h> |
3 | #include <ureg.h> |
4 | #include "dat.h" |
5 | #include "fns.h" |
6 | #include "linux.h" |
7 | |
8 | typedef struct Bufproc Bufproc; |
9 | typedef struct Bufq Bufq; |
10 | |
11 | struct Bufq |
12 | { |
13 | Bufq *next; |
14 | |
15 | uchar *start; |
16 | uchar *end; |
17 | |
18 | uchar data[8*1024]; |
19 | }; |
20 | |
21 | struct Bufproc |
22 | { |
23 | Ref; |
24 | QLock; |
25 | |
26 | int fd; |
27 | int error; |
28 | int notefd; |
29 | |
30 | Bufq *qf; |
31 | Bufq *qh; |
32 | Bufq **qt; |
33 | |
34 | int wr; |
35 | Uwaitq wq; |
36 | }; |
37 | |
38 | static int |
39 | queuesize(Bufq *q) |
40 | { |
41 | int n; |
42 | |
43 | n = 0; |
44 | while(q){ |
45 | n += (q->end - q->start); |
46 | q = q->next; |
47 | } |
48 | return n; |
49 | } |
50 | |
51 | void |
52 | freebufproc(void *bp) |
53 | { |
54 | Bufproc *b = bp; |
55 | Bufq *q; |
56 | |
57 | if(b == nil) |
58 | return; |
59 | qlock(b); |
60 | b->fd = -1; |
61 | if(decref(b)){ |
62 | if(b->wr){ |
63 | b->wr = 0; |
64 | while(rendezvous(&b->wr, 0) == (void*)~0) |
65 | ; |
66 | } else { |
67 | write(b->notefd, "interrupt", 9); |
68 | } |
69 | qunlock(b); |
70 | return; |
71 | } |
72 | qunlock(b); |
73 | |
74 | *b->qt = b->qf; |
75 | while(q = b->qh){ |
76 | b->qh = q->next; |
77 | free(q); |
78 | } |
79 | close(b->notefd); |
80 | free(b); |
81 | } |
82 | |
83 | static void |
84 | bufproc(void *aux) |
85 | { |
86 | Bufproc *b = aux; |
87 | Bufq *q; |
88 | int ret; |
89 | int fd; |
90 | |
91 | setprocname("bufproc()"); |
92 | |
93 | q = nil; |
94 | qlock(b); |
95 | for(;;){ |
96 | while((b->fd >= 0) && (queuesize(b->qh) >= 64*1024)){ |
97 | b->wr = 1; |
98 | qunlock(b); |
99 | while(rendezvous(&b->wr, 0) == (void*)~0) |
100 | ; |
101 | qlock(b); |
102 | } |
103 | if((fd = b->fd) < 0) |
104 | break; |
105 | if((q == nil) && (q = b->qf)) |
106 | b->qf = q->next; |
107 | qunlock(b); |
108 | |
109 | if(q == nil) |
110 | q = kmalloc(sizeof(*q)); |
111 | q->next = nil; |
112 | q->end = q->start = &q->data[0]; |
113 | ret = read(fd, q->start, sizeof(q->data)); |
114 | |
115 | qlock(b); |
116 | if(ret < 0){ |
117 | ret = mkerror(); |
118 | if(ret == -EINTR || ret == -ERESTART) |
119 | continue; |
120 | b->error = ret; |
121 | b->fd = -1; |
122 | break; |
123 | } |
124 | q->end = q->start + ret; |
125 | *b->qt = q; |
126 | b->qt = &q->next; |
127 | q = nil; |
128 | wakeq(&b->wq, MAXPROC); |
129 | } |
130 | if(q){ |
131 | q->next = b->qf; |
132 | b->qf = q; |
133 | } |
134 | wakeq(&b->wq, MAXPROC); |
135 | qunlock(b); |
136 | freebufproc(b); |
137 | } |
138 | |
139 | void* |
140 | newbufproc(int fd) |
141 | { |
142 | char buf[80]; |
143 | Bufproc *b; |
144 | int pid; |
145 | |
146 | b = kmallocz(sizeof(*b), 1); |
147 | b->ref = 2; |
148 | b->fd = fd; |
149 | b->qt = &b->qh; |
150 | if((pid = procfork(bufproc, b, 0)) < 0) |
151 | panic("unable to fork bufproc: %r"); |
152 | snprint(buf, sizeof(buf), "/proc/%d/note", pid); |
153 | b->notefd = open(buf, OWRITE); |
154 | |
155 | return b; |
156 | } |
157 | |
158 | int readbufproc(void *bp, void *data, int len, int peek, int noblock) |
159 | { |
160 | Bufproc *b = bp; |
161 | uchar *p; |
162 | Bufq *q; |
163 | int ret; |
164 | |
165 | qlock(b); |
166 | while((q = b->qh) == nil){ |
167 | if(noblock){ |
168 | ret = -EAGAIN; |
169 | goto out; |
170 | } |
171 | if(peek){ |
172 | ret = 0; |
173 | goto out; |
174 | } |
175 | if(b->fd < 0){ |
176 | if((ret = b->error) == 0) |
177 | ret = -EIO; |
178 | goto out; |
179 | } |
180 | if((ret = sleepq(&b->wq, b, 1)) < 0){ |
181 | qunlock(b); |
182 | return ret; |
183 | } |
184 | } |
185 | |
186 | p = data; |
187 | ret = 0; |
188 | while(q != nil){ |
189 | int n; |
190 | |
191 | n = q->end - q->start; |
192 | if(n == 0) |
193 | break; |
194 | if(n > len - ret) |
195 | n = len - ret; |
196 | memmove(p, q->start, n); |
197 | p += n; |
198 | ret += n; |
199 | if(q->start+n >= q->end){ |
200 | if(!peek){ |
201 | Bufq *t; |
202 | |
203 | t = q->next; |
204 | if((b->qh = q->next) == nil) |
205 | b->qt = &b->qh; |
206 | q->next = b->qf; |
207 | b->qf = q; |
208 | q = t; |
209 | } else { |
210 | q = q->next; |
211 | } |
212 | } else { |
213 | if(!peek) |
214 | q->start += n; |
215 | break; |
216 | } |
217 | } |
218 | |
219 | if(b->wr && !peek){ |
220 | b->wr = 0; |
221 | while(rendezvous(&b->wr, 0) == (void*)~0) |
222 | ; |
223 | qunlock(b); |
224 | |
225 | return ret; |
226 | } |
227 | out: |
228 | qunlock(b); |
229 | |
230 | return ret; |
231 | } |
232 | |
233 | int pollbufproc(void *bp, Ufile *file, void *tab) |
234 | { |
235 | Bufproc *b = bp; |
236 | int ret; |
237 | |
238 | ret = 0; |
239 | |
240 | qlock(b); |
241 | pollwait(file, &b->wq, tab); |
242 | if(b->fd >= 0){ |
243 | ret |= POLLOUT; |
244 | } else if(b->error < 0) |
245 | ret |= POLLERR; |
246 | if(b->qh) |
247 | ret |= POLLIN; |
248 | qunlock(b); |
249 | |
250 | return ret; |
251 | } |
252 | |
253 | int nreadablebufproc(void *bp) |
254 | { |
255 | Bufproc *b = bp; |
256 | int ret; |
257 | |
258 | qlock(b); |
259 | ret = queuesize(b->qh); |
260 | qunlock(b); |
261 | |
262 | return ret; |
263 | } |