1 /* Guts of both `select' and `poll' for Hurd.
2 Copyright (C) 1991-2024 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 #include <sysdep-cancel.h>
34 /* All user select types. */
35 #define SELECT_ALL (SELECT_READ | SELECT_WRITE | SELECT_URG)
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)
40 #define SELECT_ERROR (SELECT_RETURNED << 1)
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. */
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
)
53 mach_port_t portset
, sigport
;
56 fd_set rfds
, wfds
, xfds
;
58 mach_msg_id_t reply_msgid
;
59 mach_msg_timeout_t to
;
63 struct hurd_userlink ulink
;
67 mach_port_t reply_port
;
71 struct hurd_sigstate
*ss
= NULL
;
73 if (nfds
< 0 || (pollfds
== NULL
&& nfds
> FD_SETSIZE
))
74 return __hurd_fail (EINVAL
);
76 #define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
77 #define IO_SELECT_TIMEOUT_REPLY_MSGID (21031 + 100) /* XXX */
80 reply_msgid
= IO_SELECT_REPLY_MSGID
;
85 if (timeout
->tv_sec
< 0 || ! valid_nanoseconds (timeout
->tv_nsec
))
86 return __hurd_fail (EINVAL
);
88 err
= __clock_gettime (CLOCK_REALTIME
, &now
);
92 ts
.tv_sec
= now
.tv_sec
+ timeout
->tv_sec
;
93 ts
.tv_nsec
= now
.tv_nsec
+ timeout
->tv_nsec
;
95 if (ts
.tv_nsec
>= 1000000000)
98 ts
.tv_nsec
-= 1000000000;
102 ts
.tv_sec
= LONG_MAX
; /* XXX */
104 reply_msgid
= IO_SELECT_TIMEOUT_REPLY_MSGID
;
109 /* Add a port to the portset for the case when we get the signal even
110 before calling __mach_msg. */
112 sigport
= __mach_reply_port ();
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
);
120 if (__sigprocmask (SIG_SETMASK
, sigmask
, &oset
))
122 _hurd_sigstate_lock (ss
);
123 ss
->suspended
= MACH_PORT_NULL
;
124 _hurd_sigstate_unlock (ss
);
125 __mach_port_destroy (__mach_task_self (), sigport
);
130 sigport
= MACH_PORT_NULL
;
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. */
140 for (i
= 0; i
< nfds
; ++i
)
141 if (pollfds
[i
].fd
>= 0)
144 if (pollfds
[i
].events
& POLLIN
)
146 if (pollfds
[i
].events
& POLLOUT
)
147 type
|= SELECT_WRITE
;
148 if (pollfds
[i
].events
& POLLPRI
)
151 d
[i
].io_port
= pollfds
[i
].fd
;
158 __mutex_lock (&_hurd_dtable_lock
);
160 for (i
= 0; i
< nfds
; ++i
)
163 const int fd
= (int) d
[i
].io_port
;
165 if (fd
< _hurd_dtablesize
)
167 d
[i
].cell
= _hurd_dtable
[fd
];
168 if (d
[i
].cell
!= NULL
)
170 d
[i
].io_port
= _hurd_port_get (&d
[i
].cell
->port
,
172 if (d
[i
].io_port
!= MACH_PORT_NULL
)
177 /* Bogus descriptor, make it EBADF already. */
179 d
[i
].type
= SELECT_ERROR
;
183 __mutex_unlock (&_hurd_dtable_lock
);
188 /* Set timeout to 0. */
189 err
= __clock_gettime (CLOCK_REALTIME
, &ts
);
192 /* Really bad luck. */
195 __mutex_lock (&_hurd_dtable_lock
);
197 if (d
[i
].type
& ~SELECT_ERROR
!= 0)
198 _hurd_port_free (&d
[i
].cell
->port
, &d
[i
].ulink
,
200 __mutex_unlock (&_hurd_dtable_lock
);
203 __sigprocmask (SIG_SETMASK
, &oset
, NULL
);
207 reply_msgid
= IO_SELECT_TIMEOUT_REPLY_MSGID
;
211 firstfd
= i
== 0 ? lastfd
: 0;
215 /* Collect interested descriptors from the user's fd_set arguments.
216 Use local copies so we can't crash from user bogosity. */
222 if (writefds
== NULL
)
226 if (exceptfds
== NULL
)
232 __mutex_lock (&_hurd_dtable_lock
);
234 /* Collect the ports for interesting FDs. */
235 firstfd
= lastfd
= -1;
236 for (i
= 0; i
< nfds
; ++i
)
239 if (readfds
!= NULL
&& FD_ISSET (i
, &rfds
))
241 if (writefds
!= NULL
&& FD_ISSET (i
, &wfds
))
242 type
|= SELECT_WRITE
;
243 if (exceptfds
!= NULL
&& FD_ISSET (i
, &xfds
))
248 if (i
< _hurd_dtablesize
)
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
,
255 if (i
>= _hurd_dtablesize
|| d
[i
].cell
== NULL
||
256 d
[i
].io_port
== MACH_PORT_NULL
)
258 /* If one descriptor is bogus, we fail completely. */
261 _hurd_port_free (&d
[i
].cell
->port
, &d
[i
].ulink
,
271 __mutex_unlock (&_hurd_dtable_lock
);
277 __sigprocmask (SIG_SETMASK
, &oset
, NULL
);
278 return __hurd_fail (EBADF
);
281 if (nfds
> _hurd_dtablesize
)
282 nfds
= _hurd_dtablesize
;
289 /* Send them all io_select request messages. */
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 ();
302 portset
= MACH_PORT_NULL
;
304 for (i
= firstfd
; i
<= lastfd
; ++i
)
305 if (!(d
[i
].type
& ~SELECT_ERROR
))
306 d
[i
].reply_port
= MACH_PORT_NULL
;
309 int type
= d
[i
].type
;
310 d
[i
].reply_port
= __mach_reply_port ();
312 err
= __io_select_request (d
[i
].io_port
, d
[i
].reply_port
, type
);
314 err
= __io_select_timeout_request (d
[i
].io_port
, d
[i
].reply_port
,
318 if (firstfd
== lastfd
&& sigport
== MACH_PORT_NULL
)
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
;
324 /* We've got multiple reply ports, so we need a port set to
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
,
334 /* Put this reply port in the port set. */
335 __mach_port_move_member (__mach_task_self (),
336 d
[i
].reply_port
, portset
);
341 /* No error should happen, but record it for later
344 d
[i
].type
|= SELECT_ERROR
;
347 _hurd_port_free (&d
[i
].cell
->port
, &d
[i
].ulink
, d
[i
].io_port
);
350 if (got
== 0 && sigport
!= MACH_PORT_NULL
)
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
,
356 /* Put the signal reply port in the port set. */
357 __mach_port_move_member (__mach_task_self (), sigport
, portset
);
361 /* GOT is the number of replies (or errors), while READY is the number of
362 replies with at least one type bit set. */
365 /* Now wait for reply messages. */
366 if (!err
&& got
== 0)
368 /* Now wait for io_select_reply messages on PORT,
369 timing out as appropriate. */
373 mach_msg_header_t head
;
374 #ifdef MACH_MSG_TRAILER_MINIMUM_SIZE
377 mach_msg_header_t head
;
383 mach_msg_header_t head
;
387 mach_msg_trailer_t trailer
;
392 mach_msg_header_t head
;
393 mach_msg_type_t err_type
;
398 mach_msg_header_t head
;
399 mach_msg_type_t err_type
;
401 mach_msg_type_t result_type
;
406 mach_msg_option_t options
;
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)
413 options
= MACH_RCV_TIMEOUT
;
414 to
= timeout
->tv_sec
* 1000 + (timeout
->tv_nsec
+ 999999) / 1000000;
419 to
= MACH_MSG_TIMEOUT_NONE
;
422 int cancel_oldtype
= LIBC_CANCEL_ASYNC();
423 while ((msgerr
= __mach_msg (&msg
.head
,
424 MACH_RCV_MSG
| MACH_RCV_INTERRUPT
| options
,
425 0, sizeof msg
, portset
, to
,
426 MACH_PORT_NULL
)) == MACH_MSG_SUCCESS
)
428 LIBC_CANCEL_RESET (cancel_oldtype
);
430 /* We got a message. Decode it. */
431 #ifdef MACH_MSG_TYPE_BIT
432 static const mach_msg_type_t inttype
= {
433 .msgt_name
= MACH_MSG_TYPE_INTEGER_T
,
434 .msgt_size
= sizeof (integer_t
) * 8,
437 .msgt_longform
= FALSE
,
438 .msgt_deallocate
= FALSE
,
443 if (sigport
!= MACH_PORT_NULL
&& sigport
== msg
.head
.msgh_local_port
)
445 /* We actually got interrupted by a signal before
446 __mach_msg; poll for further responses and then
452 if (msg
.head
.msgh_id
== reply_msgid
453 && msg
.head
.msgh_size
>= sizeof msg
.error
454 && !(msg
.head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
455 #ifdef MACH_MSG_TYPE_BIT
456 && !BAD_TYPECHECK (&msg
.error
.err_type
, &inttype
)
460 /* This is a properly formatted message so far.
461 See if it is a success or a failure. */
462 if (msg
.error
.err
== EINTR
463 && msg
.head
.msgh_size
== sizeof msg
.error
)
465 /* EINTR response; poll for further responses
466 and then return quickly. */
470 /* Keep in mind msg.success.result can be 0 if a timeout
473 #ifdef MACH_MSG_TYPE_BIT
474 || BAD_TYPECHECK (&msg
.success
.result_type
, &inttype
)
476 || msg
.head
.msgh_size
!= sizeof msg
.success
)
478 /* Error or bogus reply. */
481 __mach_msg_destroy (&msg
.head
);
484 /* Look up the respondent's reply port and record its
489 for (i
= firstfd
; i
<= lastfd
; ++i
)
491 && d
[i
].reply_port
== msg
.head
.msgh_local_port
)
495 d
[i
].error
= msg
.error
.err
;
496 d
[i
].type
= SELECT_ERROR
;
501 d
[i
].type
&= msg
.success
.result
;
506 d
[i
].type
|= SELECT_RETURNED
;
513 if (msg
.head
.msgh_remote_port
!= MACH_PORT_NULL
)
514 __mach_port_deallocate (__mach_task_self (),
515 msg
.head
.msgh_remote_port
);
520 /* Poll for another message. */
522 options
|= MACH_RCV_TIMEOUT
;
525 LIBC_CANCEL_RESET (cancel_oldtype
);
527 if (msgerr
== MACH_RCV_INTERRUPTED
)
528 /* Interruption on our side (e.g. signal reception). */
532 /* At least one descriptor is known to be ready now, so we will
538 for (i
= firstfd
; i
<= lastfd
; ++i
)
539 if (d
[i
].reply_port
!= MACH_PORT_NULL
)
540 __mach_port_destroy (__mach_task_self (), d
[i
].reply_port
);
542 if (sigport
!= MACH_PORT_NULL
)
544 _hurd_sigstate_lock (ss
);
545 ss
->suspended
= MACH_PORT_NULL
;
546 _hurd_sigstate_unlock (ss
);
547 __mach_port_destroy (__mach_task_self (), sigport
);
550 if ((firstfd
== -1 && sigport
== MACH_PORT_NULL
)
551 || ((firstfd
!= lastfd
|| sigport
!= MACH_PORT_NULL
) && portset
!= MACH_PORT_NULL
))
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
);
560 __sigprocmask (SIG_SETMASK
, &oset
, NULL
);
561 return __hurd_fail (err
);
565 /* Fill in the `revents' members of the user's array. */
566 for (i
= 0; i
< nfds
; ++i
)
568 int type
= d
[i
].type
;
571 if (type
& SELECT_ERROR
)
585 if (type
& SELECT_RETURNED
)
587 if (type
& SELECT_READ
)
589 if (type
& SELECT_WRITE
)
591 if (type
& SELECT_URG
)
595 pollfds
[i
].revents
= revents
;
599 /* Below we recalculate READY to include an increment for each operation
600 allowed on each fd. */
603 /* Set the user bitarrays. We only ever have to clear bits, as all
604 desired ones are initially set. */
606 for (i
= firstfd
; i
<= lastfd
; ++i
)
608 int type
= d
[i
].type
;
610 if ((type
& SELECT_RETURNED
) == 0)
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
)
619 if (readfds
!= NULL
&& FD_ISSET (i
, readfds
))
621 if (writefds
!= NULL
&& FD_ISSET (i
, writefds
))
622 type
|= SELECT_WRITE
;
623 if (exceptfds
!= NULL
&& FD_ISSET (i
, exceptfds
))
627 if (type
& SELECT_READ
)
631 if (type
& SELECT_WRITE
)
634 FD_CLR (i
, writefds
);
635 if (type
& SELECT_URG
)
638 FD_CLR (i
, exceptfds
);
642 if (sigmask
&& __sigprocmask (SIG_SETMASK
, &oset
, NULL
))