1 /* Guts of both `select' and `poll' for Hurd.
2 Copyright (C) 1991-2020 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
20 #include <sys/types.h>
24 #include <hurd/io_request.h>
32 /* All user select types. */
33 #define SELECT_ALL (SELECT_READ | SELECT_WRITE | SELECT_URG)
35 /* Used to record that a particular select rpc returned. Must be distinct
36 from SELECT_ALL (which better not have the high bit set). */
37 #define SELECT_RETURNED ((SELECT_ALL << 1) & ~SELECT_ALL)
38 #define SELECT_ERROR (SELECT_RETURNED << 1)
40 /* Check the first NFDS descriptors either in POLLFDS (if nonnnull) or in
41 each of READFDS, WRITEFDS, EXCEPTFDS that is nonnull. If TIMEOUT is not
42 NULL, time out after waiting the interval specified therein. Returns
43 the number of ready descriptors, or -1 for errors. */
45 _hurd_select (int nfds
,
46 struct pollfd
*pollfds
,
47 fd_set
*readfds
, fd_set
*writefds
, fd_set
*exceptfds
,
48 const struct timespec
*timeout
, const sigset_t
*sigmask
)
51 mach_port_t portset
, sigport
;
54 fd_set rfds
, wfds
, xfds
;
56 mach_msg_id_t reply_msgid
;
57 mach_msg_timeout_t to
;
61 struct hurd_userlink ulink
;
65 mach_port_t reply_port
;
69 struct hurd_sigstate
*ss
;
71 union typeword
/* Use this to avoid unkosher casts. */
76 assert (sizeof (union typeword
) == sizeof (mach_msg_type_t
));
77 assert (sizeof (uint32_t) == sizeof (mach_msg_type_t
));
79 if (nfds
< 0 || (pollfds
== NULL
&& nfds
> FD_SETSIZE
))
85 #define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
86 #define IO_SELECT_TIMEOUT_REPLY_MSGID (21031 + 100) /* XXX */
89 reply_msgid
= IO_SELECT_REPLY_MSGID
;
94 if (timeout
->tv_sec
< 0 || ! valid_nanoseconds (timeout
->tv_nsec
))
100 err
= __clock_gettime (CLOCK_REALTIME
, &now
);
104 ts
.tv_sec
= now
.tv_sec
+ timeout
->tv_sec
;
105 ts
.tv_nsec
= now
.tv_nsec
+ timeout
->tv_nsec
;
107 if (ts
.tv_nsec
>= 1000000000)
110 ts
.tv_nsec
-= 1000000000;
114 ts
.tv_sec
= LONG_MAX
; /* XXX */
116 reply_msgid
= IO_SELECT_TIMEOUT_REPLY_MSGID
;
121 /* Add a port to the portset for the case when we get the signal even
122 before calling __mach_msg. */
124 sigport
= __mach_reply_port ();
126 ss
= _hurd_self_sigstate ();
127 _hurd_sigstate_lock (ss
);
128 /* And tell the signal thread to message us when a signal arrives. */
129 ss
->suspended
= sigport
;
130 _hurd_sigstate_unlock (ss
);
132 if (__sigprocmask (SIG_SETMASK
, sigmask
, &oset
))
134 _hurd_sigstate_lock (ss
);
135 ss
->suspended
= MACH_PORT_NULL
;
136 _hurd_sigstate_unlock (ss
);
137 __mach_port_destroy (__mach_task_self (), sigport
);
142 sigport
= MACH_PORT_NULL
;
147 /* Collect interesting descriptors from the user's `pollfd' array.
148 We do a first pass that reads the user's array before taking
149 any locks. The second pass then only touches our own stack,
150 and gets the port references. */
152 for (i
= 0; i
< nfds
; ++i
)
153 if (pollfds
[i
].fd
>= 0)
156 if (pollfds
[i
].events
& POLLIN
)
158 if (pollfds
[i
].events
& POLLOUT
)
159 type
|= SELECT_WRITE
;
160 if (pollfds
[i
].events
& POLLPRI
)
163 d
[i
].io_port
= pollfds
[i
].fd
;
170 __mutex_lock (&_hurd_dtable_lock
);
172 for (i
= 0; i
< nfds
; ++i
)
175 const int fd
= (int) d
[i
].io_port
;
177 if (fd
< _hurd_dtablesize
)
179 d
[i
].cell
= _hurd_dtable
[fd
];
180 if (d
[i
].cell
!= NULL
)
182 d
[i
].io_port
= _hurd_port_get (&d
[i
].cell
->port
,
184 if (d
[i
].io_port
!= MACH_PORT_NULL
)
189 /* Bogus descriptor, make it EBADF already. */
191 d
[i
].type
= SELECT_ERROR
;
195 __mutex_unlock (&_hurd_dtable_lock
);
200 /* Set timeout to 0. */
201 err
= __clock_gettime (CLOCK_REALTIME
, &ts
);
204 /* Really bad luck. */
207 __mutex_lock (&_hurd_dtable_lock
);
209 if (d
[i
].type
& ~SELECT_ERROR
!= 0)
210 _hurd_port_free (&d
[i
].cell
->port
, &d
[i
].ulink
,
212 __mutex_unlock (&_hurd_dtable_lock
);
215 __sigprocmask (SIG_SETMASK
, &oset
, NULL
);
219 reply_msgid
= IO_SELECT_TIMEOUT_REPLY_MSGID
;
223 firstfd
= i
== 0 ? lastfd
: 0;
227 /* Collect interested descriptors from the user's fd_set arguments.
228 Use local copies so we can't crash from user bogosity. */
234 if (writefds
== NULL
)
238 if (exceptfds
== NULL
)
244 __mutex_lock (&_hurd_dtable_lock
);
246 /* Collect the ports for interesting FDs. */
247 firstfd
= lastfd
= -1;
248 for (i
= 0; i
< nfds
; ++i
)
251 if (readfds
!= NULL
&& FD_ISSET (i
, &rfds
))
253 if (writefds
!= NULL
&& FD_ISSET (i
, &wfds
))
254 type
|= SELECT_WRITE
;
255 if (exceptfds
!= NULL
&& FD_ISSET (i
, &xfds
))
260 if (i
< _hurd_dtablesize
)
262 d
[i
].cell
= _hurd_dtable
[i
];
263 if (d
[i
].cell
!= NULL
)
264 d
[i
].io_port
= _hurd_port_get (&d
[i
].cell
->port
,
267 if (i
>= _hurd_dtablesize
|| d
[i
].cell
== NULL
||
268 d
[i
].io_port
== MACH_PORT_NULL
)
270 /* If one descriptor is bogus, we fail completely. */
273 _hurd_port_free (&d
[i
].cell
->port
, &d
[i
].ulink
,
283 __mutex_unlock (&_hurd_dtable_lock
);
289 __sigprocmask (SIG_SETMASK
, &oset
, NULL
);
294 if (nfds
> _hurd_dtablesize
)
295 nfds
= _hurd_dtablesize
;
302 /* Send them all io_select request messages. */
306 if (sigport
== MACH_PORT_NULL
)
307 /* But not if there were no ports to deal with at all.
308 We are just a pure timeout. */
309 portset
= __mach_reply_port ();
315 portset
= MACH_PORT_NULL
;
317 for (i
= firstfd
; i
<= lastfd
; ++i
)
318 if (!(d
[i
].type
& ~SELECT_ERROR
))
319 d
[i
].reply_port
= MACH_PORT_NULL
;
322 int type
= d
[i
].type
;
323 d
[i
].reply_port
= __mach_reply_port ();
325 err
= __io_select_request (d
[i
].io_port
, d
[i
].reply_port
, type
);
327 err
= __io_select_timeout_request (d
[i
].io_port
, d
[i
].reply_port
,
331 if (firstfd
== lastfd
&& sigport
== MACH_PORT_NULL
)
332 /* When there's a single descriptor, we don't need a
333 portset, so just pretend we have one, but really
334 use the single reply port. */
335 portset
= d
[i
].reply_port
;
337 /* We've got multiple reply ports, so we need a port set to
340 /* We will wait again for a reply later. */
341 if (portset
== MACH_PORT_NULL
)
342 /* Create the portset to receive all the replies on. */
343 err
= __mach_port_allocate (__mach_task_self (),
344 MACH_PORT_RIGHT_PORT_SET
,
347 /* Put this reply port in the port set. */
348 __mach_port_move_member (__mach_task_self (),
349 d
[i
].reply_port
, portset
);
354 /* No error should happen, but record it for later
357 d
[i
].type
|= SELECT_ERROR
;
360 _hurd_port_free (&d
[i
].cell
->port
, &d
[i
].ulink
, d
[i
].io_port
);
363 if (got
== 0 && sigport
!= MACH_PORT_NULL
)
365 if (portset
== MACH_PORT_NULL
)
366 /* Create the portset to receive the signal message on. */
367 __mach_port_allocate (__mach_task_self (), MACH_PORT_RIGHT_PORT_SET
,
369 /* Put the signal reply port in the port set. */
370 __mach_port_move_member (__mach_task_self (), sigport
, portset
);
374 /* GOT is the number of replies (or errors), while READY is the number of
375 replies with at least one type bit set. */
378 /* Now wait for reply messages. */
379 if (!err
&& got
== 0)
381 /* Now wait for io_select_reply messages on PORT,
382 timing out as appropriate. */
386 mach_msg_header_t head
;
387 #ifdef MACH_MSG_TRAILER_MINIMUM_SIZE
390 mach_msg_header_t head
;
396 mach_msg_header_t head
;
400 mach_msg_trailer_t trailer
;
405 mach_msg_header_t head
;
406 union typeword err_type
;
411 mach_msg_header_t head
;
412 union typeword err_type
;
414 union typeword result_type
;
419 mach_msg_option_t options
;
422 /* We rely on servers to implement the timeout, but when there are none,
423 do it on the client side. */
424 if (timeout
!= NULL
&& firstfd
== -1)
426 options
= MACH_RCV_TIMEOUT
;
427 to
= timeout
->tv_sec
* 1000 + (timeout
->tv_nsec
+ 999999) / 1000000;
432 to
= MACH_MSG_TIMEOUT_NONE
;
435 while ((msgerr
= __mach_msg (&msg
.head
,
436 MACH_RCV_MSG
| MACH_RCV_INTERRUPT
| options
,
437 0, sizeof msg
, portset
, to
,
438 MACH_PORT_NULL
)) == MACH_MSG_SUCCESS
)
440 /* We got a message. Decode it. */
441 #ifdef MACH_MSG_TYPE_BIT
442 const union typeword inttype
=
444 { MACH_MSG_TYPE_INTEGER_T
, sizeof (integer_t
) * 8, 1, 1, 0, 0 }
448 if (sigport
!= MACH_PORT_NULL
&& sigport
== msg
.head
.msgh_local_port
)
450 /* We actually got interrupted by a signal before
451 __mach_msg; poll for further responses and then
457 if (msg
.head
.msgh_id
== reply_msgid
458 && msg
.head
.msgh_size
>= sizeof msg
.error
459 && !(msg
.head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
460 #ifdef MACH_MSG_TYPE_BIT
461 && msg
.error
.err_type
.word
== inttype
.word
465 /* This is a properly formatted message so far.
466 See if it is a success or a failure. */
467 if (msg
.error
.err
== EINTR
468 && msg
.head
.msgh_size
== sizeof msg
.error
)
470 /* EINTR response; poll for further responses
471 and then return quickly. */
475 /* Keep in mind msg.success.result can be 0 if a timeout
478 #ifdef MACH_MSG_TYPE_BIT
479 || msg
.success
.result_type
.word
!= inttype
.word
481 || msg
.head
.msgh_size
!= sizeof msg
.success
)
483 /* Error or bogus reply. */
486 __mach_msg_destroy (&msg
.head
);
489 /* Look up the respondent's reply port and record its
494 for (i
= firstfd
; i
<= lastfd
; ++i
)
496 && d
[i
].reply_port
== msg
.head
.msgh_local_port
)
500 d
[i
].error
= msg
.error
.err
;
501 d
[i
].type
= SELECT_ERROR
;
506 d
[i
].type
&= msg
.success
.result
;
511 d
[i
].type
|= SELECT_RETURNED
;
518 if (msg
.head
.msgh_remote_port
!= MACH_PORT_NULL
)
519 __mach_port_deallocate (__mach_task_self (),
520 msg
.head
.msgh_remote_port
);
525 /* Poll for another message. */
527 options
|= MACH_RCV_TIMEOUT
;
531 if (msgerr
== MACH_RCV_INTERRUPTED
)
532 /* Interruption on our side (e.g. signal reception). */
536 /* At least one descriptor is known to be ready now, so we will
542 for (i
= firstfd
; i
<= lastfd
; ++i
)
543 if (d
[i
].reply_port
!= MACH_PORT_NULL
)
544 __mach_port_destroy (__mach_task_self (), d
[i
].reply_port
);
546 if (sigport
!= MACH_PORT_NULL
)
548 _hurd_sigstate_lock (ss
);
549 ss
->suspended
= MACH_PORT_NULL
;
550 _hurd_sigstate_unlock (ss
);
551 __mach_port_destroy (__mach_task_self (), sigport
);
554 if ((firstfd
== -1 && sigport
== MACH_PORT_NULL
)
555 || ((firstfd
!= lastfd
|| sigport
!= MACH_PORT_NULL
) && portset
!= MACH_PORT_NULL
))
556 /* Destroy PORTSET, but only if it's not actually the reply port for a
557 single descriptor (in which case it's destroyed in the previous loop;
558 not doing it here is just a bit more efficient). */
559 __mach_port_destroy (__mach_task_self (), portset
);
564 __sigprocmask (SIG_SETMASK
, &oset
, NULL
);
565 return __hurd_fail (err
);
569 /* Fill in the `revents' members of the user's array. */
570 for (i
= 0; i
< nfds
; ++i
)
572 int type
= d
[i
].type
;
573 int_fast16_t revents
= 0;
575 if (type
& SELECT_ERROR
)
589 if (type
& SELECT_RETURNED
)
591 if (type
& SELECT_READ
)
593 if (type
& SELECT_WRITE
)
595 if (type
& SELECT_URG
)
599 pollfds
[i
].revents
= revents
;
603 /* Below we recalculate READY to include an increment for each operation
604 allowed on each fd. */
607 /* Set the user bitarrays. We only ever have to clear bits, as all
608 desired ones are initially set. */
610 for (i
= firstfd
; i
<= lastfd
; ++i
)
612 int type
= d
[i
].type
;
614 if ((type
& SELECT_RETURNED
) == 0)
617 /* Callers of select don't expect to see errors, so we simulate
618 readiness of the erring object and the next call hopefully
619 will get the error again. */
620 if (type
& SELECT_ERROR
)
623 if (readfds
!= NULL
&& FD_ISSET (i
, readfds
))
625 if (writefds
!= NULL
&& FD_ISSET (i
, writefds
))
626 type
|= SELECT_WRITE
;
627 if (exceptfds
!= NULL
&& FD_ISSET (i
, exceptfds
))
631 if (type
& SELECT_READ
)
635 if (type
& SELECT_WRITE
)
638 FD_CLR (i
, writefds
);
639 if (type
& SELECT_URG
)
642 FD_CLR (i
, exceptfds
);
646 if (sigmask
&& __sigprocmask (SIG_SETMASK
, &oset
, NULL
))