add linux_emul base, reorganize docs
[openbsd_emul.git] / linux_emul_base / poll.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 void pollwait(Ufile *f, Uwaitq *q, void *t)
9 {
10 Uwait *w, **p;
11
12 if(f == nil || t == nil || q == nil)
13 return;
14
15 p = t;
16 w = addwaitq(q);
17 w->file = getfile(f);
18 w->next = *p;
19 *p = w;
20 }
21
22 static void
23 clearpoll(Uwait **p)
24 {
25 Uwait *w;
26
27 while(w = *p){
28 *p = w->next;
29 delwaitq(w);
30 }
31 }
32
33 struct linux_pollfd
34 {
35 int fd;
36 short events;
37 short revents;
38 };
39
40 int sys_poll(void *p, int nfd, long timeout)
41 {
42 int i, e, err;
43 Uwait *tab;
44 Ufile *file;
45 vlong now, t;
46 struct linux_pollfd *fds = p;
47
48 trace("sys_poll(%p, %d, %ld)", p, nfd, timeout);
49
50 if(nfd < 0)
51 return -EINVAL;
52
53 t = 0;
54 wakeme(1);
55 if(timeout > 0){
56 now = nsec();
57 if(current->restart->syscall){
58 t = current->restart->poll.timeout;
59 } else {
60 t = now + timeout*1000000LL;
61 }
62 if(now < t){
63 current->timeout = t;
64 setalarm(t);
65 }
66 }
67
68 tab = nil;
69 for(;;){
70 clearpoll(&tab);
71
72 err = 0;
73 for(i=0; i<nfd; i++){
74 e = 0;
75 if(fds[i].fd >= 0){
76 e = POLLNVAL;
77 if(file = fdgetfile(fds[i].fd)){
78 if(devtab[file->dev]->poll == nil){
79 e = POLLIN|POLLOUT;
80 } else {
81 e = devtab[file->dev]->poll(file, (err == 0) ? &tab : nil);
82 }
83 putfile(file);
84 e &= fds[i].events | POLLERR | POLLHUP;
85 }
86 }
87 if(fds[i].revents = e){
88 trace("sys_poll(): fd %d is ready with %x", fds[i].fd, fds[i].revents);
89 err++;
90 }
91 }
92 if(err > 0)
93 break;
94 if(timeout >= 0 && current->timeout == 0){
95 trace("sys_poll(): timeout");
96 break;
97 }
98 if((err = sleepproc(nil, 1)) < 0){
99 trace("sys_poll(): interrupted");
100 current->restart->poll.timeout = t;
101 break;
102 }
103 }
104 clearpoll(&tab);
105 wakeme(0);
106
107 if(timeout > 0)
108 current->timeout = 0;
109
110 return err;
111 }
112
113 int sys_select(int nfd, ulong *rfd, ulong *wfd, ulong *efd, void *ptv)
114 {
115 int i, p, e, w, nwrd, nbits, fd, err;
116 ulong m;
117 Uwait *tab;
118 Ufile *file;
119 vlong now, t;
120 struct linux_timeval *tv = ptv;
121 struct {
122 int fd;
123 int ret;
124 } *ardy, astk[16];
125
126 trace("sys_select(%d, %p, %p, %p, %p)", nfd, rfd, wfd, efd, ptv);
127
128 if(nfd < 0)
129 return -EINVAL;
130
131 if(tv != nil)
132 if(tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000)
133 return -EINVAL;
134
135 nwrd = (nfd + (8 * sizeof(m))-1) / (8 * sizeof(m));
136
137 nbits = 0;
138 for(w=0; w<nwrd; w++)
139 for(m=1; m; m<<=1)
140 if((rfd && rfd[w] & m) || (wfd && wfd[w] & m) || (efd && efd[w] & m))
141 nbits++;
142
143 if(nbits > nelem(astk)){
144 ardy = kmalloc(nbits * sizeof(ardy[0]));
145 } else {
146 ardy = astk;
147 }
148
149 t = 0;
150 wakeme(1);
151 if(tv != nil){
152 now = nsec();
153 if(current->restart->syscall){
154 t = current->restart->select.timeout;
155 } else {
156 t = now + tv->tv_sec*1000000000LL + tv->tv_usec*1000;
157 }
158 if(now < t){
159 current->timeout = t;
160 setalarm(t);
161 }
162 }
163
164 tab = nil;
165 for(;;){
166 clearpoll(&tab);
167
168 fd = 0;
169 err = 0;
170 for(w=0; w<nwrd; w++){
171 for(m=1; m; m<<=1, fd++){
172 p = 0;
173 if(rfd && rfd[w] & m)
174 p |= POLLIN;
175 if(wfd && wfd[w] & m)
176 p |= POLLOUT;
177 if(efd && efd[w] & m)
178 p |= POLLERR;
179 if(!p || ((file = fdgetfile(fd)) == nil))
180 continue;
181 if(devtab[file->dev]->poll == nil){
182 e = POLLIN|POLLOUT;
183 } else {
184 e = devtab[file->dev]->poll(file, (err == 0) ? &tab : nil);
185 }
186 putfile(file);
187 if(e &= p) {
188 ardy[err].fd = fd;
189 ardy[err].ret = e;
190 if(++err == nbits)
191 break;
192 }
193 }
194 }
195 if(err > 0)
196 break;
197 if(tv != nil && current->timeout == 0){
198 trace("sys_select(): timeout");
199 break;
200 }
201 if((err = sleepproc(nil, 1)) < 0){
202 trace("sys_select(): interrupted");
203 current->restart->select.timeout = t;
204 break;
205 }
206 }
207 clearpoll(&tab);
208 wakeme(0);
209
210 if(tv != nil){
211 current->timeout = 0;
212 t -= nsec();
213 if(t < 0)
214 t = 0;
215 tv->tv_sec = (long)(t/1000000000LL);
216 tv->tv_usec = (long)((t%1000000000LL)/1000);
217 }
218
219 if(err >= 0){
220 if(rfd) memset(rfd, 0, nwrd*sizeof(m));
221 if(wfd) memset(wfd, 0, nwrd*sizeof(m));
222 if(efd) memset(efd, 0, nwrd*sizeof(m));
223
224 nbits = 0;
225 for(i=0; i<err; i++){
226 e = ardy[i].ret;
227 fd = ardy[i].fd;
228 w = fd / (8 * sizeof(m));
229 m = 1 << (fd % (8 * sizeof(m)));
230 if(rfd && (e & POLLIN)){
231 rfd[w] |= m;
232 nbits++;
233 }
234 if(wfd && (e & POLLOUT)){
235 wfd[w] |= m;
236 nbits++;
237 }
238 if(efd && (e & POLLERR)){
239 efd[w] |= m;
240 nbits++;
241 }
242 }
243 err = nbits;
244 }
245
246 if(ardy != astk)
247 free(ardy);
248
249 return err;
250 }