aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1998-12-06 00:44:12 +0000
committerRoland McGrath <roland@gnu.org>1998-12-06 00:44:12 +0000
commit0d3eb016d62e69b1d13e7305faa2aafc247e99ad (patch)
treed2de284cd300d3cd4258f5eb4f56db1ada7421c5
parent7885870df337869581a87f7308e40af7ad0285db (diff)
downloadglibc-0d3eb016d62e69b1d13e7305faa2aafc247e99ad.zip
glibc-0d3eb016d62e69b1d13e7305faa2aafc247e99ad.tar.gz
glibc-0d3eb016d62e69b1d13e7305faa2aafc247e99ad.tar.bz2
1998-12-05 Roland McGrath <roland@baalperazim.frob.com>
* sysdeps/mach/hurd/pselect.c: New file. * sysdeps/mach/hurd/poll.c: New file. * hurd/Makefile (routines): Add hurdselect. * hurd/hurdselect.c: New file. (_hurd_select): New function, guts taken from ... * sysdeps/mach/hurd/select.c (__select): ... here. Now work by just calling _hurd_select. * hurd/hurd/fd.h: Declare _hurd_select. 1998-12-05 Roland McGrath <roland@baalperazim.frob.com> * time/strptime.c: Fix unterminated comment in last change. * argp/argp.h: Add __restrict.
-rw-r--r--ChangeLog19
-rw-r--r--hurd/Makefile2
-rw-r--r--hurd/hurd/fd.h16
-rw-r--r--hurd/hurdselect.c444
-rw-r--r--sysdeps/mach/hurd/pselect.c45
-rw-r--r--sysdeps/mach/hurd/select.c307
6 files changed, 531 insertions, 302 deletions
diff --git a/ChangeLog b/ChangeLog
index 70039a8..6d84569 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+1998-12-05 Roland McGrath <roland@baalperazim.frob.com>
+
+ * sysdeps/mach/hurd/pselect.c: New file.
+
+ * sysdeps/mach/hurd/poll.c: New file.
+
+ * hurd/Makefile (routines): Add hurdselect.
+ * hurd/hurdselect.c: New file.
+ (_hurd_select): New function, guts taken from ...
+ * sysdeps/mach/hurd/select.c (__select): ... here.
+ Now work by just calling _hurd_select.
+ * hurd/hurd/fd.h: Declare _hurd_select.
+
+1998-12-05 Roland McGrath <roland@baalperazim.frob.com>
+
+ * time/strptime.c: Fix unterminated comment in last change.
+
1998-12-05 Ulrich Drepper <drepper@cygnus.com>
* ctype/ctype.h (_ISbit): Protect use of parameter with
@@ -13,7 +30,7 @@
1998-12-04 Ulrich Drepper <drepper@cygnus.com>
- * argp/argp.h: Add __retrict.
+ * argp/argp.h: Add __restrict.
* dirent/dirent.h: Likewise.
* elf/dlfcn.h: Likewise.
* grp/grp.h: Likewise.
diff --git a/hurd/Makefile b/hurd/Makefile
index 250e441..07e22eb 100644
--- a/hurd/Makefile
+++ b/hurd/Makefile
@@ -41,7 +41,7 @@ user-interfaces := $(addprefix hurd/,\
server-interfaces := hurd/msg faultexc
routines = hurdstartup hurdinit \
- hurdid hurdlookup hurdpid hurdrlimit hurdprio hurdexec \
+ hurdid hurdlookup hurdpid hurdrlimit hurdprio hurdexec hurdselect \
get-host set-host \
path-lookup \
setauth \
diff --git a/hurd/hurd/fd.h b/hurd/hurd/fd.h
index 10fd563..aa48f21 100644
--- a/hurd/hurd/fd.h
+++ b/hurd/hurd/fd.h
@@ -1,5 +1,5 @@
/* File descriptors.
- Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1993,94,95,96,97,98 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
@@ -223,4 +223,18 @@ extern error_t _hurd_ctty_input (io_t port, io_t ctty, error_t (*rpc) (io_t));
extern error_t _hurd_ctty_output (io_t port, io_t ctty, error_t (*rpc) (io_t));
+/* The guts of `select' and `poll'. Check the first NFDS descriptors
+ either in POLLFDS (if nonnull) or in each of READFDS, WRITEFDS,
+ EXCEPTFDS that is nonnull. If TIMEOUT is not NULL, time out after
+ waiting the interval specified therein. If SIGMASK is nonnull,
+ the set of blocked signals is temporarily set to that during this call.
+ Returns the number of ready descriptors, or -1 for errors. */
+struct pollfd;
+struct timespec;
+extern 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);
+
+
#endif /* hurd/fd.h */
diff --git a/hurd/hurdselect.c b/hurd/hurdselect.c
new file mode 100644
index 0000000..e65def5
--- /dev/null
+++ b/hurd/hurdselect.c
@@ -0,0 +1,444 @@
+/* Guts of both `select' and `poll' for Hurd.
+ Copyright (C) 1991,92,93,94,95,96,97,98 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <hurd.h>
+#include <hurd/fd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.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)
+
+/* 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;
+ int got;
+ error_t err;
+ fd_set rfds, wfds, xfds;
+ int firstfd, lastfd;
+ mach_msg_timeout_t to = (timeout != NULL ?
+ (timeout->tv_sec * 1000 +
+ timeout->tv_nsec / 1000000) :
+ 0);
+ struct
+ {
+ struct hurd_userlink ulink;
+ struct hurd_fd *cell;
+ mach_port_t io_port;
+ int type;
+ mach_port_t reply_port;
+ } d[nfds];
+ sigset_t oset;
+
+ if (sigmask && __sigprocmask (SIG_SETMASK, sigmask, &oset))
+ return -1;
+
+ if (pollfds)
+ {
+ /* Collect interesting descriptors from the user's `pollfd' array.
+ We do a first pass that reads the user's array before taking
+ any locks. The second pass then only touches our own stack,
+ and gets the port references. */
+
+ for (i = 0; i < nfds; ++i)
+ if (pollfds[i].fd >= 0)
+ {
+ int type = 0;
+ if (pollfds[i].events & POLLIN)
+ type |= SELECT_READ;
+ if (pollfds[i].events & POLLOUT)
+ type |= SELECT_WRITE;
+ if (pollfds[i].events & POLLPRI)
+ type |= SELECT_URG;
+
+ d[i].io_port = pollfds[i].fd;
+ d[i].type = type;
+ }
+ else
+ d[i].type = 0;
+
+ HURD_CRITICAL_BEGIN;
+ __mutex_lock (&_hurd_dtable_lock);
+
+ for (i = 0; i < nfds; ++i)
+ if (d[i].type != 0)
+ {
+ const int fd = (int) d[i].io_port;
+
+ if (fd < _hurd_dtablesize)
+ {
+ d[i].cell = _hurd_dtable[fd];
+ d[i].io_port = _hurd_port_get (&d[i].cell->port, &d[i].ulink);
+ if (d[i].io_port != MACH_PORT_NULL)
+ continue;
+ }
+
+ /* If one descriptor is bogus, we fail completely. */
+ while (i-- > 0)
+ if (d[i].type != 0)
+ _hurd_port_free (&d[i].cell->port,
+ &d[i].ulink, d[i].io_port);
+ break;
+ }
+
+ __mutex_unlock (&_hurd_dtable_lock);
+ HURD_CRITICAL_END;
+
+ if (i < nfds)
+ {
+ if (sigmask)
+ __sigprocmask (SIG_SETMASK, &oset, NULL);
+ errno = EBADF;
+ return -1;
+ }
+
+ lastfd = i - 1;
+ firstfd = i == 0 ? lastfd : 0;
+ }
+ else
+ {
+ /* Collect interested descriptors from the user's fd_set arguments.
+ Use local copies so we can't crash from user bogosity. */
+
+ if (readfds == NULL)
+ FD_ZERO (&rfds);
+ else
+ rfds = *readfds;
+ if (writefds == NULL)
+ FD_ZERO (&wfds);
+ else
+ wfds = *writefds;
+ if (exceptfds == NULL)
+ FD_ZERO (&xfds);
+ else
+ xfds = *exceptfds;
+
+ HURD_CRITICAL_BEGIN;
+ __mutex_lock (&_hurd_dtable_lock);
+
+ if (nfds > _hurd_dtablesize)
+ nfds = _hurd_dtablesize;
+
+ /* Collect the ports for interesting FDs. */
+ firstfd = lastfd = -1;
+ for (i = 0; i < nfds; ++i)
+ {
+ int type = 0;
+ if (readfds != NULL && FD_ISSET (i, &rfds))
+ type |= SELECT_READ;
+ if (writefds != NULL && FD_ISSET (i, &wfds))
+ type |= SELECT_WRITE;
+ if (exceptfds != NULL && FD_ISSET (i, &xfds))
+ type |= SELECT_URG;
+ d[i].type = type;
+ if (type)
+ {
+ d[i].cell = _hurd_dtable[i];
+ d[i].io_port = _hurd_port_get (&d[i].cell->port, &d[i].ulink);
+ if (d[i].io_port == MACH_PORT_NULL)
+ {
+ /* If one descriptor is bogus, we fail completely. */
+ while (i-- > 0)
+ _hurd_port_free (&d[i].cell->port, &d[i].ulink,
+ d[i].io_port);
+ break;
+ }
+ lastfd = i;
+ if (firstfd == -1)
+ firstfd = i;
+ }
+ }
+
+ __mutex_unlock (&_hurd_dtable_lock);
+ HURD_CRITICAL_END;
+
+ if (i < nfds)
+ {
+ if (sigmask)
+ __sigprocmask (SIG_SETMASK, &oset, NULL);
+ errno = EBADF;
+ return -1;
+ }
+ }
+
+
+ err = 0;
+ got = 0;
+
+ /* Send them all io_select request messages. */
+
+ if (firstfd == -1)
+ /* But not if there were no ports to deal with at all.
+ We are just a pure timeout. */
+ portset = __mach_reply_port ();
+ else
+ {
+ portset = MACH_PORT_NULL;
+
+ for (i = firstfd; i <= lastfd; ++i)
+ if (d[i].type)
+ {
+ int type = d[i].type;
+ d[i].reply_port = __mach_reply_port ();
+ err = __io_select (d[i].io_port, d[i].reply_port,
+ /* Poll only if there's a single descriptor. */
+ (firstfd == lastfd) ? to : 0,
+ &type);
+ switch (err)
+ {
+ case MACH_RCV_TIMED_OUT:
+ /* No immediate response. This is normal. */
+ err = 0;
+ if (firstfd == lastfd)
+ /* When there's a single descriptor, we don't need a
+ portset, so just pretend we have one, but really
+ use the single reply port. */
+ portset = d[i].reply_port;
+ else if (got == 0)
+ /* We've got multiple reply ports, so we need a port set to
+ multiplex them. */
+ {
+ /* We will wait again for a reply later. */
+ if (portset == MACH_PORT_NULL)
+ /* Create the portset to receive all the replies on. */
+ err = __mach_port_allocate (__mach_task_self (),
+ MACH_PORT_RIGHT_PORT_SET,
+ &portset);
+ if (! err)
+ /* Put this reply port in the port set. */
+ __mach_port_move_member (__mach_task_self (),
+ d[i].reply_port, portset);
+ }
+ break;
+
+ default:
+ /* No other error should happen. Callers of select
+ don't expect to see errors, so we simulate
+ readiness of the erring object and the next call
+ hopefully will get the error again. */
+ type = SELECT_ALL;
+ /* FALLTHROUGH */
+
+ case 0:
+ /* We got an answer. */
+ if ((type & SELECT_ALL) == 0)
+ /* Bogus answer; treat like an error, as a fake positive. */
+ type = SELECT_ALL;
+
+ /* This port is already ready already. */
+ d[i].type &= type;
+ d[i].type |= SELECT_RETURNED;
+ ++got;
+ break;
+ }
+ _hurd_port_free (&d[i].cell->port, &d[i].ulink, d[i].io_port);
+ }
+ }
+
+ /* Now wait for reply messages. */
+ if (!err && got == 0)
+ {
+ /* Now wait for io_select_reply messages on PORT,
+ timing out as appropriate. */
+
+ union
+ {
+ mach_msg_header_t head;
+ struct
+ {
+ mach_msg_header_t head;
+ mach_msg_type_t err_type;
+ error_t err;
+ } error;
+ struct
+ {
+ mach_msg_header_t head;
+ mach_msg_type_t err_type;
+ error_t err;
+ mach_msg_type_t result_type;
+ int result;
+ } success;
+ } msg;
+ mach_msg_option_t options = (timeout == NULL ? 0 : MACH_RCV_TIMEOUT);
+ error_t msgerr;
+ while ((msgerr = __mach_msg (&msg.head,
+ MACH_RCV_MSG | options,
+ 0, sizeof msg, portset, to,
+ MACH_PORT_NULL)) == MACH_MSG_SUCCESS)
+ {
+ /* We got a message. Decode it. */
+#define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
+ const mach_msg_type_t inttype =
+ { MACH_MSG_TYPE_INTEGER_T, sizeof (MACH_MSG_TYPE_INTEGER_T) * 8,
+ 1, 1, 0, 0 };
+ if (msg.head.msgh_id == IO_SELECT_REPLY_MSGID &&
+ msg.head.msgh_size >= sizeof msg.error &&
+ !(msg.head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
+ *(int *) &msg.error.err_type == *(int *) &inttype)
+ {
+ /* This is a properly formatted message so far.
+ See if it is a success or a failure. */
+ if (msg.error.err == EINTR &&
+ msg.head.msgh_size == sizeof msg.error)
+ {
+ /* EINTR response; poll for further responses
+ and then return quickly. */
+ err = EINTR;
+ goto poll;
+ }
+ if (msg.error.err ||
+ msg.head.msgh_size != sizeof msg.success ||
+ *(int *) &msg.success.result_type != *(int *) &inttype ||
+ (msg.success.result & SELECT_ALL) == 0)
+ {
+ /* Error or bogus reply. Simulate readiness. */
+ __mach_msg_destroy (&msg.head);
+ msg.success.result = SELECT_ALL;
+ }
+
+ /* Look up the respondent's reply port and record its
+ readiness. */
+ {
+ int had = got;
+ if (firstfd != -1)
+ for (i = firstfd; i <= lastfd; ++i)
+ if (d[i].type
+ && d[i].reply_port == msg.head.msgh_local_port)
+ {
+ d[i].type &= msg.success.result;
+ d[i].type |= SELECT_RETURNED;
+ ++got;
+ }
+ assert (got > had);
+ }
+ }
+
+ if (msg.head.msgh_remote_port != MACH_PORT_NULL)
+ __mach_port_deallocate (__mach_task_self (),
+ msg.head.msgh_remote_port);
+
+ if (got)
+ poll:
+ {
+ /* Poll for another message. */
+ to = 0;
+ options |= MACH_RCV_TIMEOUT;
+ }
+ }
+
+ if (err == MACH_RCV_TIMED_OUT)
+ /* This is the normal value for ERR. We might have timed out and
+ read no messages. Otherwise, after receiving the first message,
+ we poll for more messages. We receive with a timeout of 0 to
+ effect a poll, so ERR is MACH_RCV_TIMED_OUT when the poll finds no
+ message waiting. */
+ err = 0;
+
+ if (got)
+ /* At least one descriptor is known to be ready now, so we will
+ return success. */
+ err = 0;
+ }
+
+ if (firstfd != -1)
+ for (i = firstfd; i <= lastfd; ++i)
+ if (d[i].type)
+ __mach_port_destroy (__mach_task_self (), d[i].reply_port);
+ if (firstfd == -1 || (firstfd != lastfd && portset != MACH_PORT_NULL))
+ /* Destroy PORTSET, but only if it's not actually the reply port for a
+ single descriptor (in which case it's destroyed in the previous loop;
+ not doing it here is just a bit more efficient). */
+ __mach_port_destroy (__mach_task_self (), portset);
+
+ if (err)
+ {
+ if (sigmask)
+ __sigprocmask (SIG_SETMASK, &oset, NULL);
+ return __hurd_fail (err);
+ }
+
+ if (pollfds)
+ /* Fill in the `revents' members of the user's array. */
+ for (i = 0; i < nfds; ++i)
+ {
+ const int type = d[i].type;
+ int_fast16_t revents = 0;
+
+ if (type & SELECT_READ)
+ revents |= POLLIN;
+ if (type & SELECT_WRITE)
+ revents |= POLLOUT;
+ if (type & SELECT_URG)
+ revents |= POLLPRI;
+
+ pollfds[i].revents = revents;
+ }
+ else
+ {
+ /* Below we recalculate GOT to include an increment for each operation
+ allowed on each fd. */
+ got = 0;
+
+ /* Set the user bitarrays. We only ever have to clear bits, as all
+ desired ones are initially set. */
+ if (firstfd != -1)
+ for (i = firstfd; i <= lastfd; ++i)
+ {
+ int type = d[i].type;
+
+ if ((type & SELECT_RETURNED) == 0)
+ type = 0;
+
+ if (type & SELECT_READ)
+ got++;
+ else if (readfds)
+ FD_CLR (i, readfds);
+ if (type & SELECT_WRITE)
+ got++;
+ else if (writefds)
+ FD_CLR (i, writefds);
+ if (type & SELECT_URG)
+ got++;
+ else if (exceptfds)
+ FD_CLR (i, exceptfds);
+ }
+ }
+
+ if (sigmask && __sigprocmask (SIG_SETMASK, &oset, NULL))
+ return -1;
+
+ return got;
+}
diff --git a/sysdeps/mach/hurd/pselect.c b/sysdeps/mach/hurd/pselect.c
new file mode 100644
index 0000000..6c0bc7b
--- /dev/null
+++ b/sysdeps/mach/hurd/pselect.c
@@ -0,0 +1,45 @@
+/* pselect for Hurd.
+ Copyright (C) 1998 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <hurd.h>
+#include <hurd/fd.h>
+
+/* Check the first NFDS descriptors each in READFDS (if not NULL) for read
+ readiness, in WRITEFDS (if not NULL) for write readiness, and in EXCEPTFDS
+ (if not NULL) for exceptional conditions. If TIMEOUT is not NULL, time out
+ after waiting the interval specified therein. Additionally set the sigmask
+ SIGMASK for this call. Returns the number of ready descriptors, or -1 for
+ errors. */
+int
+__pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask)
+ int nfds;
+ fd_set *readfds;
+ fd_set *writefds;
+ fd_set *exceptfds;
+ const struct timespec *timeout;
+ const sigset_t *sigmask;
+{
+ return _hurd_select (nfds, NULL,
+ readfds, writefds, exceptfds, timeout, sigmask);
+}
+weak_alias (__pselect, pselect)
diff --git a/sysdeps/mach/hurd/select.c b/sysdeps/mach/hurd/select.c
index 904e141..e58b542 100644
--- a/sysdeps/mach/hurd/select.c
+++ b/sysdeps/mach/hurd/select.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
+/* Copyright (C) 1991,92,93,94,95,96,97,98 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
@@ -17,18 +17,9 @@
Boston, MA 02111-1307, USA. */
#include <sys/types.h>
+#include <sys/time.h>
#include <hurd.h>
#include <hurd/fd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.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)
/* Check the first NFDS descriptors each in READFDS (if not NULL) for read
readiness, in WRITEFDS (if not NULL) for write readiness, and in EXCEPTFDS
@@ -43,299 +34,17 @@ __select (nfds, readfds, writefds, exceptfds, timeout)
fd_set *exceptfds;
struct timeval *timeout;
{
- int i;
- mach_port_t portset;
- int got;
- error_t err;
- fd_set rfds, wfds, xfds;
- int firstfd, lastfd;
- mach_msg_timeout_t to = (timeout != NULL ?
- (timeout->tv_sec * 1000 +
- timeout->tv_usec / 1000) :
- 0);
- struct
- {
- struct hurd_userlink ulink;
- struct hurd_fd *cell;
- mach_port_t io_port;
- int type;
- mach_port_t reply_port;
- } d[nfds];
-
- /* Use local copies so we can't crash from user bogosity. */
- if (readfds == NULL)
- FD_ZERO (&rfds);
- else
- rfds = *readfds;
- if (writefds == NULL)
- FD_ZERO (&wfds);
- else
- wfds = *writefds;
- if (exceptfds == NULL)
- FD_ZERO (&xfds);
- else
- xfds = *exceptfds;
-
- HURD_CRITICAL_BEGIN;
- __mutex_lock (&_hurd_dtable_lock);
-
- if (nfds > _hurd_dtablesize)
- nfds = _hurd_dtablesize;
+ struct timespec ts, *to;
- /* Collect the ports for interesting FDs. */
- firstfd = lastfd = -1;
- for (i = 0; i < nfds; ++i)
+ if (timeout)
{
- int type = 0;
- if (readfds != NULL && FD_ISSET (i, &rfds))
- type |= SELECT_READ;
- if (writefds != NULL && FD_ISSET (i, &wfds))
- type |= SELECT_WRITE;
- if (exceptfds != NULL && FD_ISSET (i, &xfds))
- type |= SELECT_URG;
- d[i].type = type;
- if (type)
- {
- d[i].cell = _hurd_dtable[i];
- d[i].io_port = _hurd_port_get (&d[i].cell->port, &d[i].ulink);
- if (d[i].io_port == MACH_PORT_NULL)
- {
- /* If one descriptor is bogus, we fail completely. */
- while (i-- > 0)
- _hurd_port_free (&d[i].cell->port, &d[i].ulink, d[i].io_port);
- errno = EBADF;
- break;
- }
- lastfd = i;
- if (firstfd == -1)
- firstfd = i;
- }
+ to = &ts;
+ TIMEVAL_TO_TIMESPEC (timeout, to);
}
-
- __mutex_unlock (&_hurd_dtable_lock);
- HURD_CRITICAL_END;
-
- if (i < nfds)
- return -1;
-
- /* Send them all io_select request messages. */
-
- if (firstfd == -1)
- /* But not if there were no ports to deal with at all. */
- portset = __mach_reply_port ();
else
- {
- err = 0;
- got = 0;
- portset = MACH_PORT_NULL;
-
- for (i = firstfd; i <= lastfd; ++i)
- if (d[i].type)
- {
- int type = d[i].type;
- d[i].reply_port = __mach_reply_port ();
- err = __io_select (d[i].io_port, d[i].reply_port,
- /* Poll only if there's a single descriptor. */
- (firstfd == lastfd) ? to : 0,
- &type);
- switch (err)
- {
- case MACH_RCV_TIMED_OUT:
- /* No immediate response. This is normal. */
- err = 0;
- if (firstfd == lastfd)
- /* When there's a single descriptor, we don't need a
- portset, so just pretend we have one, but really
- use the single reply port. */
- portset = d[i].reply_port;
- else if (got == 0)
- /* We've got multiple reply ports, so we need a port set to
- multiplex them. */
- {
- /* We will wait again for a reply later. */
- if (portset == MACH_PORT_NULL)
- /* Create the portset to receive all the replies on. */
- err = __mach_port_allocate (__mach_task_self (),
- MACH_PORT_RIGHT_PORT_SET,
- &portset);
- if (! err)
- /* Put this reply port in the port set. */
- __mach_port_move_member (__mach_task_self (),
- d[i].reply_port, portset);
- }
- break;
-
- default:
- /* No other error should happen. Callers of select
- don't expect to see errors, so we simulate
- readiness of the erring object and the next call
- hopefully will get the error again. */
- type = SELECT_ALL;
- /* FALLTHROUGH */
-
- case 0:
- /* We got an answer. */
- if ((type & SELECT_ALL) == 0)
- /* Bogus answer; treat like an error, as a fake positive. */
- type = SELECT_ALL;
-
- /* This port is already ready already. */
- d[i].type &= type;
- d[i].type |= SELECT_RETURNED;
- ++got;
- break;
- }
- _hurd_port_free (&d[i].cell->port, &d[i].ulink, d[i].io_port);
- }
- }
-
- /* Now wait for reply messages. */
- if (!err && got == 0)
- {
- /* Now wait for io_select_reply messages on PORT,
- timing out as appropriate. */
-
- union
- {
- mach_msg_header_t head;
- struct
- {
- mach_msg_header_t head;
- mach_msg_type_t err_type;
- error_t err;
- } error;
- struct
- {
- mach_msg_header_t head;
- mach_msg_type_t err_type;
- error_t err;
- mach_msg_type_t result_type;
- int result;
- } success;
- } msg;
- mach_msg_option_t options = (timeout == NULL ? 0 : MACH_RCV_TIMEOUT);
- error_t msgerr;
- while ((msgerr = __mach_msg (&msg.head,
- MACH_RCV_MSG | options,
- 0, sizeof msg, portset, to,
- MACH_PORT_NULL)) == MACH_MSG_SUCCESS)
- {
- /* We got a message. Decode it. */
-#define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
- const mach_msg_type_t inttype =
- { MACH_MSG_TYPE_INTEGER_T, sizeof (MACH_MSG_TYPE_INTEGER_T) * 8,
- 1, 1, 0, 0 };
- if (msg.head.msgh_id == IO_SELECT_REPLY_MSGID &&
- msg.head.msgh_size >= sizeof msg.error &&
- !(msg.head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
- *(int *) &msg.error.err_type == *(int *) &inttype)
- {
- /* This is a properly formatted message so far.
- See if it is a success or a failure. */
- if (msg.error.err == EINTR &&
- msg.head.msgh_size == sizeof msg.error)
- {
- /* EINTR response; poll for further responses
- and then return quickly. */
- err = EINTR;
- goto poll;
- }
- if (msg.error.err ||
- msg.head.msgh_size != sizeof msg.success ||
- *(int *) &msg.success.result_type != *(int *) &inttype ||
- (msg.success.result & SELECT_ALL) == 0)
- {
- /* Error or bogus reply. Simulate readiness. */
- __mach_msg_destroy (&msg.head);
- msg.success.result = SELECT_ALL;
- }
-
- /* Look up the respondent's reply port and record its
- readiness. */
- {
- int had = got;
- if (firstfd != -1)
- for (i = firstfd; i <= lastfd; ++i)
- if (d[i].type
- && d[i].reply_port == msg.head.msgh_local_port)
- {
- d[i].type &= msg.success.result;
- d[i].type |= SELECT_RETURNED;
- ++got;
- }
- assert (got > had);
- }
- }
-
- if (msg.head.msgh_remote_port != MACH_PORT_NULL)
- __mach_port_deallocate (__mach_task_self (),
- msg.head.msgh_remote_port);
-
- if (got)
- poll:
- {
- /* Poll for another message. */
- to = 0;
- options |= MACH_RCV_TIMEOUT;
- }
- }
-
- if (err == MACH_RCV_TIMED_OUT)
- /* This is the normal value for ERR. We might have timed out and
- read no messages. Otherwise, after receiving the first message,
- we poll for more messages. We receive with a timeout of 0 to
- effect a poll, so ERR is MACH_RCV_TIMED_OUT when the poll finds no
- message waiting. */
- err = 0;
-
- if (got)
- /* At least one descriptor is known to be ready now, so we will
- return success. */
- err = 0;
- }
-
- if (firstfd != -1)
- for (i = firstfd; i <= lastfd; ++i)
- if (d[i].type)
- __mach_port_destroy (__mach_task_self (), d[i].reply_port);
- if (firstfd == -1 || (firstfd != lastfd && portset != MACH_PORT_NULL))
- /* Destroy PORTSET, but only if it's not actually the reply port for a
- single descriptor (in which case it's destroyed in the previous loop;
- not doing it here is just a bit more efficient). */
- __mach_port_destroy (__mach_task_self (), portset);
-
- if (err)
- return __hurd_fail (err);
-
- /* Below we recalculate GOT to include an increment for each operation
- allowed on each fd. */
- got = 0;
-
- /* Set the user bitarrays. We only ever have to clear bits, as all desired
- ones are initially set. */
- if (firstfd != -1)
- for (i = firstfd; i <= lastfd; ++i)
- {
- int type = d[i].type;
-
- if ((type & SELECT_RETURNED) == 0)
- type = 0;
-
- if (type & SELECT_READ)
- got++;
- else if (readfds)
- FD_CLR (i, readfds);
- if (type & SELECT_WRITE)
- got++;
- else if (writefds)
- FD_CLR (i, writefds);
- if (type & SELECT_URG)
- got++;
- else if (exceptfds)
- FD_CLR (i, exceptfds);
- }
+ to = NULL;
- return got;
+ return _hurd_select (nfds, NULL, readfds, writefds, exceptfds, to, NULL);
}
weak_alias (__select, select)