Back to index

glibc  2.9
hurdselect.c
Go to the documentation of this file.
00001 /* Guts of both `select' and `poll' for Hurd.
00002    Copyright (C) 1991,92,93,94,95,96,97,98,99,2001
00003        Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <sys/types.h>
00022 #include <sys/poll.h>
00023 #include <hurd.h>
00024 #include <hurd/fd.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <assert.h>
00028 #include <stdint.h>
00029 
00030 /* All user select types.  */
00031 #define SELECT_ALL (SELECT_READ | SELECT_WRITE | SELECT_URG)
00032 
00033 /* Used to record that a particular select rpc returned.  Must be distinct
00034    from SELECT_ALL (which better not have the high bit set).  */
00035 #define SELECT_RETURNED ((SELECT_ALL << 1) & ~SELECT_ALL)
00036 
00037 /* Check the first NFDS descriptors either in POLLFDS (if nonnnull) or in
00038    each of READFDS, WRITEFDS, EXCEPTFDS that is nonnull.  If TIMEOUT is not
00039    NULL, time out after waiting the interval specified therein.  Returns
00040    the number of ready descriptors, or -1 for errors.  */
00041 int
00042 _hurd_select (int nfds,
00043              struct pollfd *pollfds,
00044              fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
00045              const struct timespec *timeout, const sigset_t *sigmask)
00046 {
00047   int i;
00048   mach_port_t portset;
00049   int got;
00050   error_t err;
00051   fd_set rfds, wfds, xfds;
00052   int firstfd, lastfd;
00053   mach_msg_timeout_t to = (timeout != NULL ?
00054                         (timeout->tv_sec * 1000 +
00055                          timeout->tv_nsec / 1000000) :
00056                         0);
00057   struct
00058     {
00059       struct hurd_userlink ulink;
00060       struct hurd_fd *cell;
00061       mach_port_t io_port;
00062       int type;
00063       mach_port_t reply_port;
00064     } d[nfds];
00065   sigset_t oset;
00066 
00067   union typeword            /* Use this to avoid unkosher casts.  */
00068     {
00069       mach_msg_type_t type;
00070       uint32_t word;
00071     };
00072   assert (sizeof (union typeword) == sizeof (mach_msg_type_t));
00073   assert (sizeof (uint32_t) == sizeof (mach_msg_type_t));
00074 
00075   if (sigmask && __sigprocmask (SIG_SETMASK, sigmask, &oset))
00076     return -1;
00077 
00078   if (pollfds)
00079     {
00080       /* Collect interesting descriptors from the user's `pollfd' array.
00081         We do a first pass that reads the user's array before taking
00082         any locks.  The second pass then only touches our own stack,
00083         and gets the port references.  */
00084 
00085       for (i = 0; i < nfds; ++i)
00086        if (pollfds[i].fd >= 0)
00087          {
00088            int type = 0;
00089            if (pollfds[i].events & POLLIN)
00090              type |= SELECT_READ;
00091            if (pollfds[i].events & POLLOUT)
00092              type |= SELECT_WRITE;
00093            if (pollfds[i].events & POLLPRI)
00094              type |= SELECT_URG;
00095 
00096            d[i].io_port = pollfds[i].fd;
00097            d[i].type = type;
00098          }
00099        else
00100          d[i].type = 0;
00101 
00102       HURD_CRITICAL_BEGIN;
00103       __mutex_lock (&_hurd_dtable_lock);
00104 
00105       for (i = 0; i < nfds; ++i)
00106        if (d[i].type != 0)
00107          {
00108            const int fd = (int) d[i].io_port;
00109 
00110            if (fd < _hurd_dtablesize)
00111              {
00112               d[i].cell = _hurd_dtable[fd];
00113               d[i].io_port = _hurd_port_get (&d[i].cell->port, &d[i].ulink);
00114               if (d[i].io_port != MACH_PORT_NULL)
00115                 continue;
00116              }
00117 
00118            /* If one descriptor is bogus, we fail completely.  */
00119            while (i-- > 0)
00120              if (d[i].type != 0)
00121               _hurd_port_free (&d[i].cell->port,
00122                              &d[i].ulink, d[i].io_port);
00123            break;
00124          }
00125 
00126       __mutex_unlock (&_hurd_dtable_lock);
00127       HURD_CRITICAL_END;
00128 
00129       if (i < nfds)
00130        {
00131          if (sigmask)
00132            __sigprocmask (SIG_SETMASK, &oset, NULL);
00133          errno = EBADF;
00134          return -1;
00135        }
00136 
00137       lastfd = i - 1;
00138       firstfd = i == 0 ? lastfd : 0;
00139     }
00140   else
00141     {
00142       /* Collect interested descriptors from the user's fd_set arguments.
00143         Use local copies so we can't crash from user bogosity.  */
00144 
00145       if (readfds == NULL)
00146        FD_ZERO (&rfds);
00147       else
00148        rfds = *readfds;
00149       if (writefds == NULL)
00150        FD_ZERO (&wfds);
00151       else
00152        wfds = *writefds;
00153       if (exceptfds == NULL)
00154        FD_ZERO (&xfds);
00155       else
00156        xfds = *exceptfds;
00157 
00158       HURD_CRITICAL_BEGIN;
00159       __mutex_lock (&_hurd_dtable_lock);
00160 
00161       if (nfds > _hurd_dtablesize)
00162        nfds = _hurd_dtablesize;
00163 
00164       /* Collect the ports for interesting FDs.  */
00165       firstfd = lastfd = -1;
00166       for (i = 0; i < nfds; ++i)
00167        {
00168          int type = 0;
00169          if (readfds != NULL && FD_ISSET (i, &rfds))
00170            type |= SELECT_READ;
00171          if (writefds != NULL && FD_ISSET (i, &wfds))
00172            type |= SELECT_WRITE;
00173          if (exceptfds != NULL && FD_ISSET (i, &xfds))
00174            type |= SELECT_URG;
00175          d[i].type = type;
00176          if (type)
00177            {
00178              d[i].cell = _hurd_dtable[i];
00179              d[i].io_port = _hurd_port_get (&d[i].cell->port, &d[i].ulink);
00180              if (d[i].io_port == MACH_PORT_NULL)
00181               {
00182                 /* If one descriptor is bogus, we fail completely.  */
00183                 while (i-- > 0)
00184                   if (d[i].type != 0)
00185                     _hurd_port_free (&d[i].cell->port, &d[i].ulink,
00186                                    d[i].io_port);
00187                 break;
00188               }
00189              lastfd = i;
00190              if (firstfd == -1)
00191               firstfd = i;
00192            }
00193        }
00194 
00195       __mutex_unlock (&_hurd_dtable_lock);
00196       HURD_CRITICAL_END;
00197 
00198       if (i < nfds)
00199        {
00200          if (sigmask)
00201            __sigprocmask (SIG_SETMASK, &oset, NULL);
00202          errno = EBADF;
00203          return -1;
00204        }
00205     }
00206 
00207 
00208   err = 0;
00209   got = 0;
00210 
00211   /* Send them all io_select request messages.  */
00212 
00213   if (firstfd == -1)
00214     /* But not if there were no ports to deal with at all.
00215        We are just a pure timeout.  */
00216     portset = __mach_reply_port ();
00217   else
00218     {
00219       portset = MACH_PORT_NULL;
00220 
00221       for (i = firstfd; i <= lastfd; ++i)
00222        if (d[i].type)
00223          {
00224            int type = d[i].type;
00225            d[i].reply_port = __mach_reply_port ();
00226            err = __io_select (d[i].io_port, d[i].reply_port,
00227                             /* Poll only if there's a single descriptor.  */
00228                             (firstfd == lastfd) ? to : 0,
00229                             &type);
00230            switch (err)
00231              {
00232              case MACH_RCV_TIMED_OUT:
00233               /* No immediate response.  This is normal.  */
00234               err = 0;
00235               if (firstfd == lastfd)
00236                 /* When there's a single descriptor, we don't need a
00237                    portset, so just pretend we have one, but really
00238                    use the single reply port.  */
00239                 portset = d[i].reply_port;
00240               else if (got == 0)
00241                 /* We've got multiple reply ports, so we need a port set to
00242                    multiplex them.  */
00243                 {
00244                   /* We will wait again for a reply later.  */
00245                   if (portset == MACH_PORT_NULL)
00246                     /* Create the portset to receive all the replies on.  */
00247                     err = __mach_port_allocate (__mach_task_self (),
00248                                             MACH_PORT_RIGHT_PORT_SET,
00249                                             &portset);
00250                   if (! err)
00251                     /* Put this reply port in the port set.  */
00252                     __mach_port_move_member (__mach_task_self (),
00253                                           d[i].reply_port, portset);
00254                 }
00255               break;
00256 
00257              default:
00258               /* No other error should happen.  Callers of select
00259                  don't expect to see errors, so we simulate
00260                  readiness of the erring object and the next call
00261                  hopefully will get the error again.  */
00262               type = SELECT_ALL;
00263               /* FALLTHROUGH */
00264 
00265              case 0:
00266               /* We got an answer.  */
00267               if ((type & SELECT_ALL) == 0)
00268                 /* Bogus answer; treat like an error, as a fake positive.  */
00269                 type = SELECT_ALL;
00270 
00271               /* This port is already ready already.  */
00272               d[i].type &= type;
00273               d[i].type |= SELECT_RETURNED;
00274               ++got;
00275               break;
00276              }
00277            _hurd_port_free (&d[i].cell->port, &d[i].ulink, d[i].io_port);
00278          }
00279     }
00280 
00281   /* Now wait for reply messages.  */
00282   if (!err && got == 0)
00283     {
00284       /* Now wait for io_select_reply messages on PORT,
00285         timing out as appropriate.  */
00286 
00287       union
00288        {
00289          mach_msg_header_t head;
00290 #ifdef MACH_MSG_TRAILER_MINIMUM_SIZE
00291          struct
00292            {
00293              mach_msg_header_t head;
00294              NDR_record_t ndr;
00295              error_t err;
00296            } error;
00297          struct
00298            {
00299              mach_msg_header_t head;
00300              NDR_record_t ndr;
00301              error_t err;
00302              int result;
00303              mach_msg_trailer_t trailer;
00304            } success;
00305 #else
00306          struct
00307            {
00308              mach_msg_header_t head;
00309              union typeword err_type;
00310              error_t err;
00311            } error;
00312          struct
00313            {
00314              mach_msg_header_t head;
00315              union typeword err_type;
00316              error_t err;
00317              union typeword result_type;
00318              int result;
00319            } success;
00320 #endif
00321        } msg;
00322       mach_msg_option_t options = (timeout == NULL ? 0 : MACH_RCV_TIMEOUT);
00323       error_t msgerr;
00324       while ((msgerr = __mach_msg (&msg.head,
00325                                MACH_RCV_MSG | options,
00326                                0, sizeof msg, portset, to,
00327                                MACH_PORT_NULL)) == MACH_MSG_SUCCESS)
00328        {
00329          /* We got a message.  Decode it.  */
00330 #define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
00331 #ifdef MACH_MSG_TYPE_BIT
00332          const union typeword inttype =
00333          { type:
00334            { MACH_MSG_TYPE_INTEGER_T, sizeof (integer_t) * 8, 1, 1, 0, 0 }
00335          };
00336 #endif
00337          if (msg.head.msgh_id == IO_SELECT_REPLY_MSGID &&
00338              msg.head.msgh_size >= sizeof msg.error &&
00339              !(msg.head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
00340 #ifdef MACH_MSG_TYPE_BIT
00341              msg.error.err_type.word == inttype.word
00342 #endif
00343              )
00344            {
00345              /* This is a properly formatted message so far.
00346                See if it is a success or a failure.  */
00347              if (msg.error.err == EINTR &&
00348                 msg.head.msgh_size == sizeof msg.error)
00349               {
00350                 /* EINTR response; poll for further responses
00351                    and then return quickly.  */
00352                 err = EINTR;
00353                 goto poll;
00354               }
00355              if (msg.error.err ||
00356                 msg.head.msgh_size != sizeof msg.success ||
00357 #ifdef MACH_MSG_TYPE_BIT
00358                 msg.success.result_type.word != inttype.word ||
00359 #endif
00360                 (msg.success.result & SELECT_ALL) == 0)
00361               {
00362                 /* Error or bogus reply.  Simulate readiness.  */
00363                 __mach_msg_destroy (&msg.head);
00364                 msg.success.result = SELECT_ALL;
00365               }
00366 
00367              /* Look up the respondent's reply port and record its
00368                  readiness.  */
00369              {
00370               int had = got;
00371               if (firstfd != -1)
00372                 for (i = firstfd; i <= lastfd; ++i)
00373                   if (d[i].type
00374                      && d[i].reply_port == msg.head.msgh_local_port)
00375                     {
00376                      d[i].type &= msg.success.result;
00377                      d[i].type |= SELECT_RETURNED;
00378                      ++got;
00379                     }
00380               assert (got > had);
00381              }
00382            }
00383 
00384          if (msg.head.msgh_remote_port != MACH_PORT_NULL)
00385            __mach_port_deallocate (__mach_task_self (),
00386                                 msg.head.msgh_remote_port);
00387 
00388          if (got)
00389          poll:
00390            {
00391              /* Poll for another message.  */
00392              to = 0;
00393              options |= MACH_RCV_TIMEOUT;
00394            }
00395        }
00396 
00397       if (err == MACH_RCV_TIMED_OUT)
00398        /* This is the normal value for ERR.  We might have timed out and
00399           read no messages.  Otherwise, after receiving the first message,
00400           we poll for more messages.  We receive with a timeout of 0 to
00401           effect a poll, so ERR is MACH_RCV_TIMED_OUT when the poll finds no
00402           message waiting.  */
00403        err = 0;
00404 
00405       if (got)
00406        /* At least one descriptor is known to be ready now, so we will
00407           return success.  */
00408        err = 0;
00409     }
00410 
00411   if (firstfd != -1)
00412     for (i = firstfd; i <= lastfd; ++i)
00413       if (d[i].type)
00414        __mach_port_destroy (__mach_task_self (), d[i].reply_port);
00415   if (firstfd == -1 || (firstfd != lastfd && portset != MACH_PORT_NULL))
00416     /* Destroy PORTSET, but only if it's not actually the reply port for a
00417        single descriptor (in which case it's destroyed in the previous loop;
00418        not doing it here is just a bit more efficient).  */
00419     __mach_port_destroy (__mach_task_self (), portset);
00420 
00421   if (err)
00422     {
00423       if (sigmask)
00424        __sigprocmask (SIG_SETMASK, &oset, NULL);
00425       return __hurd_fail (err);
00426     }
00427 
00428   if (pollfds)
00429     /* Fill in the `revents' members of the user's array.  */
00430     for (i = 0; i < nfds; ++i)
00431       {
00432        int type = d[i].type;
00433        int_fast16_t revents = 0;
00434 
00435        if (type & SELECT_RETURNED)
00436          {
00437            if (type & SELECT_READ)
00438              revents |= POLLIN;
00439            if (type & SELECT_WRITE)
00440              revents |= POLLOUT;
00441            if (type & SELECT_URG)
00442              revents |= POLLPRI;
00443          }
00444 
00445        pollfds[i].revents = revents;
00446       }
00447   else
00448     {
00449       /* Below we recalculate GOT to include an increment for each operation
00450         allowed on each fd.  */
00451       got = 0;
00452 
00453       /* Set the user bitarrays.  We only ever have to clear bits, as all
00454         desired ones are initially set.  */
00455       if (firstfd != -1)
00456        for (i = firstfd; i <= lastfd; ++i)
00457          {
00458            int type = d[i].type;
00459 
00460            if ((type & SELECT_RETURNED) == 0)
00461              type = 0;
00462 
00463            if (type & SELECT_READ)
00464              got++;
00465            else if (readfds)
00466              FD_CLR (i, readfds);
00467            if (type & SELECT_WRITE)
00468              got++;
00469            else if (writefds)
00470              FD_CLR (i, writefds);
00471            if (type & SELECT_URG)
00472              got++;
00473            else if (exceptfds)
00474              FD_CLR (i, exceptfds);
00475          }
00476     }
00477 
00478   if (sigmask && __sigprocmask (SIG_SETMASK, &oset, NULL))
00479     return -1;
00480 
00481   return got;
00482 }