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
)
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
;
70 union typeword
/* Use this to avoid unkosher casts. */
75 assert (sizeof (union typeword
) == sizeof (mach_msg_type_t
));
76 assert (sizeof (uint32_t) == sizeof (mach_msg_type_t
));
78 if (nfds
< 0 || (pollfds
== NULL
&& nfds
> FD_SETSIZE
))
84 #define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
85 #define IO_SELECT_TIMEOUT_REPLY_MSGID (21031 + 100) /* XXX */
88 reply_msgid
= IO_SELECT_REPLY_MSGID
;
93 if (timeout
->tv_sec
< 0 || ! valid_nanoseconds (timeout
->tv_nsec
))
99 err
= __clock_gettime (CLOCK_REALTIME
, &now
);
103 ts
.tv_sec
= now
.tv_sec
+ timeout
->tv_sec
;
104 ts
.tv_nsec
= now
.tv_nsec
+ timeout
->tv_nsec
;
106 if (ts
.tv_nsec
>= 1000000000)
109 ts
.tv_nsec
-= 1000000000;
113 ts
.tv_sec
= LONG_MAX
; /* XXX */
115 reply_msgid
= IO_SELECT_TIMEOUT_REPLY_MSGID
;
118 if (sigmask
&& __sigprocmask (SIG_SETMASK
, sigmask
, &oset
))
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. */
129 for (i
= 0; i
< nfds
; ++i
)
130 if (pollfds
[i
].fd
>= 0)
133 if (pollfds
[i
].events
& POLLIN
)
135 if (pollfds
[i
].events
& POLLOUT
)
136 type
|= SELECT_WRITE
;
137 if (pollfds
[i
].events
& POLLPRI
)
140 d
[i
].io_port
= pollfds
[i
].fd
;
147 __mutex_lock (&_hurd_dtable_lock
);
149 for (i
= 0; i
< nfds
; ++i
)
152 const int fd
= (int) d
[i
].io_port
;
154 if (fd
< _hurd_dtablesize
)
156 d
[i
].cell
= _hurd_dtable
[fd
];
157 if (d
[i
].cell
!= NULL
)
159 d
[i
].io_port
= _hurd_port_get (&d
[i
].cell
->port
,
161 if (d
[i
].io_port
!= MACH_PORT_NULL
)
166 /* Bogus descriptor, make it EBADF already. */
168 d
[i
].type
= SELECT_ERROR
;
172 __mutex_unlock (&_hurd_dtable_lock
);
177 /* Set timeout to 0. */
178 err
= __clock_gettime (CLOCK_REALTIME
, &ts
);
181 /* Really bad luck. */
184 __mutex_lock (&_hurd_dtable_lock
);
186 if (d
[i
].type
& ~SELECT_ERROR
!= 0)
187 _hurd_port_free (&d
[i
].cell
->port
, &d
[i
].ulink
,
189 __mutex_unlock (&_hurd_dtable_lock
);
194 reply_msgid
= IO_SELECT_TIMEOUT_REPLY_MSGID
;
198 firstfd
= i
== 0 ? lastfd
: 0;
202 /* Collect interested descriptors from the user's fd_set arguments.
203 Use local copies so we can't crash from user bogosity. */
209 if (writefds
== NULL
)
213 if (exceptfds
== NULL
)
219 __mutex_lock (&_hurd_dtable_lock
);
221 /* Collect the ports for interesting FDs. */
222 firstfd
= lastfd
= -1;
223 for (i
= 0; i
< nfds
; ++i
)
226 if (readfds
!= NULL
&& FD_ISSET (i
, &rfds
))
228 if (writefds
!= NULL
&& FD_ISSET (i
, &wfds
))
229 type
|= SELECT_WRITE
;
230 if (exceptfds
!= NULL
&& FD_ISSET (i
, &xfds
))
235 if (i
< _hurd_dtablesize
)
237 d
[i
].cell
= _hurd_dtable
[i
];
238 if (d
[i
].cell
!= NULL
)
239 d
[i
].io_port
= _hurd_port_get (&d
[i
].cell
->port
,
242 if (i
>= _hurd_dtablesize
|| d
[i
].cell
== NULL
||
243 d
[i
].io_port
== MACH_PORT_NULL
)
245 /* If one descriptor is bogus, we fail completely. */
248 _hurd_port_free (&d
[i
].cell
->port
, &d
[i
].ulink
,
258 __mutex_unlock (&_hurd_dtable_lock
);
264 __sigprocmask (SIG_SETMASK
, &oset
, NULL
);
269 if (nfds
> _hurd_dtablesize
)
270 nfds
= _hurd_dtablesize
;
277 /* Send them all io_select request messages. */
280 /* But not if there were no ports to deal with at all.
281 We are just a pure timeout. */
282 portset
= __mach_reply_port ();
285 portset
= MACH_PORT_NULL
;
287 for (i
= firstfd
; i
<= lastfd
; ++i
)
288 if (!(d
[i
].type
& ~SELECT_ERROR
))
289 d
[i
].reply_port
= MACH_PORT_NULL
;
292 int type
= d
[i
].type
;
293 d
[i
].reply_port
= __mach_reply_port ();
295 err
= __io_select_request (d
[i
].io_port
, d
[i
].reply_port
, type
);
297 err
= __io_select_timeout_request (d
[i
].io_port
, d
[i
].reply_port
,
301 if (firstfd
== lastfd
)
302 /* When there's a single descriptor, we don't need a
303 portset, so just pretend we have one, but really
304 use the single reply port. */
305 portset
= d
[i
].reply_port
;
307 /* We've got multiple reply ports, so we need a port set to
310 /* We will wait again for a reply later. */
311 if (portset
== MACH_PORT_NULL
)
312 /* Create the portset to receive all the replies on. */
313 err
= __mach_port_allocate (__mach_task_self (),
314 MACH_PORT_RIGHT_PORT_SET
,
317 /* Put this reply port in the port set. */
318 __mach_port_move_member (__mach_task_self (),
319 d
[i
].reply_port
, portset
);
324 /* No error should happen, but record it for later
327 d
[i
].type
|= SELECT_ERROR
;
330 _hurd_port_free (&d
[i
].cell
->port
, &d
[i
].ulink
, d
[i
].io_port
);
334 /* GOT is the number of replies (or errors), while READY is the number of
335 replies with at least one type bit set. */
338 /* Now wait for reply messages. */
339 if (!err
&& got
== 0)
341 /* Now wait for io_select_reply messages on PORT,
342 timing out as appropriate. */
346 mach_msg_header_t head
;
347 #ifdef MACH_MSG_TRAILER_MINIMUM_SIZE
350 mach_msg_header_t head
;
356 mach_msg_header_t head
;
360 mach_msg_trailer_t trailer
;
365 mach_msg_header_t head
;
366 union typeword err_type
;
371 mach_msg_header_t head
;
372 union typeword err_type
;
374 union typeword result_type
;
379 mach_msg_option_t options
;
382 /* We rely on servers to implement the timeout, but when there are none,
383 do it on the client side. */
384 if (timeout
!= NULL
&& firstfd
== -1)
386 options
= MACH_RCV_TIMEOUT
;
387 to
= timeout
->tv_sec
* 1000 + (timeout
->tv_nsec
+ 999999) / 1000000;
392 to
= MACH_MSG_TIMEOUT_NONE
;
395 while ((msgerr
= __mach_msg (&msg
.head
,
396 MACH_RCV_MSG
| MACH_RCV_INTERRUPT
| options
,
397 0, sizeof msg
, portset
, to
,
398 MACH_PORT_NULL
)) == MACH_MSG_SUCCESS
)
400 /* We got a message. Decode it. */
401 #ifdef MACH_MSG_TYPE_BIT
402 const union typeword inttype
=
404 { MACH_MSG_TYPE_INTEGER_T
, sizeof (integer_t
) * 8, 1, 1, 0, 0 }
407 if (msg
.head
.msgh_id
== reply_msgid
408 && msg
.head
.msgh_size
>= sizeof msg
.error
409 && !(msg
.head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)
410 #ifdef MACH_MSG_TYPE_BIT
411 && msg
.error
.err_type
.word
== inttype
.word
415 /* This is a properly formatted message so far.
416 See if it is a success or a failure. */
417 if (msg
.error
.err
== EINTR
418 && msg
.head
.msgh_size
== sizeof msg
.error
)
420 /* EINTR response; poll for further responses
421 and then return quickly. */
425 /* Keep in mind msg.success.result can be 0 if a timeout
428 #ifdef MACH_MSG_TYPE_BIT
429 || msg
.success
.result_type
.word
!= inttype
.word
431 || msg
.head
.msgh_size
!= sizeof msg
.success
)
433 /* Error or bogus reply. */
436 __mach_msg_destroy (&msg
.head
);
439 /* Look up the respondent's reply port and record its
444 for (i
= firstfd
; i
<= lastfd
; ++i
)
446 && d
[i
].reply_port
== msg
.head
.msgh_local_port
)
450 d
[i
].error
= msg
.error
.err
;
451 d
[i
].type
= SELECT_ERROR
;
456 d
[i
].type
&= msg
.success
.result
;
461 d
[i
].type
|= SELECT_RETURNED
;
468 if (msg
.head
.msgh_remote_port
!= MACH_PORT_NULL
)
469 __mach_port_deallocate (__mach_task_self (),
470 msg
.head
.msgh_remote_port
);
475 /* Poll for another message. */
477 options
|= MACH_RCV_TIMEOUT
;
481 if (msgerr
== MACH_RCV_INTERRUPTED
)
482 /* Interruption on our side (e.g. signal reception). */
486 /* At least one descriptor is known to be ready now, so we will
492 for (i
= firstfd
; i
<= lastfd
; ++i
)
493 if (d
[i
].reply_port
!= MACH_PORT_NULL
)
494 __mach_port_destroy (__mach_task_self (), d
[i
].reply_port
);
495 if (firstfd
== -1 || (firstfd
!= lastfd
&& portset
!= MACH_PORT_NULL
))
496 /* Destroy PORTSET, but only if it's not actually the reply port for a
497 single descriptor (in which case it's destroyed in the previous loop;
498 not doing it here is just a bit more efficient). */
499 __mach_port_destroy (__mach_task_self (), portset
);
504 __sigprocmask (SIG_SETMASK
, &oset
, NULL
);
505 return __hurd_fail (err
);
509 /* Fill in the `revents' members of the user's array. */
510 for (i
= 0; i
< nfds
; ++i
)
512 int type
= d
[i
].type
;
513 int_fast16_t revents
= 0;
515 if (type
& SELECT_ERROR
)
529 if (type
& SELECT_RETURNED
)
531 if (type
& SELECT_READ
)
533 if (type
& SELECT_WRITE
)
535 if (type
& SELECT_URG
)
539 pollfds
[i
].revents
= revents
;
543 /* Below we recalculate READY to include an increment for each operation
544 allowed on each fd. */
547 /* Set the user bitarrays. We only ever have to clear bits, as all
548 desired ones are initially set. */
550 for (i
= firstfd
; i
<= lastfd
; ++i
)
552 int type
= d
[i
].type
;
554 if ((type
& SELECT_RETURNED
) == 0)
557 /* Callers of select don't expect to see errors, so we simulate
558 readiness of the erring object and the next call hopefully
559 will get the error again. */
560 if (type
& SELECT_ERROR
)
563 if (readfds
!= NULL
&& FD_ISSET (i
, readfds
))
565 if (writefds
!= NULL
&& FD_ISSET (i
, writefds
))
566 type
|= SELECT_WRITE
;
567 if (exceptfds
!= NULL
&& FD_ISSET (i
, exceptfds
))
571 if (type
& SELECT_READ
)
575 if (type
& SELECT_WRITE
)
578 FD_CLR (i
, writefds
);
579 if (type
& SELECT_URG
)
582 FD_CLR (i
, exceptfds
);
586 if (sigmask
&& __sigprocmask (SIG_SETMASK
, &oset
, NULL
))