hjl / source-git / glibc

Forked from source-git/glibc 3 years ago
Clone

Blame hurd/hurdselect.c

Packit 6c4009
/* Guts of both `select' and `poll' for Hurd.
Packit 6c4009
   Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <sys/poll.h>
Packit 6c4009
#include <hurd.h>
Packit 6c4009
#include <hurd/fd.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
Packit 6c4009
/* All user select types.  */
Packit 6c4009
#define SELECT_ALL (SELECT_READ | SELECT_WRITE | SELECT_URG)
Packit 6c4009
Packit 6c4009
/* Used to record that a particular select rpc returned.  Must be distinct
Packit 6c4009
   from SELECT_ALL (which better not have the high bit set).  */
Packit 6c4009
#define SELECT_RETURNED ((SELECT_ALL << 1) & ~SELECT_ALL)
Packit 6c4009
Packit 6c4009
/* Check the first NFDS descriptors either in POLLFDS (if nonnnull) or in
Packit 6c4009
   each of READFDS, WRITEFDS, EXCEPTFDS that is nonnull.  If TIMEOUT is not
Packit 6c4009
   NULL, time out after waiting the interval specified therein.  Returns
Packit 6c4009
   the number of ready descriptors, or -1 for errors.  */
Packit 6c4009
int
Packit 6c4009
_hurd_select (int nfds,
Packit 6c4009
	      struct pollfd *pollfds,
Packit 6c4009
	      fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
Packit 6c4009
	      const struct timespec *timeout, const sigset_t *sigmask)
Packit 6c4009
{
Packit 6c4009
  int i;
Packit 6c4009
  mach_port_t portset;
Packit 6c4009
  int got;
Packit 6c4009
  error_t err;
Packit 6c4009
  fd_set rfds, wfds, xfds;
Packit 6c4009
  int firstfd, lastfd;
Packit 6c4009
  mach_msg_timeout_t to = 0;
Packit 6c4009
  struct
Packit 6c4009
    {
Packit 6c4009
      struct hurd_userlink ulink;
Packit 6c4009
      struct hurd_fd *cell;
Packit 6c4009
      mach_port_t io_port;
Packit 6c4009
      int type;
Packit 6c4009
      mach_port_t reply_port;
Packit 6c4009
    } d[nfds];
Packit 6c4009
  sigset_t oset;
Packit 6c4009
Packit 6c4009
  union typeword		/* Use this to avoid unkosher casts.  */
Packit 6c4009
    {
Packit 6c4009
      mach_msg_type_t type;
Packit 6c4009
      uint32_t word;
Packit 6c4009
    };
Packit 6c4009
  assert (sizeof (union typeword) == sizeof (mach_msg_type_t));
Packit 6c4009
  assert (sizeof (uint32_t) == sizeof (mach_msg_type_t));
Packit 6c4009
Packit 6c4009
  if (nfds < 0 || (pollfds == NULL && nfds > FD_SETSIZE))
Packit 6c4009
    {
Packit 6c4009
      errno = EINVAL;
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (timeout != NULL)
Packit 6c4009
    {
Packit 6c4009
      if (timeout->tv_sec < 0 || timeout->tv_nsec < 0)
Packit 6c4009
	{
Packit 6c4009
	  errno = EINVAL;
Packit 6c4009
	  return -1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      to = (timeout->tv_sec * 1000 +
Packit 6c4009
            (timeout->tv_nsec + 999999) / 1000000);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (sigmask && __sigprocmask (SIG_SETMASK, sigmask, &oset))
Packit 6c4009
    return -1;
Packit 6c4009
Packit 6c4009
  if (pollfds)
Packit 6c4009
    {
Packit 6c4009
      /* Collect interesting descriptors from the user's `pollfd' array.
Packit 6c4009
	 We do a first pass that reads the user's array before taking
Packit 6c4009
	 any locks.  The second pass then only touches our own stack,
Packit 6c4009
	 and gets the port references.  */
Packit 6c4009
Packit 6c4009
      for (i = 0; i < nfds; ++i)
Packit 6c4009
	if (pollfds[i].fd >= 0)
Packit 6c4009
	  {
Packit 6c4009
	    int type = 0;
Packit 6c4009
	    if (pollfds[i].events & POLLIN)
Packit 6c4009
	      type |= SELECT_READ;
Packit 6c4009
	    if (pollfds[i].events & POLLOUT)
Packit 6c4009
	      type |= SELECT_WRITE;
Packit 6c4009
	    if (pollfds[i].events & POLLPRI)
Packit 6c4009
	      type |= SELECT_URG;
Packit 6c4009
Packit 6c4009
	    d[i].io_port = pollfds[i].fd;
Packit 6c4009
	    d[i].type = type;
Packit 6c4009
	  }
Packit 6c4009
	else
Packit 6c4009
	  d[i].type = 0;
Packit 6c4009
Packit 6c4009
      HURD_CRITICAL_BEGIN;
Packit 6c4009
      __mutex_lock (&_hurd_dtable_lock);
Packit 6c4009
Packit 6c4009
      for (i = 0; i < nfds; ++i)
Packit 6c4009
	if (d[i].type != 0)
Packit 6c4009
	  {
Packit 6c4009
	    const int fd = (int) d[i].io_port;
Packit 6c4009
Packit 6c4009
	    if (fd < _hurd_dtablesize)
Packit 6c4009
	      {
Packit 6c4009
		d[i].cell = _hurd_dtable[fd];
Packit 6c4009
		d[i].io_port = _hurd_port_get (&d[i].cell->port, &d[i].ulink);
Packit 6c4009
		if (d[i].io_port != MACH_PORT_NULL)
Packit 6c4009
		  continue;
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    /* If one descriptor is bogus, we fail completely.  */
Packit 6c4009
	    while (i-- > 0)
Packit 6c4009
	      if (d[i].type != 0)
Packit 6c4009
		_hurd_port_free (&d[i].cell->port,
Packit 6c4009
				 &d[i].ulink, d[i].io_port);
Packit 6c4009
	    break;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
      __mutex_unlock (&_hurd_dtable_lock);
Packit 6c4009
      HURD_CRITICAL_END;
Packit 6c4009
Packit 6c4009
      if (i < nfds)
Packit 6c4009
	{
Packit 6c4009
	  if (sigmask)
Packit 6c4009
	    __sigprocmask (SIG_SETMASK, &oset, NULL);
Packit 6c4009
	  errno = EBADF;
Packit 6c4009
	  return -1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      lastfd = i - 1;
Packit 6c4009
      firstfd = i == 0 ? lastfd : 0;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* Collect interested descriptors from the user's fd_set arguments.
Packit 6c4009
	 Use local copies so we can't crash from user bogosity.  */
Packit 6c4009
Packit 6c4009
      if (readfds == NULL)
Packit 6c4009
	FD_ZERO (&rfds);
Packit 6c4009
      else
Packit 6c4009
	rfds = *readfds;
Packit 6c4009
      if (writefds == NULL)
Packit 6c4009
	FD_ZERO (&wfds);
Packit 6c4009
      else
Packit 6c4009
	wfds = *writefds;
Packit 6c4009
      if (exceptfds == NULL)
Packit 6c4009
	FD_ZERO (&xfds);
Packit 6c4009
      else
Packit 6c4009
	xfds = *exceptfds;
Packit 6c4009
Packit 6c4009
      HURD_CRITICAL_BEGIN;
Packit 6c4009
      __mutex_lock (&_hurd_dtable_lock);
Packit 6c4009
Packit 6c4009
      if (nfds > _hurd_dtablesize)
Packit 6c4009
	nfds = _hurd_dtablesize;
Packit 6c4009
Packit 6c4009
      /* Collect the ports for interesting FDs.  */
Packit 6c4009
      firstfd = lastfd = -1;
Packit 6c4009
      for (i = 0; i < nfds; ++i)
Packit 6c4009
	{
Packit 6c4009
	  int type = 0;
Packit 6c4009
	  if (readfds != NULL && FD_ISSET (i, &rfds))
Packit 6c4009
	    type |= SELECT_READ;
Packit 6c4009
	  if (writefds != NULL && FD_ISSET (i, &wfds))
Packit 6c4009
	    type |= SELECT_WRITE;
Packit 6c4009
	  if (exceptfds != NULL && FD_ISSET (i, &xfds))
Packit 6c4009
	    type |= SELECT_URG;
Packit 6c4009
	  d[i].type = type;
Packit 6c4009
	  if (type)
Packit 6c4009
	    {
Packit 6c4009
	      d[i].cell = _hurd_dtable[i];
Packit 6c4009
	      d[i].io_port = _hurd_port_get (&d[i].cell->port, &d[i].ulink);
Packit 6c4009
	      if (d[i].io_port == MACH_PORT_NULL)
Packit 6c4009
		{
Packit 6c4009
		  /* If one descriptor is bogus, we fail completely.  */
Packit 6c4009
		  while (i-- > 0)
Packit 6c4009
		    if (d[i].type != 0)
Packit 6c4009
		      _hurd_port_free (&d[i].cell->port, &d[i].ulink,
Packit 6c4009
				       d[i].io_port);
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
	      lastfd = i;
Packit 6c4009
	      if (firstfd == -1)
Packit 6c4009
		firstfd = i;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      __mutex_unlock (&_hurd_dtable_lock);
Packit 6c4009
      HURD_CRITICAL_END;
Packit 6c4009
Packit 6c4009
      if (i < nfds)
Packit 6c4009
	{
Packit 6c4009
	  if (sigmask)
Packit 6c4009
	    __sigprocmask (SIG_SETMASK, &oset, NULL);
Packit 6c4009
	  errno = EBADF;
Packit 6c4009
	  return -1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
Packit 6c4009
  err = 0;
Packit 6c4009
  got = 0;
Packit 6c4009
Packit 6c4009
  /* Send them all io_select request messages.  */
Packit 6c4009
Packit 6c4009
  if (firstfd == -1)
Packit 6c4009
    /* But not if there were no ports to deal with at all.
Packit 6c4009
       We are just a pure timeout.  */
Packit 6c4009
    portset = __mach_reply_port ();
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      portset = MACH_PORT_NULL;
Packit 6c4009
Packit 6c4009
      for (i = firstfd; i <= lastfd; ++i)
Packit 6c4009
	if (d[i].type)
Packit 6c4009
	  {
Packit 6c4009
	    int type = d[i].type;
Packit 6c4009
	    d[i].reply_port = __mach_reply_port ();
Packit 6c4009
	    err = __io_select (d[i].io_port, d[i].reply_port,
Packit 6c4009
			       /* Poll only if there's a single descriptor.  */
Packit 6c4009
			       (firstfd == lastfd) ? to : 0,
Packit 6c4009
			       &type);
Packit 6c4009
	    switch (err)
Packit 6c4009
	      {
Packit 6c4009
	      case MACH_RCV_TIMED_OUT:
Packit 6c4009
		/* No immediate response.  This is normal.  */
Packit 6c4009
		err = 0;
Packit 6c4009
		if (firstfd == lastfd)
Packit 6c4009
		  /* When there's a single descriptor, we don't need a
Packit 6c4009
		     portset, so just pretend we have one, but really
Packit 6c4009
		     use the single reply port.  */
Packit 6c4009
		  portset = d[i].reply_port;
Packit 6c4009
		else if (got == 0)
Packit 6c4009
		  /* We've got multiple reply ports, so we need a port set to
Packit 6c4009
		     multiplex them.  */
Packit 6c4009
		  {
Packit 6c4009
		    /* We will wait again for a reply later.  */
Packit 6c4009
		    if (portset == MACH_PORT_NULL)
Packit 6c4009
		      /* Create the portset to receive all the replies on.  */
Packit 6c4009
		      err = __mach_port_allocate (__mach_task_self (),
Packit 6c4009
						  MACH_PORT_RIGHT_PORT_SET,
Packit 6c4009
						  &portset);
Packit 6c4009
		    if (! err)
Packit 6c4009
		      /* Put this reply port in the port set.  */
Packit 6c4009
		      __mach_port_move_member (__mach_task_self (),
Packit 6c4009
					       d[i].reply_port, portset);
Packit 6c4009
		  }
Packit 6c4009
		break;
Packit 6c4009
Packit 6c4009
	      default:
Packit 6c4009
		/* No other error should happen.  Callers of select
Packit 6c4009
		   don't expect to see errors, so we simulate
Packit 6c4009
		   readiness of the erring object and the next call
Packit 6c4009
		   hopefully will get the error again.  */
Packit 6c4009
		type = SELECT_ALL;
Packit 6c4009
		/* FALLTHROUGH */
Packit 6c4009
Packit 6c4009
	      case 0:
Packit 6c4009
		/* We got an answer.  */
Packit 6c4009
		if ((type & SELECT_ALL) == 0)
Packit 6c4009
		  /* Bogus answer; treat like an error, as a fake positive.  */
Packit 6c4009
		  type = SELECT_ALL;
Packit 6c4009
Packit 6c4009
		/* This port is already ready already.  */
Packit 6c4009
		d[i].type &= type;
Packit 6c4009
		d[i].type |= SELECT_RETURNED;
Packit 6c4009
		++got;
Packit 6c4009
		break;
Packit 6c4009
	      }
Packit 6c4009
	    _hurd_port_free (&d[i].cell->port, &d[i].ulink, d[i].io_port);
Packit 6c4009
	  }
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Now wait for reply messages.  */
Packit 6c4009
  if (!err && got == 0)
Packit 6c4009
    {
Packit 6c4009
      /* Now wait for io_select_reply messages on PORT,
Packit 6c4009
	 timing out as appropriate.  */
Packit 6c4009
Packit 6c4009
      union
Packit 6c4009
	{
Packit 6c4009
	  mach_msg_header_t head;
Packit 6c4009
#ifdef MACH_MSG_TRAILER_MINIMUM_SIZE
Packit 6c4009
	  struct
Packit 6c4009
	    {
Packit 6c4009
	      mach_msg_header_t head;
Packit 6c4009
	      NDR_record_t ndr;
Packit 6c4009
	      error_t err;
Packit 6c4009
	    } error;
Packit 6c4009
	  struct
Packit 6c4009
	    {
Packit 6c4009
	      mach_msg_header_t head;
Packit 6c4009
	      NDR_record_t ndr;
Packit 6c4009
	      error_t err;
Packit 6c4009
	      int result;
Packit 6c4009
	      mach_msg_trailer_t trailer;
Packit 6c4009
	    } success;
Packit 6c4009
#else
Packit 6c4009
	  struct
Packit 6c4009
	    {
Packit 6c4009
	      mach_msg_header_t head;
Packit 6c4009
	      union typeword err_type;
Packit 6c4009
	      error_t err;
Packit 6c4009
	    } error;
Packit 6c4009
	  struct
Packit 6c4009
	    {
Packit 6c4009
	      mach_msg_header_t head;
Packit 6c4009
	      union typeword err_type;
Packit 6c4009
	      error_t err;
Packit 6c4009
	      union typeword result_type;
Packit 6c4009
	      int result;
Packit 6c4009
	    } success;
Packit 6c4009
#endif
Packit 6c4009
	} msg;
Packit 6c4009
      mach_msg_option_t options = (timeout == NULL ? 0 : MACH_RCV_TIMEOUT);
Packit 6c4009
      error_t msgerr;
Packit 6c4009
      while ((msgerr = __mach_msg (&msg.head,
Packit 6c4009
				   MACH_RCV_MSG | MACH_RCV_INTERRUPT | options,
Packit 6c4009
				   0, sizeof msg, portset, to,
Packit 6c4009
				   MACH_PORT_NULL)) == MACH_MSG_SUCCESS)
Packit 6c4009
	{
Packit 6c4009
	  /* We got a message.  Decode it.  */
Packit 6c4009
#define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
Packit 6c4009
#ifdef MACH_MSG_TYPE_BIT
Packit 6c4009
	  const union typeword inttype =
Packit 6c4009
	  { type:
Packit 6c4009
	    { MACH_MSG_TYPE_INTEGER_T, sizeof (integer_t) * 8, 1, 1, 0, 0 }
Packit 6c4009
	  };
Packit 6c4009
#endif
Packit 6c4009
	  if (msg.head.msgh_id == IO_SELECT_REPLY_MSGID &&
Packit 6c4009
	      msg.head.msgh_size >= sizeof msg.error &&
Packit 6c4009
	      !(msg.head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
Packit 6c4009
#ifdef MACH_MSG_TYPE_BIT
Packit 6c4009
	      msg.error.err_type.word == inttype.word
Packit 6c4009
#endif
Packit 6c4009
	      )
Packit 6c4009
	    {
Packit 6c4009
	      /* This is a properly formatted message so far.
Packit 6c4009
		 See if it is a success or a failure.  */
Packit 6c4009
	      if (msg.error.err == EINTR &&
Packit 6c4009
		  msg.head.msgh_size == sizeof msg.error)
Packit 6c4009
		{
Packit 6c4009
		  /* EINTR response; poll for further responses
Packit 6c4009
		     and then return quickly.  */
Packit 6c4009
		  err = EINTR;
Packit 6c4009
		  goto poll;
Packit 6c4009
		}
Packit 6c4009
	      if (msg.error.err ||
Packit 6c4009
		  msg.head.msgh_size != sizeof msg.success ||
Packit 6c4009
#ifdef MACH_MSG_TYPE_BIT
Packit 6c4009
		  msg.success.result_type.word != inttype.word ||
Packit 6c4009
#endif
Packit 6c4009
		  (msg.success.result & SELECT_ALL) == 0)
Packit 6c4009
		{
Packit 6c4009
		  /* Error or bogus reply.  Simulate readiness.  */
Packit 6c4009
		  __mach_msg_destroy (&msg.head);
Packit 6c4009
		  msg.success.result = SELECT_ALL;
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      /* Look up the respondent's reply port and record its
Packit 6c4009
		 readiness.  */
Packit 6c4009
	      {
Packit 6c4009
		int had = got;
Packit 6c4009
		if (firstfd != -1)
Packit 6c4009
		  for (i = firstfd; i <= lastfd; ++i)
Packit 6c4009
		    if (d[i].type
Packit 6c4009
			&& d[i].reply_port == msg.head.msgh_local_port)
Packit 6c4009
		      {
Packit 6c4009
			d[i].type &= msg.success.result;
Packit 6c4009
			d[i].type |= SELECT_RETURNED;
Packit 6c4009
			++got;
Packit 6c4009
		      }
Packit 6c4009
		assert (got > had);
Packit 6c4009
	      }
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (msg.head.msgh_remote_port != MACH_PORT_NULL)
Packit 6c4009
	    __mach_port_deallocate (__mach_task_self (),
Packit 6c4009
				    msg.head.msgh_remote_port);
Packit 6c4009
Packit 6c4009
	  if (got)
Packit 6c4009
	  poll:
Packit 6c4009
	    {
Packit 6c4009
	      /* Poll for another message.  */
Packit 6c4009
	      to = 0;
Packit 6c4009
	      options |= MACH_RCV_TIMEOUT;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (msgerr == MACH_RCV_INTERRUPTED)
Packit 6c4009
	/* Interruption on our side (e.g. signal reception).  */
Packit 6c4009
	err = EINTR;
Packit 6c4009
Packit 6c4009
      if (got)
Packit 6c4009
	/* At least one descriptor is known to be ready now, so we will
Packit 6c4009
	   return success.  */
Packit 6c4009
	err = 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (firstfd != -1)
Packit 6c4009
    for (i = firstfd; i <= lastfd; ++i)
Packit 6c4009
      if (d[i].type)
Packit 6c4009
	__mach_port_destroy (__mach_task_self (), d[i].reply_port);
Packit 6c4009
  if (firstfd == -1 || (firstfd != lastfd && portset != MACH_PORT_NULL))
Packit 6c4009
    /* Destroy PORTSET, but only if it's not actually the reply port for a
Packit 6c4009
       single descriptor (in which case it's destroyed in the previous loop;
Packit 6c4009
       not doing it here is just a bit more efficient).  */
Packit 6c4009
    __mach_port_destroy (__mach_task_self (), portset);
Packit 6c4009
Packit 6c4009
  if (err)
Packit 6c4009
    {
Packit 6c4009
      if (sigmask)
Packit 6c4009
	__sigprocmask (SIG_SETMASK, &oset, NULL);
Packit 6c4009
      return __hurd_fail (err);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pollfds)
Packit 6c4009
    /* Fill in the `revents' members of the user's array.  */
Packit 6c4009
    for (i = 0; i < nfds; ++i)
Packit 6c4009
      {
Packit 6c4009
	int type = d[i].type;
Packit 6c4009
	int_fast16_t revents = 0;
Packit 6c4009
Packit 6c4009
	if (type & SELECT_RETURNED)
Packit 6c4009
	  {
Packit 6c4009
	    if (type & SELECT_READ)
Packit 6c4009
	      revents |= POLLIN;
Packit 6c4009
	    if (type & SELECT_WRITE)
Packit 6c4009
	      revents |= POLLOUT;
Packit 6c4009
	    if (type & SELECT_URG)
Packit 6c4009
	      revents |= POLLPRI;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	pollfds[i].revents = revents;
Packit 6c4009
      }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* Below we recalculate GOT to include an increment for each operation
Packit 6c4009
	 allowed on each fd.  */
Packit 6c4009
      got = 0;
Packit 6c4009
Packit 6c4009
      /* Set the user bitarrays.  We only ever have to clear bits, as all
Packit 6c4009
	 desired ones are initially set.  */
Packit 6c4009
      if (firstfd != -1)
Packit 6c4009
	for (i = firstfd; i <= lastfd; ++i)
Packit 6c4009
	  {
Packit 6c4009
	    int type = d[i].type;
Packit 6c4009
Packit 6c4009
	    if ((type & SELECT_RETURNED) == 0)
Packit 6c4009
	      type = 0;
Packit 6c4009
Packit 6c4009
	    if (type & SELECT_READ)
Packit 6c4009
	      got++;
Packit 6c4009
	    else if (readfds)
Packit 6c4009
	      FD_CLR (i, readfds);
Packit 6c4009
	    if (type & SELECT_WRITE)
Packit 6c4009
	      got++;
Packit 6c4009
	    else if (writefds)
Packit 6c4009
	      FD_CLR (i, writefds);
Packit 6c4009
	    if (type & SELECT_URG)
Packit 6c4009
	      got++;
Packit 6c4009
	    else if (exceptfds)
Packit 6c4009
	      FD_CLR (i, exceptfds);
Packit 6c4009
	  }
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (sigmask && __sigprocmask (SIG_SETMASK, &oset, NULL))
Packit 6c4009
    return -1;
Packit 6c4009
Packit 6c4009
  return got;
Packit 6c4009
}