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