/* Guts of both `select' and `poll' for Hurd.
Copyright (C) 1991-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <sys/time.h>
#include <sys/types.h>
#include <sys/poll.h>
#include <hurd.h>
#include <hurd/fd.h>
#include <hurd/io_request.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <limits.h>
#include <time.h>
#include <sysdep-cancel.h>
/* All user select types. */
#define SELECT_ALL (SELECT_READ | SELECT_WRITE | SELECT_URG)
/* Used to record that a particular select rpc returned. Must be distinct
from SELECT_ALL (which better not have the high bit set). */
#define SELECT_RETURNED ((SELECT_ALL << 1) & ~SELECT_ALL)
#define SELECT_ERROR (SELECT_RETURNED << 1)
/* Check the first NFDS descriptors either in POLLFDS (if nonnnull) or in
each of READFDS, WRITEFDS, EXCEPTFDS that is nonnull. If TIMEOUT is not
NULL, time out after waiting the interval specified therein. Returns
the number of ready descriptors, or -1 for errors. */
int
_hurd_select (int nfds,
struct pollfd *pollfds,
fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
const struct timespec *timeout, const sigset_t *sigmask)
{
int i;
mach_port_t portset, sigport;
int got, ready;
error_t err;
fd_set rfds, wfds, xfds;
int firstfd, lastfd;
mach_msg_id_t reply_msgid;
mach_msg_timeout_t to;
struct timespec ts;
struct
{
struct hurd_userlink ulink;
struct hurd_fd *cell;
mach_port_t io_port;
int type;
mach_port_t reply_port;
int error;
} d[nfds];
sigset_t oset;
struct hurd_sigstate *ss = NULL;
union typeword /* Use this to avoid unkosher casts. */
{
mach_msg_type_t type;
uint32_t word;
};
assert (sizeof (union typeword) == sizeof (mach_msg_type_t));
assert (sizeof (uint32_t) == sizeof (mach_msg_type_t));
if (nfds < 0 || (pollfds == NULL && nfds > FD_SETSIZE))
{
errno = EINVAL;
return -1;
}
#define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
#define IO_SELECT_TIMEOUT_REPLY_MSGID (21031 + 100) /* XXX */
if (timeout == NULL)
reply_msgid = IO_SELECT_REPLY_MSGID;
else
{
struct timespec now;
if (timeout->tv_sec < 0 || ! valid_nanoseconds (timeout->tv_nsec))
{
errno = EINVAL;
return -1;
}
err = __clock_gettime (CLOCK_REALTIME, &now);
if (err)
return -1;
ts.tv_sec = now.tv_sec + timeout->tv_sec;
ts.tv_nsec = now.tv_nsec + timeout->tv_nsec;
if (ts.tv_nsec >= 1000000000)
{
ts.tv_sec++;
ts.tv_nsec -= 1000000000;
}
if