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