]> git.ipfire.org Git - thirdparty/glibc.git/blob - hurd/hurdselect.c
y2038: Introduce struct __timespec64 - new internal glibc type
[thirdparty/glibc.git] / hurd / hurdselect.c
1 /* Guts of both `select' and `poll' for Hurd.
2 Copyright (C) 1991-2019 Free Software Foundation, Inc.
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
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.
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
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19 #include <sys/time.h>
20 #include <sys/types.h>
21 #include <sys/poll.h>
22 #include <hurd.h>
23 #include <hurd/fd.h>
24 #include <hurd/io_request.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <stdint.h>
29 #include <limits.h>
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)
37 #define SELECT_ERROR (SELECT_RETURNED << 1)
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. */
43 int
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;
51 int got, ready;
52 error_t err;
53 fd_set rfds, wfds, xfds;
54 int firstfd, lastfd;
55 mach_msg_id_t reply_msgid;
56 mach_msg_timeout_t to;
57 struct timespec ts;
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;
65 int error;
66 } d[nfds];
67 sigset_t oset;
68
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
77 if (nfds < 0 || (pollfds == NULL && nfds > FD_SETSIZE))
78 {
79 errno = EINVAL;
80 return -1;
81 }
82
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
89 {
90 struct timeval now;
91
92 if (timeout->tv_sec < 0 || timeout->tv_nsec < 0 ||
93 timeout->tv_nsec >= 1000000000)
94 {
95 errno = EINVAL;
96 return -1;
97 }
98
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;
116 }
117
118 if (sigmask && __sigprocmask (SIG_SETMASK, sigmask, &oset))
119 return -1;
120
121 if (pollfds)
122 {
123 int error = 0;
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];
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 }
164 }
165
166 /* Bogus descriptor, make it EBADF already. */
167 d[i].error = EBADF;
168 d[i].type = SELECT_ERROR;
169 error = 1;
170 }
171
172 __mutex_unlock (&_hurd_dtable_lock);
173 HURD_CRITICAL_END;
174
175 if (error)
176 {
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;
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
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 {
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)
247 {
248 /* If one descriptor is bogus, we fail completely. */
249 while (i-- > 0)
250 if (d[i].type != 0)
251 _hurd_port_free (&d[i].cell->port, &d[i].ulink,
252 d[i].io_port);
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 }
271
272 if (nfds > _hurd_dtablesize)
273 nfds = _hurd_dtablesize;
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)
291 if (!(d[i].type & ~SELECT_ERROR))
292 d[i].reply_port = MACH_PORT_NULL;
293 else
294 {
295 int type = d[i].type;
296 d[i].reply_port = __mach_reply_port ();
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)
303 {
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 }
324 }
325 else
326 {
327 /* No error should happen, but record it for later
328 processing. */
329 d[i].error = err;
330 d[i].type |= SELECT_ERROR;
331 ++got;
332 }
333 _hurd_port_free (&d[i].cell->port, &d[i].ulink, d[i].io_port);
334 }
335 }
336
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
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;
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
366 struct
367 {
368 mach_msg_header_t head;
369 union typeword err_type;
370 error_t err;
371 } error;
372 struct
373 {
374 mach_msg_header_t head;
375 union typeword err_type;
376 error_t err;
377 union typeword result_type;
378 int result;
379 } success;
380 #endif
381 } msg;
382 mach_msg_option_t options;
383 error_t msgerr;
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
398 while ((msgerr = __mach_msg (&msg.head,
399 MACH_RCV_MSG | MACH_RCV_INTERRUPT | options,
400 0, sizeof msg, portset, to,
401 MACH_PORT_NULL)) == MACH_MSG_SUCCESS)
402 {
403 /* We got a message. Decode it. */
404 #ifdef MACH_MSG_TYPE_BIT
405 const union typeword inttype =
406 { type:
407 { MACH_MSG_TYPE_INTEGER_T, sizeof (integer_t) * 8, 1, 1, 0, 0 }
408 };
409 #endif
410 if (msg.head.msgh_id == reply_msgid
411 && msg.head.msgh_size >= sizeof msg.error
412 && !(msg.head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
413 #ifdef MACH_MSG_TYPE_BIT
414 && msg.error.err_type.word == inttype.word
415 #endif
416 )
417 {
418 /* This is a properly formatted message so far.
419 See if it is a success or a failure. */
420 if (msg.error.err == EINTR
421 && msg.head.msgh_size == sizeof msg.error)
422 {
423 /* EINTR response; poll for further responses
424 and then return quickly. */
425 err = EINTR;
426 goto poll;
427 }
428 /* Keep in mind msg.success.result can be 0 if a timeout
429 occurred. */
430 if (msg.error.err
431 #ifdef MACH_MSG_TYPE_BIT
432 || msg.success.result_type.word != inttype.word
433 #endif
434 || msg.head.msgh_size != sizeof msg.success)
435 {
436 /* Error or bogus reply. */
437 if (!msg.error.err)
438 msg.error.err = EIO;
439 __mach_msg_destroy (&msg.head);
440 }
441
442 /* Look up the respondent's reply port and record its
443 readiness. */
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 {
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 }
463
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
484 if (msgerr == MACH_RCV_INTERRUPTED)
485 /* Interruption on our side (e.g. signal reception). */
486 err = EINTR;
487
488 if (ready)
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)
496 if (d[i].reply_port != MACH_PORT_NULL)
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 {
515 int type = d[i].type;
516 int_fast16_t revents = 0;
517
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 }
541
542 pollfds[i].revents = revents;
543 }
544 else
545 {
546 /* Below we recalculate READY to include an increment for each operation
547 allowed on each fd. */
548 ready = 0;
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
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
574 if (type & SELECT_READ)
575 ready++;
576 else if (readfds)
577 FD_CLR (i, readfds);
578 if (type & SELECT_WRITE)
579 ready++;
580 else if (writefds)
581 FD_CLR (i, writefds);
582 if (type & SELECT_URG)
583 ready++;
584 else if (exceptfds)
585 FD_CLR (i, exceptfds);
586 }
587 }
588
589 if (sigmask && __sigprocmask (SIG_SETMASK, &oset, NULL))
590 return -1;
591
592 return ready;
593 }