summaryrefslogtreecommitdiff
path: root/sysdeps/mach/hurd/select.c
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 /sysdeps/mach/hurd/select.c
parent7885870df337869581a87f7308e40af7ad0285db (diff)
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.
Diffstat (limited to 'sysdeps/mach/hurd/select.c')
-rw-r--r--sysdeps/mach/hurd/select.c307
1 files changed, 8 insertions, 299 deletions
diff --git a/sysdeps/mach/hurd/select.c b/sysdeps/mach/hurd/select.c
index 904e1419ef..e58b542d0a 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)