1 /* Guts of both `select' and `poll' for Hurd.
2 Copyright (C) 1991-2023 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>
31 #include <sysdep-cancel.h>
33 /* All user select types. */
34 #define SELECT_ALL (SELECT_READ | SELECT_WRITE | SELECT_URG)
36 /* Used to record that a particular select rpc returned. Must be distinct
37 from SELECT_ALL (which better not have the high bit set). */
38 #define SELECT_RETURNED ((SELECT_ALL << 1) & ~SELECT_ALL)
39 #define SELECT_ERROR (SELECT_RETURNED << 1)
41 /* Check the first NFDS descriptors either in POLLFDS (if nonnnull) or in
42 each of READFDS, WRITEFDS, EXCEPTFDS that is nonnull. If TIMEOUT is not
43 NULL, time out after waiting the interval specified therein. Returns
44 the number of ready descriptors, or -1 for errors. */
46 _hurd_select (int nfds
,
47 struct pollfd
*pollfds
,
48 fd_set
*readfds
, fd_set
*writefds
, fd_set
*exceptfds
,
49 const struct timespec
*timeout
, const sigset_t
*sigmask
)
52 mach_port_t portset
, sigport
;
55 fd_set rfds
, wfds
, xfds
;
57 mach_msg_id_t reply_msgid
;
58 mach_msg_timeout_t to
;
62 struct hurd_userlink ulink
;
66 mach_port_t reply_port
;
70 struct hurd_sigstate
*ss
= NULL
;
72 union typeword
/* Use this to avoid unkosher casts. */
77 assert (sizeof (union typeword
) == sizeof (mach_msg_type_t
));
78 assert (sizeof (uint32_t) == sizeof (mach_msg_type_t
));
80 if (nfds
< 0 || (pollfds
== NULL
&& nfds
> FD_SETSIZE
))
86 #define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
87 #define IO_SELECT_TIMEOUT_REPLY_MSGID (21031 + 100) /* XXX */
90 reply_msgid
= IO_SELECT_REPLY_MSGID
;
95 if (timeout
->tv_sec
< 0 || ! valid_nanoseconds (timeout
->tv_nsec
))
101 err
= __clock_gettime (CLOCK_REALTIME
, &now
);
105 ts
.tv_sec
= now
.tv_sec
+ timeout
->tv_sec
;
106 ts
.tv_nsec
= now
.tv_nsec
+ timeout
->tv_nsec
;
108 if (ts
.tv_nsec
>= 1000000000)
111 ts
.tv_nsec
-= 1000000000;
115 ts
.tv_sec
= LONG_MAX
; /* XXX */
117 reply_msgid
= IO_SELECT_TIMEOUT_REPLY_MSGID
;
122 /* Add a port to the portset for the case when we get the signal even
123 before calling __mach_msg. */
125 sigport
= __mach_reply_port ();
127 ss
= _hurd_self_sigstate ();
128 _hurd_sigstate_lock (ss
);
129 /* And tell the signal thread to message us when a signal arrives. */
130 ss
->suspended
= sigport
;
131 _hurd_sigstate_unlock (ss
);
133 if (__sigprocmask (SIG_SETMASK
, sigmask
, &oset
))
135 _hurd_sigstate_lock (ss
);
136 ss
->suspended
= MACH_PORT_NULL
;
137 _hurd_sigstate_unlock (ss
);
138 __mach_port_destroy (__mach_task_self (), sigport
);
143 sigport
= MACH_PORT_NULL
;
148 /* Collect interesting descriptors from the user's `pollfd' array.
149 We do a first pass that reads the user's array before taking
150 any locks. The second pass then only touches our own stack,
151 and gets the port references. */
153 for (i
= 0; i
< nfds
; ++i
)
154 if (pollfds
[i
].fd
>= 0)
157 if (pollfds
[i
].events
& POLLIN
)
159 if (pollfds
[i
].events
& POLLOUT
)
160 type
|= SELECT_WRITE
;
161 if (pollfds
[i
].events
& POLLPRI
)
164 d
[i
].io_port
= pollfds
[i
].fd
;
171 __mutex_lock (&_hurd_dtable_lock
);
173 for (i
= 0; i
< nfds
; ++i
)
176 const int fd
= (int) d
[i
].io_port
;
178 if (fd
< _hurd_dtablesize
)
180 d
[i
].cell
= _hurd_dtable
[fd
];
181 if (d
[i
].cell
!= NULL
)
183 d
[i
].io_port
= _hurd_port_get (&d
[i
].cell
->port
,
185 if (d
[i
].io_port
!= MACH_PORT_NULL
)
190 /* Bogus descriptor, make it EBADF already. */
192 d
[i
].type
= SELECT_ERROR
;
196 __mutex_unlock (&_hurd_dtable_lock
);
201 /* Set timeout to 0. */
202 err
= __clock_gettime (CLOCK_REALTIME
, &ts
);
205 /* Really bad luck. */
208 __mutex_lock (&_hurd_dtable_lock
);
210 if (d
[i
].type
& ~SELECT_ERROR
!= 0)
211 _hurd_port_free (&d
[i
].cell
->port
, &d
[i
].ulink
,
213 __mutex_unlock (&_hurd_dtable_lock
);
216 __sigprocmask (SIG_SETMASK
, &oset
, NULL
);
220 reply_msgid
= IO_SELECT_TIMEOUT_REPLY_MSGID
;
224 firstfd
= i
== 0 ? lastfd
: 0;
228 /* Collect interested descriptors from the user's fd_set arguments.
229 Use local copies so we can't crash from user bogosity. */
235 if (writefds
== NULL
)
239 if (exceptfds
== NULL
)
245 __mutex_lock (&_hurd_dtable_lock
);
247 /* Collect the ports for interesting FDs. */
248 firstfd
= lastfd
= -1;
249 for (i
= 0; i
< nfds
; ++i
)
252 if (readfds
!= NULL
&& FD_ISSET (i
, &rfds
))
254 if (writefds
!= NULL
&& FD_ISSET (i
, &wfds
))
255 type
|= SELECT_WRITE
;
256 if (exceptfds
!= NULL
&& FD_ISSET (i
, &xfds
))
261 if (i
< _hurd_dtablesize
)
263 d
[i
].cell
= _hurd_dtable
[i
];
264 if (d
[i
].cell
!= NULL
)
265 d
[i
].io_port
= _hurd_port_get (&d
[i
].cell
->port
,
268 if (i
>= _hurd_dtablesize
|| d
[i
].cell
== NULL
||
269 d
[i
].io_port
== MACH_PORT_NULL
)
271 /* If one descriptor is bogus, we fail completely. */
274 _hurd_port_free (&d
[i
].cell
->port
, &d
[i
].ulink
,
284 __mutex_unlock (&_hurd_dtable_lock
);
290 __sigprocmask (SIG_SETMASK
, &oset
, NULL
);
295 if (nfds
> _hurd_dtablesize
)
296 nfds
= _hurd_dtablesize
;
303 /* Send them all io_select request messages. */
307 if (sigport
== MACH_PORT_NULL
)
308 /* But not if there were no ports to deal with at all.
309 We are just a pure timeout. */
310 portset
= __mach_reply_port ();
316 portset
= MACH_PORT_NULL
;
318 for (i
= firstfd
; i
<= lastfd
; ++i
)
319 if (!(d
[i
].type
& ~SELECT_ERROR
))
320 d
[i
].reply_port
= MACH_PORT_NULL
;
323 int type
= d
[i
].type
;
324 d
[i
].reply_port
= __mach_reply_port ();
326 err
= __io_select_request (d
[i
].io_port
, d
[i
].reply_port
, type
);
328 err
= __io_select_timeout_request (d
[i
].io_port
, d
[i
].reply_port
,
332 if (firstfd
== lastfd
&& sigport
== MACH_PORT_NULL
)
333 /* When there's a single descriptor, we don't need a
334 portset, so just pretend we have one, but really
335 use the single reply port. */
336 portset
= d
[i
].reply_port
;
338 /* We've got multiple reply ports, so we need a port set to
341 /* We will wait again for a reply later. */
342 if (portset
== MACH_PORT_NULL
)
343 /* Create the portset to receive all the replies on. */
344 err
= __mach_port_allocate (__mach_task_self (),
345 MACH_PORT_RIGHT_PORT_SET
,
348 /* Put this reply port in the port set. */
349 __mach_port_move_member (__mach_task_self (),
350 d
[i
].reply_port
, portset
);
355 /* No error should happen, but record it for later
358 d
[i
].type
|= SELECT_ERROR
;
361 _hurd_port_free (&d
[i
].cell
->port
, &d
[i
].ulink
, d
[i
].io_port
);
364 if (got
== 0 && sigport
!= MACH_PORT_NULL
)
366 if (portset
== MACH_PORT_NULL
)
367 /* Create the portset to receive the signal message on. */
368 __mach_port_allocate (__mach_task_self (), MACH_PORT_RIGHT_PORT_SET
,
370 /* Put the signal reply port in the port set. */
371 __mach_port_move_member (__mach_task_self (), sigport
, portset
);
375 /* GOT is the number of replies (or errors), while READY is the number of
376 replies with at least one type bit set. */
379 /* Now wait for reply messages. */
380 if (!err
&& got
== 0)
382 /* Now wait for io_select_reply messages on PORT,
383 timing out as appropriate. */
387 mach_msg_header_t head
;
388 #ifdef MACH_MSG_TRAILER_MINIMUM_SIZE
391 mach_msg_header_t head
;
397 mach_msg_header_t head
;
401 mach_msg_trailer_t trailer
;
406 mach_msg_header_t head
;
407 union typeword err_type
;
412 mach_msg_header_t head
;
413 union typeword err_type
;
415 union typeword result_type
;
420 mach_msg_option_t options
;
423 /* We rely on servers to implement the timeout, but when there are none,
424 do it on the client side. */
425 if (timeout
!= NULL
&& firstfd
== -1)
427 options
= MACH_RCV_TIMEOUT
;
428 to
= timeout
->tv_sec
* 1000 + (timeout
->tv_nsec
+ 999999) / 1000000;
433 to
= MACH_MSG_TIMEOUT_NONE
;
436 int cancel_oldtype
= LIBC_CANCEL_ASYNC();
437 while ((msgerr
= __mach_msg (&msg
.head
,
438 MACH_RCV_MSG
| MACH_RCV_INTERRUPT
| options
,
439 0, sizeof msg
, portset
, to
,
440 MACH_PORT_NULL
)) == MACH_MSG_SUCCESS
)
442 LIBC_CANCEL_RESET (cancel_oldtype
);
444 /* We got a message. Decode it. */
445 #ifdef MACH_MSG_TYPE_BIT
446 const union typeword inttype
=
448 { MACH_MSG_TYPE_INTEGER_T
, sizeof (integer_t
) * 8, 1, 1, 0, 0 }
452 if (sigport
!= MACH_PORT_NULL
&& sigport
== msg
.head
.msgh_local_port
)
454 /* We actually got interrupted by a signal before
455 __mach_msg; poll for further responses and then
461 if (msg
.head
.msgh_id
== reply_msgid
462 && msg
.head
.msgh_size
>= sizeof msg
.error
463 && !(msg
.head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
464 #ifdef MACH_MSG_TYPE_BIT
465 && msg
.error
.err_type
.word
== inttype
.word
469 /* This is a properly formatted message so far.
470 See if it is a success or a failure. */
471 if (msg
.error
.err
== EINTR
472 && msg
.head
.msgh_size
== sizeof msg
.error
)
474 /* EINTR response; poll for further responses
475 and then return quickly. */
479 /* Keep in mind msg.success.result can be 0 if a timeout
482 #ifdef MACH_MSG_TYPE_BIT
483 || msg
.success
.result_type
.word
!= inttype
.word
485 || msg
.head
.msgh_size
!= sizeof msg
.success
)
487 /* Error or bogus reply. */
490 __mach_msg_destroy (&msg
.head
);
493 /* Look up the respondent's reply port and record its
498 for (i
= firstfd
; i
<= lastfd
; ++i
)
500 && d
[i
].reply_port
== msg
.head
.msgh_local_port
)
504 d
[i
].error
= msg
.error
.err
;
505 d
[i
].type
= SELECT_ERROR
;
510 d
[i
].type
&= msg
.success
.result
;
515 d
[i
].type
|= SELECT_RETURNED
;
522 if (msg
.head
.msgh_remote_port
!= MACH_PORT_NULL
)
523 __mach_port_deallocate (__mach_task_self (),
524 msg
.head
.msgh_remote_port
);
529 /* Poll for another message. */
531 options
|= MACH_RCV_TIMEOUT
;
534 LIBC_CANCEL_RESET (cancel_oldtype
);
536 if (msgerr
== MACH_RCV_INTERRUPTED
)
537 /* Interruption on our side (e.g. signal reception). */
541 /* At least one descriptor is known to be ready now, so we will
547 for (i
= firstfd
; i
<= lastfd
; ++i
)
548 if (d
[i
].reply_port
!= MACH_PORT_NULL
)
549 __mach_port_destroy (__mach_task_self (), d
[i
].reply_port
);
551 if (sigport
!= MACH_PORT_NULL
)
553 _hurd_sigstate_lock (ss
);
554 ss
->suspended
= MACH_PORT_NULL
;
555 _hurd_sigstate_unlock (ss
);
556 __mach_port_destroy (__mach_task_self (), sigport
);
559 if ((firstfd
== -1 && sigport
== MACH_PORT_NULL
)
560 || ((firstfd
!= lastfd
|| sigport
!= MACH_PORT_NULL
) && portset
!= MACH_PORT_NULL
))
561 /* Destroy PORTSET, but only if it's not actually the reply port for a
562 single descriptor (in which case it's destroyed in the previous loop;
563 not doing it here is just a bit more efficient). */
564 __mach_port_destroy (__mach_task_self (), portset
);
569 __sigprocmask (SIG_SETMASK
, &oset
, NULL
);
570 return __hurd_fail (err
);
574 /* Fill in the `revents' members of the user's array. */
575 for (i
= 0; i
< nfds
; ++i
)
577 int type
= d
[i
].type
;
580 if (type
& SELECT_ERROR
)
594 if (type
& SELECT_RETURNED
)
596 if (type
& SELECT_READ
)
598 if (type
& SELECT_WRITE
)
600 if (type
& SELECT_URG
)
604 pollfds
[i
].revents
= revents
;
608 /* Below we recalculate READY to include an increment for each operation
609 allowed on each fd. */
612 /* Set the user bitarrays. We only ever have to clear bits, as all
613 desired ones are initially set. */
615 for (i
= firstfd
; i
<= lastfd
; ++i
)
617 int type
= d
[i
].type
;
619 if ((type
& SELECT_RETURNED
) == 0)
622 /* Callers of select don't expect to see errors, so we simulate
623 readiness of the erring object and the next call hopefully
624 will get the error again. */
625 if (type
& SELECT_ERROR
)
628 if (readfds
!= NULL
&& FD_ISSET (i
, readfds
))
630 if (writefds
!= NULL
&& FD_ISSET (i
, writefds
))
631 type
|= SELECT_WRITE
;
632 if (exceptfds
!= NULL
&& FD_ISSET (i
, exceptfds
))
636 if (type
& SELECT_READ
)
640 if (type
& SELECT_WRITE
)
643 FD_CLR (i
, writefds
);
644 if (type
& SELECT_URG
)
647 FD_CLR (i
, exceptfds
);
651 if (sigmask
&& __sigprocmask (SIG_SETMASK
, &oset
, NULL
))