]>
Commit | Line | Data |
---|---|---|
0d3eb016 | 1 | /* Guts of both `select' and `poll' for Hurd. |
dff8da6b | 2 | Copyright (C) 1991-2024 Free Software Foundation, Inc. |
0d3eb016 RM |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
0d3eb016 RM |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
0d3eb016 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
0d3eb016 | 18 | |
c3010778 | 19 | #include <sys/time.h> |
0d3eb016 RM |
20 | #include <sys/types.h> |
21 | #include <sys/poll.h> | |
22 | #include <hurd.h> | |
23 | #include <hurd/fd.h> | |
c3010778 | 24 | #include <hurd/io_request.h> |
84b4a81a | 25 | #include <mach_rpc.h> |
0d3eb016 RM |
26 | #include <stdlib.h> |
27 | #include <string.h> | |
28 | #include <assert.h> | |
29 | #include <stdint.h> | |
c3010778 | 30 | #include <limits.h> |
48123656 | 31 | #include <time.h> |
f5123211 | 32 | #include <sysdep-cancel.h> |
0d3eb016 RM |
33 | |
34 | /* All user select types. */ | |
35 | #define SELECT_ALL (SELECT_READ | SELECT_WRITE | SELECT_URG) | |
36 | ||
37 | /* Used to record that a particular select rpc returned. Must be distinct | |
38 | from SELECT_ALL (which better not have the high bit set). */ | |
39 | #define SELECT_RETURNED ((SELECT_ALL << 1) & ~SELECT_ALL) | |
d76d187c | 40 | #define SELECT_ERROR (SELECT_RETURNED << 1) |
0d3eb016 RM |
41 | |
42 | /* Check the first NFDS descriptors either in POLLFDS (if nonnnull) or in | |
43 | each of READFDS, WRITEFDS, EXCEPTFDS that is nonnull. If TIMEOUT is not | |
44 | NULL, time out after waiting the interval specified therein. Returns | |
45 | the number of ready descriptors, or -1 for errors. */ | |
46 | int | |
47 | _hurd_select (int nfds, | |
48 | struct pollfd *pollfds, | |
49 | fd_set *readfds, fd_set *writefds, fd_set *exceptfds, | |
50 | const struct timespec *timeout, const sigset_t *sigmask) | |
51 | { | |
52 | int i; | |
f9011787 | 53 | mach_port_t portset, sigport; |
c3010778 | 54 | int got, ready; |
0d3eb016 RM |
55 | error_t err; |
56 | fd_set rfds, wfds, xfds; | |
57 | int firstfd, lastfd; | |
c3010778 RB |
58 | mach_msg_id_t reply_msgid; |
59 | mach_msg_timeout_t to; | |
60 | struct timespec ts; | |
0d3eb016 RM |
61 | struct |
62 | { | |
63 | struct hurd_userlink ulink; | |
64 | struct hurd_fd *cell; | |
65 | mach_port_t io_port; | |
66 | int type; | |
67 | mach_port_t reply_port; | |
d76d187c | 68 | int error; |
0d3eb016 RM |
69 | } d[nfds]; |
70 | sigset_t oset; | |
df183287 | 71 | struct hurd_sigstate *ss = NULL; |
0d3eb016 | 72 | |
d5131d3c | 73 | if (nfds < 0 || (pollfds == NULL && nfds > FD_SETSIZE)) |
9ec31e57 | 74 | return __hurd_fail (EINVAL); |
c6474b07 | 75 | |
c3010778 RB |
76 | #define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */ |
77 | #define IO_SELECT_TIMEOUT_REPLY_MSGID (21031 + 100) /* XXX */ | |
78 | ||
79 | if (timeout == NULL) | |
80 | reply_msgid = IO_SELECT_REPLY_MSGID; | |
81 | else | |
c6474b07 | 82 | { |
a673c07a | 83 | struct timespec now; |
c3010778 | 84 | |
48123656 | 85 | if (timeout->tv_sec < 0 || ! valid_nanoseconds (timeout->tv_nsec)) |
9ec31e57 | 86 | return __hurd_fail (EINVAL); |
c6474b07 | 87 | |
a673c07a | 88 | err = __clock_gettime (CLOCK_REALTIME, &now); |
c3010778 RB |
89 | if (err) |
90 | return -1; | |
91 | ||
92 | ts.tv_sec = now.tv_sec + timeout->tv_sec; | |
a673c07a | 93 | ts.tv_nsec = now.tv_nsec + timeout->tv_nsec; |
c3010778 RB |
94 | |
95 | if (ts.tv_nsec >= 1000000000) | |
96 | { | |
97 | ts.tv_sec++; | |
98 | ts.tv_nsec -= 1000000000; | |
99 | } | |
100 | ||
101 | if (ts.tv_sec < 0) | |
102 | ts.tv_sec = LONG_MAX; /* XXX */ | |
103 | ||
104 | reply_msgid = IO_SELECT_TIMEOUT_REPLY_MSGID; | |
c6474b07 PT |
105 | } |
106 | ||
f9011787 ST |
107 | if (sigmask) |
108 | { | |
109 | /* Add a port to the portset for the case when we get the signal even | |
110 | before calling __mach_msg. */ | |
111 | ||
112 | sigport = __mach_reply_port (); | |
113 | ||
114 | ss = _hurd_self_sigstate (); | |
115 | _hurd_sigstate_lock (ss); | |
116 | /* And tell the signal thread to message us when a signal arrives. */ | |
117 | ss->suspended = sigport; | |
118 | _hurd_sigstate_unlock (ss); | |
119 | ||
120 | if (__sigprocmask (SIG_SETMASK, sigmask, &oset)) | |
121 | { | |
122 | _hurd_sigstate_lock (ss); | |
123 | ss->suspended = MACH_PORT_NULL; | |
124 | _hurd_sigstate_unlock (ss); | |
125 | __mach_port_destroy (__mach_task_self (), sigport); | |
126 | return -1; | |
127 | } | |
128 | } | |
129 | else | |
130 | sigport = MACH_PORT_NULL; | |
0d3eb016 RM |
131 | |
132 | if (pollfds) | |
133 | { | |
d76d187c | 134 | int error = 0; |
0d3eb016 RM |
135 | /* Collect interesting descriptors from the user's `pollfd' array. |
136 | We do a first pass that reads the user's array before taking | |
137 | any locks. The second pass then only touches our own stack, | |
138 | and gets the port references. */ | |
139 | ||
140 | for (i = 0; i < nfds; ++i) | |
141 | if (pollfds[i].fd >= 0) | |
142 | { | |
143 | int type = 0; | |
144 | if (pollfds[i].events & POLLIN) | |
145 | type |= SELECT_READ; | |
146 | if (pollfds[i].events & POLLOUT) | |
147 | type |= SELECT_WRITE; | |
148 | if (pollfds[i].events & POLLPRI) | |
149 | type |= SELECT_URG; | |
150 | ||
151 | d[i].io_port = pollfds[i].fd; | |
152 | d[i].type = type; | |
153 | } | |
154 | else | |
155 | d[i].type = 0; | |
156 | ||
157 | HURD_CRITICAL_BEGIN; | |
158 | __mutex_lock (&_hurd_dtable_lock); | |
159 | ||
160 | for (i = 0; i < nfds; ++i) | |
161 | if (d[i].type != 0) | |
162 | { | |
163 | const int fd = (int) d[i].io_port; | |
164 | ||
165 | if (fd < _hurd_dtablesize) | |
166 | { | |
167 | d[i].cell = _hurd_dtable[fd]; | |
d76d187c ST |
168 | if (d[i].cell != NULL) |
169 | { | |
170 | d[i].io_port = _hurd_port_get (&d[i].cell->port, | |
171 | &d[i].ulink); | |
172 | if (d[i].io_port != MACH_PORT_NULL) | |
173 | continue; | |
174 | } | |
0d3eb016 RM |
175 | } |
176 | ||
d76d187c ST |
177 | /* Bogus descriptor, make it EBADF already. */ |
178 | d[i].error = EBADF; | |
179 | d[i].type = SELECT_ERROR; | |
180 | error = 1; | |
0d3eb016 RM |
181 | } |
182 | ||
183 | __mutex_unlock (&_hurd_dtable_lock); | |
184 | HURD_CRITICAL_END; | |
185 | ||
d76d187c | 186 | if (error) |
0d3eb016 | 187 | { |
d76d187c | 188 | /* Set timeout to 0. */ |
a673c07a | 189 | err = __clock_gettime (CLOCK_REALTIME, &ts); |
d76d187c ST |
190 | if (err) |
191 | { | |
192 | /* Really bad luck. */ | |
193 | err = errno; | |
194 | HURD_CRITICAL_BEGIN; | |
195 | __mutex_lock (&_hurd_dtable_lock); | |
196 | while (i-- > 0) | |
197 | if (d[i].type & ~SELECT_ERROR != 0) | |
198 | _hurd_port_free (&d[i].cell->port, &d[i].ulink, | |
199 | d[i].io_port); | |
200 | __mutex_unlock (&_hurd_dtable_lock); | |
201 | HURD_CRITICAL_END; | |
f9011787 ST |
202 | if (sigmask) |
203 | __sigprocmask (SIG_SETMASK, &oset, NULL); | |
d76d187c ST |
204 | errno = err; |
205 | return -1; | |
206 | } | |
d76d187c | 207 | reply_msgid = IO_SELECT_TIMEOUT_REPLY_MSGID; |
0d3eb016 RM |
208 | } |
209 | ||
210 | lastfd = i - 1; | |
211 | firstfd = i == 0 ? lastfd : 0; | |
212 | } | |
213 | else | |
214 | { | |
215 | /* Collect interested descriptors from the user's fd_set arguments. | |
216 | Use local copies so we can't crash from user bogosity. */ | |
217 | ||
218 | if (readfds == NULL) | |
219 | FD_ZERO (&rfds); | |
220 | else | |
221 | rfds = *readfds; | |
222 | if (writefds == NULL) | |
223 | FD_ZERO (&wfds); | |
224 | else | |
225 | wfds = *writefds; | |
226 | if (exceptfds == NULL) | |
227 | FD_ZERO (&xfds); | |
228 | else | |
229 | xfds = *exceptfds; | |
230 | ||
231 | HURD_CRITICAL_BEGIN; | |
232 | __mutex_lock (&_hurd_dtable_lock); | |
233 | ||
0d3eb016 RM |
234 | /* Collect the ports for interesting FDs. */ |
235 | firstfd = lastfd = -1; | |
236 | for (i = 0; i < nfds; ++i) | |
237 | { | |
238 | int type = 0; | |
239 | if (readfds != NULL && FD_ISSET (i, &rfds)) | |
240 | type |= SELECT_READ; | |
241 | if (writefds != NULL && FD_ISSET (i, &wfds)) | |
242 | type |= SELECT_WRITE; | |
243 | if (exceptfds != NULL && FD_ISSET (i, &xfds)) | |
244 | type |= SELECT_URG; | |
245 | d[i].type = type; | |
246 | if (type) | |
247 | { | |
d76d187c ST |
248 | if (i < _hurd_dtablesize) |
249 | { | |
250 | d[i].cell = _hurd_dtable[i]; | |
251 | if (d[i].cell != NULL) | |
252 | d[i].io_port = _hurd_port_get (&d[i].cell->port, | |
253 | &d[i].ulink); | |
254 | } | |
255 | if (i >= _hurd_dtablesize || d[i].cell == NULL || | |
256 | d[i].io_port == MACH_PORT_NULL) | |
0d3eb016 RM |
257 | { |
258 | /* If one descriptor is bogus, we fail completely. */ | |
259 | while (i-- > 0) | |
c3aba1be RM |
260 | if (d[i].type != 0) |
261 | _hurd_port_free (&d[i].cell->port, &d[i].ulink, | |
262 | d[i].io_port); | |
0d3eb016 RM |
263 | break; |
264 | } | |
265 | lastfd = i; | |
266 | if (firstfd == -1) | |
267 | firstfd = i; | |
268 | } | |
269 | } | |
270 | ||
271 | __mutex_unlock (&_hurd_dtable_lock); | |
272 | HURD_CRITICAL_END; | |
273 | ||
274 | if (i < nfds) | |
275 | { | |
276 | if (sigmask) | |
277 | __sigprocmask (SIG_SETMASK, &oset, NULL); | |
9ec31e57 | 278 | return __hurd_fail (EBADF); |
0d3eb016 | 279 | } |
d76d187c ST |
280 | |
281 | if (nfds > _hurd_dtablesize) | |
282 | nfds = _hurd_dtablesize; | |
0d3eb016 RM |
283 | } |
284 | ||
285 | ||
286 | err = 0; | |
287 | got = 0; | |
288 | ||
289 | /* Send them all io_select request messages. */ | |
290 | ||
291 | if (firstfd == -1) | |
f9011787 ST |
292 | { |
293 | if (sigport == MACH_PORT_NULL) | |
294 | /* But not if there were no ports to deal with at all. | |
295 | We are just a pure timeout. */ | |
296 | portset = __mach_reply_port (); | |
297 | else | |
298 | portset = sigport; | |
299 | } | |
0d3eb016 RM |
300 | else |
301 | { | |
302 | portset = MACH_PORT_NULL; | |
303 | ||
304 | for (i = firstfd; i <= lastfd; ++i) | |
d76d187c ST |
305 | if (!(d[i].type & ~SELECT_ERROR)) |
306 | d[i].reply_port = MACH_PORT_NULL; | |
307 | else | |
0d3eb016 RM |
308 | { |
309 | int type = d[i].type; | |
310 | d[i].reply_port = __mach_reply_port (); | |
c3010778 RB |
311 | if (timeout == NULL) |
312 | err = __io_select_request (d[i].io_port, d[i].reply_port, type); | |
313 | else | |
314 | err = __io_select_timeout_request (d[i].io_port, d[i].reply_port, | |
315 | ts, type); | |
316 | if (!err) | |
0d3eb016 | 317 | { |
f9011787 | 318 | if (firstfd == lastfd && sigport == MACH_PORT_NULL) |
0d3eb016 RM |
319 | /* When there's a single descriptor, we don't need a |
320 | portset, so just pretend we have one, but really | |
321 | use the single reply port. */ | |
322 | portset = d[i].reply_port; | |
323 | else if (got == 0) | |
324 | /* We've got multiple reply ports, so we need a port set to | |
325 | multiplex them. */ | |
326 | { | |
327 | /* We will wait again for a reply later. */ | |
328 | if (portset == MACH_PORT_NULL) | |
329 | /* Create the portset to receive all the replies on. */ | |
330 | err = __mach_port_allocate (__mach_task_self (), | |
331 | MACH_PORT_RIGHT_PORT_SET, | |
332 | &portset); | |
333 | if (! err) | |
334 | /* Put this reply port in the port set. */ | |
335 | __mach_port_move_member (__mach_task_self (), | |
336 | d[i].reply_port, portset); | |
337 | } | |
c3010778 RB |
338 | } |
339 | else | |
340 | { | |
d76d187c ST |
341 | /* No error should happen, but record it for later |
342 | processing. */ | |
343 | d[i].error = err; | |
344 | d[i].type |= SELECT_ERROR; | |
0d3eb016 | 345 | ++got; |
0d3eb016 RM |
346 | } |
347 | _hurd_port_free (&d[i].cell->port, &d[i].ulink, d[i].io_port); | |
348 | } | |
f9011787 ST |
349 | |
350 | if (got == 0 && sigport != MACH_PORT_NULL) | |
351 | { | |
352 | if (portset == MACH_PORT_NULL) | |
353 | /* Create the portset to receive the signal message on. */ | |
354 | __mach_port_allocate (__mach_task_self (), MACH_PORT_RIGHT_PORT_SET, | |
355 | &portset); | |
356 | /* Put the signal reply port in the port set. */ | |
357 | __mach_port_move_member (__mach_task_self (), sigport, portset); | |
358 | } | |
0d3eb016 RM |
359 | } |
360 | ||
c3010778 RB |
361 | /* GOT is the number of replies (or errors), while READY is the number of |
362 | replies with at least one type bit set. */ | |
363 | ready = 0; | |
364 | ||
0d3eb016 RM |
365 | /* Now wait for reply messages. */ |
366 | if (!err && got == 0) | |
367 | { | |
368 | /* Now wait for io_select_reply messages on PORT, | |
369 | timing out as appropriate. */ | |
370 | ||
371 | union | |
372 | { | |
373 | mach_msg_header_t head; | |
f22a77e1 RM |
374 | #ifdef MACH_MSG_TRAILER_MINIMUM_SIZE |
375 | struct | |
376 | { | |
377 | mach_msg_header_t head; | |
378 | NDR_record_t ndr; | |
379 | error_t err; | |
380 | } error; | |
381 | struct | |
382 | { | |
383 | mach_msg_header_t head; | |
384 | NDR_record_t ndr; | |
385 | error_t err; | |
386 | int result; | |
387 | mach_msg_trailer_t trailer; | |
388 | } success; | |
389 | #else | |
0d3eb016 RM |
390 | struct |
391 | { | |
392 | mach_msg_header_t head; | |
84b4a81a | 393 | mach_msg_type_t err_type; |
0d3eb016 RM |
394 | error_t err; |
395 | } error; | |
396 | struct | |
397 | { | |
398 | mach_msg_header_t head; | |
84b4a81a | 399 | mach_msg_type_t err_type; |
0d3eb016 | 400 | error_t err; |
84b4a81a | 401 | mach_msg_type_t result_type; |
0d3eb016 RM |
402 | int result; |
403 | } success; | |
f22a77e1 | 404 | #endif |
0d3eb016 | 405 | } msg; |
c3010778 | 406 | mach_msg_option_t options; |
0d3eb016 | 407 | error_t msgerr; |
c3010778 RB |
408 | |
409 | /* We rely on servers to implement the timeout, but when there are none, | |
410 | do it on the client side. */ | |
411 | if (timeout != NULL && firstfd == -1) | |
412 | { | |
413 | options = MACH_RCV_TIMEOUT; | |
414 | to = timeout->tv_sec * 1000 + (timeout->tv_nsec + 999999) / 1000000; | |
415 | } | |
416 | else | |
417 | { | |
418 | options = 0; | |
419 | to = MACH_MSG_TIMEOUT_NONE; | |
420 | } | |
421 | ||
f5123211 | 422 | int cancel_oldtype = LIBC_CANCEL_ASYNC(); |
0d3eb016 | 423 | while ((msgerr = __mach_msg (&msg.head, |
a9a002fb | 424 | MACH_RCV_MSG | MACH_RCV_INTERRUPT | options, |
0d3eb016 RM |
425 | 0, sizeof msg, portset, to, |
426 | MACH_PORT_NULL)) == MACH_MSG_SUCCESS) | |
427 | { | |
f5123211 ST |
428 | LIBC_CANCEL_RESET (cancel_oldtype); |
429 | ||
0d3eb016 | 430 | /* We got a message. Decode it. */ |
f22a77e1 | 431 | #ifdef MACH_MSG_TYPE_BIT |
84b4a81a FC |
432 | static const mach_msg_type_t inttype = { |
433 | .msgt_name = MACH_MSG_TYPE_INTEGER_T, | |
434 | .msgt_size = sizeof (integer_t) * 8, | |
435 | .msgt_number = 1, | |
436 | .msgt_inline = TRUE, | |
437 | .msgt_longform = FALSE, | |
438 | .msgt_deallocate = FALSE, | |
439 | .msgt_unused = 0 | |
db6b51ad | 440 | }; |
f22a77e1 | 441 | #endif |
f9011787 ST |
442 | |
443 | if (sigport != MACH_PORT_NULL && sigport == msg.head.msgh_local_port) | |
444 | { | |
445 | /* We actually got interrupted by a signal before | |
446 | __mach_msg; poll for further responses and then | |
447 | return quickly. */ | |
448 | err = EINTR; | |
449 | goto poll; | |
450 | } | |
451 | ||
c3010778 | 452 | if (msg.head.msgh_id == reply_msgid |
34a5a146 JM |
453 | && msg.head.msgh_size >= sizeof msg.error |
454 | && !(msg.head.msgh_bits & MACH_MSGH_BITS_COMPLEX) | |
f22a77e1 | 455 | #ifdef MACH_MSG_TYPE_BIT |
84b4a81a | 456 | && !BAD_TYPECHECK (&msg.error.err_type, &inttype) |
f22a77e1 RM |
457 | #endif |
458 | ) | |
0d3eb016 RM |
459 | { |
460 | /* This is a properly formatted message so far. | |
461 | See if it is a success or a failure. */ | |
34a5a146 JM |
462 | if (msg.error.err == EINTR |
463 | && msg.head.msgh_size == sizeof msg.error) | |
0d3eb016 RM |
464 | { |
465 | /* EINTR response; poll for further responses | |
466 | and then return quickly. */ | |
467 | err = EINTR; | |
468 | goto poll; | |
469 | } | |
c3010778 RB |
470 | /* Keep in mind msg.success.result can be 0 if a timeout |
471 | occurred. */ | |
34a5a146 | 472 | if (msg.error.err |
f22a77e1 | 473 | #ifdef MACH_MSG_TYPE_BIT |
84b4a81a | 474 | || BAD_TYPECHECK (&msg.success.result_type, &inttype) |
f22a77e1 | 475 | #endif |
c3010778 | 476 | || msg.head.msgh_size != sizeof msg.success) |
0d3eb016 | 477 | { |
d76d187c ST |
478 | /* Error or bogus reply. */ |
479 | if (!msg.error.err) | |
480 | msg.error.err = EIO; | |
0d3eb016 | 481 | __mach_msg_destroy (&msg.head); |
0d3eb016 RM |
482 | } |
483 | ||
484 | /* Look up the respondent's reply port and record its | |
c6474b07 | 485 | readiness. */ |
0d3eb016 RM |
486 | { |
487 | int had = got; | |
488 | if (firstfd != -1) | |
489 | for (i = firstfd; i <= lastfd; ++i) | |
490 | if (d[i].type | |
491 | && d[i].reply_port == msg.head.msgh_local_port) | |
492 | { | |
d76d187c ST |
493 | if (msg.error.err) |
494 | { | |
495 | d[i].error = msg.error.err; | |
496 | d[i].type = SELECT_ERROR; | |
497 | ++ready; | |
498 | } | |
499 | else | |
500 | { | |
501 | d[i].type &= msg.success.result; | |
502 | if (d[i].type) | |
503 | ++ready; | |
504 | } | |
c3010778 | 505 | |
0d3eb016 RM |
506 | d[i].type |= SELECT_RETURNED; |
507 | ++got; | |
508 | } | |
509 | assert (got > had); | |
510 | } | |
511 | } | |
512 | ||
513 | if (msg.head.msgh_remote_port != MACH_PORT_NULL) | |
514 | __mach_port_deallocate (__mach_task_self (), | |
515 | msg.head.msgh_remote_port); | |
516 | ||
517 | if (got) | |
518 | poll: | |
519 | { | |
520 | /* Poll for another message. */ | |
521 | to = 0; | |
522 | options |= MACH_RCV_TIMEOUT; | |
523 | } | |
524 | } | |
f5123211 | 525 | LIBC_CANCEL_RESET (cancel_oldtype); |
0d3eb016 | 526 | |
a9a002fb ST |
527 | if (msgerr == MACH_RCV_INTERRUPTED) |
528 | /* Interruption on our side (e.g. signal reception). */ | |
529 | err = EINTR; | |
0d3eb016 | 530 | |
c3010778 | 531 | if (ready) |
0d3eb016 RM |
532 | /* At least one descriptor is known to be ready now, so we will |
533 | return success. */ | |
534 | err = 0; | |
535 | } | |
536 | ||
537 | if (firstfd != -1) | |
538 | for (i = firstfd; i <= lastfd; ++i) | |
d76d187c | 539 | if (d[i].reply_port != MACH_PORT_NULL) |
0d3eb016 | 540 | __mach_port_destroy (__mach_task_self (), d[i].reply_port); |
f9011787 ST |
541 | |
542 | if (sigport != MACH_PORT_NULL) | |
543 | { | |
544 | _hurd_sigstate_lock (ss); | |
545 | ss->suspended = MACH_PORT_NULL; | |
546 | _hurd_sigstate_unlock (ss); | |
547 | __mach_port_destroy (__mach_task_self (), sigport); | |
548 | } | |
549 | ||
550 | if ((firstfd == -1 && sigport == MACH_PORT_NULL) | |
551 | || ((firstfd != lastfd || sigport != MACH_PORT_NULL) && portset != MACH_PORT_NULL)) | |
0d3eb016 RM |
552 | /* Destroy PORTSET, but only if it's not actually the reply port for a |
553 | single descriptor (in which case it's destroyed in the previous loop; | |
554 | not doing it here is just a bit more efficient). */ | |
555 | __mach_port_destroy (__mach_task_self (), portset); | |
556 | ||
557 | if (err) | |
558 | { | |
559 | if (sigmask) | |
560 | __sigprocmask (SIG_SETMASK, &oset, NULL); | |
561 | return __hurd_fail (err); | |
562 | } | |
563 | ||
564 | if (pollfds) | |
565 | /* Fill in the `revents' members of the user's array. */ | |
566 | for (i = 0; i < nfds; ++i) | |
567 | { | |
80081a0a | 568 | int type = d[i].type; |
535e935a | 569 | int revents = 0; |
0d3eb016 | 570 | |
d76d187c ST |
571 | if (type & SELECT_ERROR) |
572 | switch (d[i].error) | |
573 | { | |
574 | case EPIPE: | |
575 | revents = POLLHUP; | |
576 | break; | |
577 | case EBADF: | |
578 | revents = POLLNVAL; | |
579 | break; | |
580 | default: | |
581 | revents = POLLERR; | |
582 | break; | |
583 | } | |
584 | else | |
585 | if (type & SELECT_RETURNED) | |
586 | { | |
587 | if (type & SELECT_READ) | |
588 | revents |= POLLIN; | |
589 | if (type & SELECT_WRITE) | |
590 | revents |= POLLOUT; | |
591 | if (type & SELECT_URG) | |
592 | revents |= POLLPRI; | |
593 | } | |
0d3eb016 RM |
594 | |
595 | pollfds[i].revents = revents; | |
596 | } | |
597 | else | |
598 | { | |
c3010778 | 599 | /* Below we recalculate READY to include an increment for each operation |
0d3eb016 | 600 | allowed on each fd. */ |
c3010778 | 601 | ready = 0; |
0d3eb016 RM |
602 | |
603 | /* Set the user bitarrays. We only ever have to clear bits, as all | |
604 | desired ones are initially set. */ | |
605 | if (firstfd != -1) | |
606 | for (i = firstfd; i <= lastfd; ++i) | |
607 | { | |
608 | int type = d[i].type; | |
609 | ||
610 | if ((type & SELECT_RETURNED) == 0) | |
611 | type = 0; | |
612 | ||
d76d187c ST |
613 | /* Callers of select don't expect to see errors, so we simulate |
614 | readiness of the erring object and the next call hopefully | |
615 | will get the error again. */ | |
616 | if (type & SELECT_ERROR) | |
617 | { | |
618 | type = 0; | |
619 | if (readfds != NULL && FD_ISSET (i, readfds)) | |
620 | type |= SELECT_READ; | |
621 | if (writefds != NULL && FD_ISSET (i, writefds)) | |
622 | type |= SELECT_WRITE; | |
623 | if (exceptfds != NULL && FD_ISSET (i, exceptfds)) | |
624 | type |= SELECT_URG; | |
625 | } | |
626 | ||
0d3eb016 | 627 | if (type & SELECT_READ) |
c3010778 | 628 | ready++; |
0d3eb016 RM |
629 | else if (readfds) |
630 | FD_CLR (i, readfds); | |
631 | if (type & SELECT_WRITE) | |
c3010778 | 632 | ready++; |
0d3eb016 RM |
633 | else if (writefds) |
634 | FD_CLR (i, writefds); | |
635 | if (type & SELECT_URG) | |
c3010778 | 636 | ready++; |
0d3eb016 RM |
637 | else if (exceptfds) |
638 | FD_CLR (i, exceptfds); | |
639 | } | |
640 | } | |
641 | ||
642 | if (sigmask && __sigprocmask (SIG_SETMASK, &oset, NULL)) | |
643 | return -1; | |
644 | ||
c3010778 | 645 | return ready; |
0d3eb016 | 646 | } |