Back to index

glibc  2.9
Classes | Defines | Functions | Variables
fd.h File Reference
#include <features.h>
#include <cthreads.h>
#include <hurd/hurd_types.h>
#include <hurd/port.h>
#include <sys/socket.h>
#include <hurd/signal.h>
#include <errno.h>

Go to the source code of this file.

Classes

struct  hurd_fd

Defines

#define _HURD_FD_H_EXTERN_INLINE   __extern_inline
#define HURD_FD_USE(fd, expr)
#define HURD_DPORT_USE(fd, expr)   HURD_FD_USE ((fd), HURD_FD_PORT_USE (descriptor, (expr)))
#define HURD_FD_PORT_USE(fd, expr)

Functions

_HURD_FD_H_EXTERN_INLINE
struct hurd_fd
_hurd_fd_get (int fd)
_HURD_FD_H_EXTERN_INLINE int _hurd_fd_error_signal (error_t err)
_HURD_FD_H_EXTERN_INLINE error_t _hurd_fd_error (int fd, error_t err)
_HURD_FD_H_EXTERN_INLINE int __hurd_dfail (int fd, error_t err)
_HURD_FD_H_EXTERN_INLINE int __hurd_sockfail (int fd, int flags, error_t err)
void _hurd_port2fd (struct hurd_fd *fd, io_t port, int flags)
int _hurd_intern_fd (io_t port, int flags, int dealloc)
struct hurd_fd_hurd_alloc_fd (int *fd_ptr, int first_fd)
struct hurd_fd_hurd_new_fd (io_t port, io_t ctty)
error_t _hurd_fd_close (struct hurd_fd *fd)
error_t _hurd_fd_read (struct hurd_fd *fd, void *buf, size_t *nbytes, loff_t offset)
error_t _hurd_fd_write (struct hurd_fd *fd, const void *buf, size_t *nbytes, loff_t offset)
error_t _hurd_ctty_input (io_t port, io_t ctty, error_t(*rpc)(io_t))
error_t _hurd_ctty_output (io_t port, io_t ctty, error_t(*rpc)(io_t))
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)
file_t __file_name_lookup_at (int fd, int at_flags, const char *file_name, int flags, mode_t mode)
file_t __file_name_split_at (int fd, const char *file_name, char **name)
file_t __directory_name_split_at (int fd, const char *directory_name, char **name)

Variables

int _hurd_dtablesize
struct hurd_fd ** _hurd_dtable

Class Documentation

struct hurd_fd

Definition at line 35 of file fd.h.

Class Members
int flags

Define Documentation

Definition at line 56 of file fd.h.

#define HURD_DPORT_USE (   fd,
  expr 
)    HURD_FD_USE ((fd), HURD_FD_PORT_USE (descriptor, (expr)))

Definition at line 105 of file fd.h.

#define HURD_FD_PORT_USE (   fd,
  expr 
)
Value:
({ error_t __result;                                                 \
     struct hurd_fd *const __d = (fd);                                      \
     struct hurd_userlink __ulink, __ctty_ulink;                     \
     io_t port, ctty;                                                       \
     void *crit = _hurd_critical_section_lock ();                           \
     __spin_lock (&__d->port.lock);                                         \
     if (__d->port.port == MACH_PORT_NULL)                                  \
       {                                                             \
        __spin_unlock (&__d->port.lock);                             \
        _hurd_critical_section_unlock (crit);                               \
        __result = EBADF;                                            \
       }                                                             \
     else                                                            \
       {                                                             \
        ctty = _hurd_port_get (&__d->ctty, &__ctty_ulink);                  \
        port = _hurd_port_locked_get (&__d->port, &__ulink);                \
        _hurd_critical_section_unlock (crit);                               \
        __result = (expr);                                           \
        _hurd_port_free (&__d->port, &__ulink, port);                       \
        if (ctty != MACH_PORT_NULL)                                         \
          _hurd_port_free (&__d->ctty, &__ctty_ulink, ctty);                \
       }                                                             \
     __result; })

Definition at line 110 of file fd.h.

#define HURD_FD_USE (   fd,
  expr 
)
Value:
({ struct hurd_fd *descriptor = _hurd_fd_get (fd);                          \
     descriptor == NULL ? EBADF : (expr); })

Definition at line 98 of file fd.h.


Function Documentation

file_t __directory_name_split_at ( int  fd,
const char *  directory_name,
char **  name 
)

Definition at line 88 of file lookup-at.c.

{
  error_t err;
  file_t result;

  if (fd == AT_FDCWD || directory_name[0] == '/')
    return __directory_name_split (directory_name, name);

  file_t startdir;
  error_t use_init_port (int which, error_t (*operate) (mach_port_t))
    {
      return (which == INIT_PORT_CWDIR ? (*operate) (startdir) :
             _hurd_ports_use (which, operate));
    }

  err = HURD_DPORT_USE (fd, (startdir = port,
                          __hurd_directory_name_split (&use_init_port,
                                                   &__getdport, 0,
                                                   directory_name,
                                                   &result, name)));

  return err ? (__hurd_dfail (fd, err), MACH_PORT_NULL) : result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

file_t __file_name_lookup_at ( int  fd,
int  at_flags,
const char *  file_name,
int  flags,
mode_t  mode 
)

Definition at line 27 of file lookup-at.c.

{
  error_t err;
  file_t result;

  flags |= (at_flags & AT_SYMLINK_NOFOLLOW) ? O_NOLINK : 0;
  at_flags &= ~AT_SYMLINK_NOFOLLOW;
  if (at_flags != 0)
    return __hurd_fail (EINVAL);

  if (fd == AT_FDCWD || file_name[0] == '/')
    return __file_name_lookup (file_name, flags, mode);

  file_t startdir;
  error_t use_init_port (int which, error_t (*operate) (mach_port_t))
    {
      return (which == INIT_PORT_CWDIR ? (*operate) (startdir) :
             _hurd_ports_use (which, operate));
    }

  err = HURD_DPORT_USE (fd, (startdir = port,
                          __hurd_file_name_lookup (&use_init_port,
                                                &__getdport, NULL,
                                                file_name,
                                                flags,
                                                mode & ~_hurd_umask,
                                                &result)));

  return err ? (__hurd_dfail (fd, err), MACH_PORT_NULL) : result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

file_t __file_name_split_at ( int  fd,
const char *  file_name,
char **  name 
)

Definition at line 60 of file lookup-at.c.

{
  error_t err;
  file_t result;

  if (fd == AT_FDCWD || file_name[0] == '/')
    return __file_name_split (file_name, name);

  err = __hurd_file_name_split (&_hurd_ports_use, &__getdport, 0,
                            file_name, &result, name);

  file_t startdir;
  error_t use_init_port (int which, error_t (*operate) (mach_port_t))
  {
    return (which == INIT_PORT_CWDIR ? (*operate) (startdir) :
           _hurd_ports_use (which, operate));
  }

  err = HURD_DPORT_USE (fd, (startdir = port,
                          __hurd_file_name_split (&use_init_port,
                                               &__getdport, 0,
                                               file_name,
                                               &result, name)));

  return err ? (__hurd_dfail (fd, err), MACH_PORT_NULL) : result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 178 of file fd.h.

{
  errno = _hurd_fd_error (fd, err);
  return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 188 of file fd.h.

{
  if (!(flags & MSG_NOSIGNAL) || err != EPIPE)
    err = _hurd_fd_error (fd, err);
  errno = err;
  return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct hurd_fd* _hurd_alloc_fd ( int fd_ptr,
int  first_fd 
) [read]

Definition at line 31 of file alloc-fd.c.

{
  int i;
  void *crit;
  long int rlimit;

  if (first_fd < 0)
    {
      errno = EINVAL;
      return NULL;
    }

  crit = _hurd_critical_section_lock ();

  __mutex_lock (&_hurd_dtable_lock);

 search:
  for (i = first_fd; i < _hurd_dtablesize; ++i)
    {
      struct hurd_fd *d = _hurd_dtable[i];
      if (d == NULL)
       {
         /* Allocate a new descriptor structure for this slot,
            initializing its port cells to nil.  The test below will catch
            and return this descriptor cell after locking it.  */
         d = _hurd_new_fd (MACH_PORT_NULL, MACH_PORT_NULL);
         if (d == NULL)
           {
             __mutex_unlock (&_hurd_dtable_lock);
             _hurd_critical_section_unlock (crit);
             return NULL;
           }
         _hurd_dtable[i] = d;
       }

      __spin_lock (&d->port.lock);
      if (d->port.port == MACH_PORT_NULL)
       {
         __mutex_unlock (&_hurd_dtable_lock);
         _hurd_critical_section_unlock (crit);
         if (fd != NULL)
           *fd = i;
         return d;
       }
      else
       __spin_unlock (&d->port.lock);
    }

  __mutex_lock (&_hurd_rlimit_lock);
  rlimit = _hurd_rlimits[RLIMIT_OFILE].rlim_cur;
  __mutex_unlock (&_hurd_rlimit_lock);

  if (first_fd < rlimit)
    {
      /* The descriptor table is full.  Check if we have reached the
        resource limit, or only the allocated size.  */
      if (_hurd_dtablesize < rlimit)
       {
         /* Enlarge the table.  */
         int save = errno;
         struct hurd_fd **new;
         /* Try to double the table size, but don't exceed the limit,
            and make sure it exceeds FIRST_FD.  */
         int size = _hurd_dtablesize * 2;
         if (size > rlimit)
           size = rlimit;
         else if (size <= first_fd)
           size = first_fd + 1;

         if (size * sizeof (*_hurd_dtable) < size)
           {
             /* Integer overflow! */
             errno = ENOMEM;
             goto out;
           }

         /* If we fail to allocate that, decrement the desired size
            until we succeed in allocating it.  */
         do
           new = realloc (_hurd_dtable, size * sizeof (*_hurd_dtable));
         while (new == NULL && size-- > first_fd);

         if (new != NULL)
           {
             /* We managed to allocate a new table.  Now install it.  */
             errno = save;
             if (first_fd < _hurd_dtablesize)
              first_fd = _hurd_dtablesize;
             /* Initialize the new slots.  */
             for (i = _hurd_dtablesize; i < size; ++i)
              new[i] = NULL;
             _hurd_dtablesize = size;
             _hurd_dtable = new;
             /* Go back to the loop to initialize the first new slot.  */
             goto search;
           }
         else
           errno = ENOMEM;
       }
      else
       errno = EMFILE;
    }
  else
    errno = EINVAL;         /* Bogus FIRST_FD value.  */

 out:
  __mutex_unlock (&_hurd_dtable_lock);
  _hurd_critical_section_unlock (crit);

  return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

error_t _hurd_ctty_input ( io_t  port,
io_t  ctty,
error_t(*)(io_t)  rpc 
)

Definition at line 27 of file ctty-input.c.

{
  error_t err;

  if (ctty == MACH_PORT_NULL)
    return (*rpc) (port);

  do
    {
      err = (*rpc) (ctty);
      if (err == EBACKGROUND)
       {
         /* We are a background job and tried to read from the tty.
            We should probably get a SIGTTIN signal.  */
         if (_hurd_orphaned)
           /* Our process group is orphaned.  Don't stop; just fail.  */
           err = EIO;
         else
           {
             struct hurd_sigstate *ss = _hurd_self_sigstate ();
             __spin_lock (&ss->lock);
             if (__sigismember (&ss->blocked, SIGTTIN) ||
                ss->actions[SIGTTIN].sa_handler == SIG_IGN)
              /* We are blocking or ignoring SIGTTIN.  Just fail.  */
              err = EIO;
             __spin_unlock (&ss->lock);

             if (err == EBACKGROUND)
              {
                /* Send a SIGTTIN signal to our process group.

                   We must remember here not to clobber ERR, since
                   the loop condition below uses it to recall that
                we should retry after a stop.  */

                __USEPORT (CTTYID, _hurd_sig_post (0, SIGTTIN, port));
                /* XXX what to do if error here? */

                /* At this point we should have just run the handler for
                   SIGTTIN or resumed after being stopped.  Now this is
                   still a "system call", so check to see if we should
                restart it.  */
                __spin_lock (&ss->lock);
                if (!(ss->actions[SIGTTIN].sa_flags & SA_RESTART))
                  err = EINTR;
                __spin_unlock (&ss->lock);
              }
           }
       }
      /* If the last RPC generated a SIGTTIN, loop to try it again.  */
    } while (err == EBACKGROUND);

  return err;
}

Here is the call graph for this function:

Here is the caller graph for this function:

error_t _hurd_ctty_output ( io_t  port,
io_t  ctty,
error_t(*)(io_t)  rpc 
)

Definition at line 27 of file ctty-output.c.

{
  if (ctty == MACH_PORT_NULL)
    return (*rpc) (port);
  else
    {
      struct hurd_sigstate *ss = _hurd_self_sigstate ();
      error_t err;

      do
       {
         /* Don't use the ctty io port if we are blocking or ignoring
            SIGTTOU.  We redo this check at the top of the loop in case
            the signal handler changed the state.  */
         __spin_lock (&ss->lock);
         if (__sigismember (&ss->blocked, SIGTTOU) ||
             ss->actions[SIGTTOU].sa_handler == SIG_IGN)
           err = EIO;
         else
           err = 0;
         __spin_unlock (&ss->lock);

         if (err)
           return (*rpc) (port);

         err = (*rpc) (ctty);
         if (err == EBACKGROUND)
           {
             if (_hurd_orphaned)
              /* Our process group is orphaned, so we never generate a
                 signal; we just fail.  */
              err = EIO;
             else
              {
                /* Send a SIGTTOU signal to our process group.

                   We must remember here not to clobber ERR, since
                   the loop condition below uses it to recall that
                we should retry after a stop.  */

                __USEPORT (CTTYID, _hurd_sig_post (0, SIGTTOU, port));
                /* XXX what to do if error here? */

                /* At this point we should have just run the handler for
                   SIGTTOU or resumed after being stopped.  Now this is
                   still a "system call", so check to see if we should
                restart it.  */
                __spin_lock (&ss->lock);
                if (!(ss->actions[SIGTTOU].sa_flags & SA_RESTART))
                  err = EINTR;
                __spin_unlock (&ss->lock);
              }
           }
         /* If the last RPC generated a SIGTTOU, loop to try it again.  */
       } while (err == EBACKGROUND);

      return err;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

error_t _hurd_fd_close ( struct hurd_fd fd)

Definition at line 22 of file fd-close.c.

{
  error_t err;

  HURD_CRITICAL_BEGIN;

  __spin_lock (&fd->port.lock);
  if (fd->port.port == MACH_PORT_NULL)
    {
      __spin_unlock (&fd->port.lock);
      err = EBADF;
    }
  else
    {
      /* Clear the descriptor's port cells.
        This deallocates the ports if noone else is still using them.  */
      _hurd_port_set (&fd->ctty, MACH_PORT_NULL);
      _hurd_port_locked_set (&fd->port, MACH_PORT_NULL);
      err = 0;
    }

  HURD_CRITICAL_END;

  return err;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 162 of file fd.h.

{
  int signo = _hurd_fd_error_signal (err);
  if (signo)
    {
      const struct hurd_signal_detail detail
       = { code: fd, error: err, exc: 0 };
      _hurd_raise_signal (NULL, signo, &detail);
    }
  return err;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 141 of file fd.h.

{
  switch (err)
    {
    case EMACH_SEND_INVALID_DEST:
    case EMIG_SERVER_DIED:
      /* The server has disappeared!  */
      return SIGLOST;
    case EPIPE:
      return SIGPIPE;
    default:
      /* Having a default case avoids -Wenum-switch warnings.  */
      return 0;
    }
}

Here is the caller graph for this function:

Definition at line 64 of file fd.h.

{
  struct hurd_fd *descriptor;

  __mutex_lock (&_hurd_dtable_lock);
  if (fd < 0 || fd >= _hurd_dtablesize)
    descriptor = NULL;
  else
    {
      struct hurd_fd *cell = _hurd_dtable[fd];
      if (cell == NULL)
       /* No descriptor allocated at this index.  */
       descriptor = NULL;
      else
       {
         __spin_lock (&cell->port.lock);
         if (cell->port.port == MACH_PORT_NULL)
           /* The descriptor at this index has no port in it.
              This happens if it existed before but was closed.  */
           descriptor = NULL;
         else
           descriptor = cell;
         __spin_unlock (&cell->port.lock);
       }
    }
  __mutex_unlock (&_hurd_dtable_lock);

  return descriptor;
}

Here is the call graph for this function:

Here is the caller graph for this function:

error_t _hurd_fd_read ( struct hurd_fd fd,
void *  buf,
size_t nbytes,
loff_t  offset 
)

Definition at line 26 of file fd-read.c.

{
  error_t err;
  char *data;
  mach_msg_type_number_t nread;

  error_t readfd (io_t port)
    {
      return __io_read (port, &data, &nread, offset, *nbytes);
    }

  data = buf;
  nread = *nbytes;
  if (err = HURD_FD_PORT_USE (fd, _hurd_ctty_input (port, ctty, readfd)))
    return err;

  if (data != buf)
    {
      if (nread > *nbytes)  /* Sanity check for bogus server.  */
       {
         __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
         return EGRATUITOUS;
       }
      memcpy (buf, data, nread);
      __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
    }

  *nbytes = nread;
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

error_t _hurd_fd_write ( struct hurd_fd fd,
const void *  buf,
size_t nbytes,
loff_t  offset 
)

Definition at line 26 of file fd-write.c.

{
  error_t err;
  mach_msg_type_number_t wrote;

  error_t writefd (io_t port)
    {
      return __io_write (port, buf, *nbytes, offset, &wrote);
    }

  err = HURD_FD_PORT_USE (fd, _hurd_ctty_output (port, ctty, writefd));

  if (! err)
    *nbytes = wrote;

  return err;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int _hurd_intern_fd ( io_t  port,
int  flags,
int  dealloc 
)

Definition at line 28 of file intern-fd.c.

{
  int fd;
  struct hurd_fd *d;

  HURD_CRITICAL_BEGIN;
  d = _hurd_alloc_fd (&fd, 0);
  if (d != NULL)
    {
      _hurd_port2fd (d, port, flags);
      __spin_unlock (&d->port.lock);
    }
  HURD_CRITICAL_END;

  if (d == NULL)
    {
      if (dealloc)
       __mach_port_deallocate (__mach_task_self (), port);
      return -1;
    }

  return fd;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct hurd_fd* _hurd_new_fd ( io_t  port,
io_t  ctty 
) [read]

Definition at line 27 of file new-fd.c.

{
  struct hurd_fd *d = malloc (sizeof (struct hurd_fd));

  if (d != NULL)
    {
      /* Initialize the port cells.  */
      _hurd_port_init (&d->port, port);
      _hurd_port_init (&d->ctty, ctty);
      
      /* And the fcntl flags.  */
      d->flags = 0;
    }

  return d;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _hurd_port2fd ( struct hurd_fd fd,
io_t  port,
int  flags 
)

Definition at line 30 of file port2fd.c.

{
  mach_port_t cttyid;
  io_t ctty = MACH_PORT_NULL;

  if (!(flags & O_IGNORE_CTTY))
    __USEPORT (CTTYID,
              ({
               if (port != MACH_PORT_NULL && /* Do we have a ctty? */
                   ! __term_getctty (dport, &cttyid))   /* Could this be it? */
                 {
                   __mach_port_deallocate (__mach_task_self (), cttyid);
                   /* This port is capable of being a controlling tty.
                     Is it ours?  */
                   if (cttyid == port)
                     __term_open_ctty (dport, _hurd_pid, _hurd_pgrp, &ctty);
                   /* XXX if this port is our ctty, but we are not doing
                     ctty style i/o because term_become_ctty barfed,
                     what to do?  */
                 }
               0;
              }));

  /* Install PORT in the descriptor cell, leaving it locked.  */
  {
    mach_port_t old
      = _hurd_userlink_clear (&d->port.users) ? d->port.port : MACH_PORT_NULL;
    d->port.port = dport;
    d->flags = (flags & O_CLOEXEC) ? FD_CLOEXEC : 0;
    if (old != MACH_PORT_NULL)
      __mach_port_deallocate (__mach_task_self (), old);
  }

  _hurd_port_set (&d->ctty, ctty);
}

Here is the call graph for this function:

Here is the caller graph for this function:

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 
)

Definition at line 42 of file hurdselect.c.

{
  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;

  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 (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)
                  if (d[i].type != 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;
#ifdef MACH_MSG_TRAILER_MINIMUM_SIZE
         struct
           {
             mach_msg_header_t head;
             NDR_record_t ndr;
             error_t err;
           } error;
         struct
           {
             mach_msg_header_t head;
             NDR_record_t ndr;
             error_t err;
             int result;
             mach_msg_trailer_t trailer;
           } success;
#else
         struct
           {
             mach_msg_header_t head;
             union typeword err_type;
             error_t err;
           } error;
         struct
           {
             mach_msg_header_t head;
             union typeword err_type;
             error_t err;
             union typeword result_type;
             int result;
           } success;
#endif
       } 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 */
#ifdef MACH_MSG_TYPE_BIT
         const union typeword inttype =
         { type:
           { MACH_MSG_TYPE_INTEGER_T, sizeof (integer_t) * 8, 1, 1, 0, 0 }
         };
#endif
         if (msg.head.msgh_id == IO_SELECT_REPLY_MSGID &&
             msg.head.msgh_size >= sizeof msg.error &&
             !(msg.head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
#ifdef MACH_MSG_TYPE_BIT
             msg.error.err_type.word == inttype.word
#endif
             )
           {
             /* 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 ||
#ifdef MACH_MSG_TYPE_BIT
                msg.success.result_type.word != inttype.word ||
#endif
                (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)
      {
       int type = d[i].type;
       int_fast16_t revents = 0;

       if (type & SELECT_RETURNED)
         {
           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;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 32 of file dtable.c.

Definition at line 33 of file dtable.c.