add linux_emul base, reorganize docs
[openbsd_emul.git] / linux_emul_base / bufproc.c
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 }