1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*      Copyright (c) 1988 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 #pragma ident   "%Z%%M% %I%     %E% SMI"
  31 
  32 /*
  33  * Emulation of select() system call using poll() system call.
  34  *
  35  * Assumptions:
  36  *      polling for input only is most common.
  37  *      polling for exceptional conditions is very rare.
  38  *
  39  * Note that is it not feasible to emulate all error conditions,
  40  * in particular conditions that would return EFAULT are far too
  41  * difficult to check for in a library routine.
  42  */
  43 
  44 #pragma weak _select = select
  45 
  46 #include "lint.h"
  47 #include <values.h>
  48 #include <pthread.h>
  49 #include <errno.h>
  50 #include <sys/time.h>
  51 #include <sys/types.h>
  52 #include <sys/select.h>
  53 #include <sys/poll.h>
  54 #include <alloca.h>
  55 #include "libc.h"
  56 
  57 int
  58 pselect(int nfds, fd_set *in0, fd_set *out0, fd_set *ex0,
  59         const timespec_t *tsp, const sigset_t *sigmask)
  60 {
  61         long *in, *out, *ex;
  62         ulong_t m;      /* bit mask */
  63         int j;          /* loop counter */
  64         ulong_t b;      /* bits to test */
  65         int n, rv;
  66         struct pollfd *pfd;
  67         struct pollfd *p;
  68         int lastj = -1;
  69 
  70         /* "zero" is read-only, it could go in the text segment */
  71         static fd_set zero = { 0 };
  72 
  73         /*
  74          * Check for invalid conditions at outset.
  75          * Required for spec1170.
  76          * SUSV3: We must behave as a cancellation point even if we fail early.
  77          */
  78         if (nfds < 0 || nfds > FD_SETSIZE) {
  79                 pthread_testcancel();
  80                 errno = EINVAL;
  81                 return (-1);
  82         }
  83         p = pfd = (struct pollfd *)alloca(nfds * sizeof (struct pollfd));
  84 
  85         if (tsp != NULL) {
  86                 /* check timespec validity */
  87                 if (tsp->tv_nsec < 0 || tsp->tv_nsec >= NANOSEC ||
  88                     tsp->tv_sec < 0) {
  89                         pthread_testcancel();
  90                         errno = EINVAL;
  91                         return (-1);
  92                 }
  93         }
  94 
  95         /*
  96          * If any input args are null, point them at the null array.
  97          */
  98         if (in0 == NULL)
  99                 in0 = &zero;
 100         if (out0 == NULL)
 101                 out0 = &zero;
 102         if (ex0 == NULL)
 103                 ex0 = &zero;
 104 
 105         /*
 106          * For each fd, if any bits are set convert them into
 107          * the appropriate pollfd struct.
 108          */
 109         in = (long *)in0->fds_bits;
 110         out = (long *)out0->fds_bits;
 111         ex = (long *)ex0->fds_bits;
 112         for (n = 0; n < nfds; n += NFDBITS) {
 113                 b = (ulong_t)(*in | *out | *ex);
 114                 for (j = 0, m = 1; b != 0; j++, b >>= 1, m <<= 1) {
 115                         if (b & 1) {
 116                                 p->fd = n + j;
 117                                 if (p->fd >= nfds)
 118                                         goto done;
 119                                 p->events = 0;
 120                                 if (*in & m)
 121                                         p->events |= POLLRDNORM;
 122                                 if (*out & m)
 123                                         p->events |= POLLWRNORM;
 124                                 if (*ex & m)
 125                                         p->events |= POLLRDBAND;
 126                                 p++;
 127                         }
 128                 }
 129                 in++;
 130                 out++;
 131                 ex++;
 132         }
 133 done:
 134         /*
 135          * Now do the poll.
 136          */
 137         n = (int)(p - pfd);             /* number of pollfd's */
 138         do {
 139                 rv = _pollsys(pfd, (nfds_t)n, tsp, sigmask);
 140         } while (rv < 0 && errno == EAGAIN);
 141 
 142         if (rv < 0)          /* no need to set bit masks */
 143                 return (rv);
 144 
 145         if (rv == 0) {
 146                 /*
 147                  * Clear out bit masks, just in case.
 148                  * On the assumption that usually only
 149                  * one bit mask is set, use three loops.
 150                  */
 151                 if (in0 != &zero) {
 152                         in = (long *)in0->fds_bits;
 153                         for (n = 0; n < nfds; n += NFDBITS)
 154                                 *in++ = 0;
 155                 }
 156                 if (out0 != &zero) {
 157                         out = (long *)out0->fds_bits;
 158                         for (n = 0; n < nfds; n += NFDBITS)
 159                                 *out++ = 0;
 160                 }
 161                 if (ex0 != &zero) {
 162                         ex = (long *)ex0->fds_bits;
 163                         for (n = 0; n < nfds; n += NFDBITS)
 164                                 *ex++ = 0;
 165                 }
 166                 return (0);
 167         }
 168 
 169         /*
 170          * Check for EINVAL error case first to avoid changing any bits
 171          * if we're going to return an error.
 172          */
 173         for (p = pfd, j = n; j-- > 0; p++) {
 174                 /*
 175                  * select will return EBADF immediately if any fd's
 176                  * are bad.  poll will complete the poll on the
 177                  * rest of the fd's and include the error indication
 178                  * in the returned bits.  This is a rare case so we
 179                  * accept this difference and return the error after
 180                  * doing more work than select would've done.
 181                  */
 182                 if (p->revents & POLLNVAL) {
 183                         errno = EBADF;
 184                         return (-1);
 185                 }
 186                 /*
 187                  * We would like to make POLLHUP available to select,
 188                  * checking to see if we have pending data to be read.
 189                  * BUT until we figure out how not to break Xsun's
 190                  * dependencies on select's existing features...
 191                  * This is what we _thought_ would work ... sigh!
 192                  */
 193                 /*
 194                  * if ((p->revents & POLLHUP) &&
 195                  *      !(p->revents & (POLLRDNORM|POLLRDBAND))) {
 196                  *      errno = EINTR;
 197                  *      return (-1);
 198                  * }
 199                  */
 200         }
 201 
 202         /*
 203          * Convert results of poll back into bits
 204          * in the argument arrays.
 205          *
 206          * We assume POLLRDNORM, POLLWRNORM, and POLLRDBAND will only be set
 207          * on return from poll if they were set on input, thus we don't
 208          * worry about accidentally setting the corresponding bits in the
 209          * zero array if the input bit masks were null.
 210          *
 211          * Must return number of bits set, not number of ready descriptors
 212          * (as the man page says, and as poll() does).
 213          */
 214         rv = 0;
 215         for (p = pfd; n-- > 0; p++) {
 216                 j = (int)(p->fd / NFDBITS);
 217                 /* have we moved into another word of the bit mask yet? */
 218                 if (j != lastj) {
 219                         /* clear all output bits to start with */
 220                         in = (long *)&in0->fds_bits[j];
 221                         out = (long *)&out0->fds_bits[j];
 222                         ex = (long *)&ex0->fds_bits[j];
 223                         /*
 224                          * In case we made "zero" read-only (e.g., with
 225                          * cc -R), avoid actually storing into it.
 226                          */
 227                         if (in0 != &zero)
 228                                 *in = 0;
 229                         if (out0 != &zero)
 230                                 *out = 0;
 231                         if (ex0 != &zero)
 232                                 *ex = 0;
 233                         lastj = j;
 234                 }
 235                 if (p->revents) {
 236                         m = 1L << (p->fd % NFDBITS);
 237                         if (p->revents & POLLRDNORM) {
 238                                 *in |= m;
 239                                 rv++;
 240                         }
 241                         if (p->revents & POLLWRNORM) {
 242                                 *out |= m;
 243                                 rv++;
 244                         }
 245                         if (p->revents & POLLRDBAND) {
 246                                 *ex |= m;
 247                                 rv++;
 248                         }
 249                         /*
 250                          * Only set this bit on return if we asked about
 251                          * input conditions.
 252                          */
 253                         if ((p->revents & (POLLHUP|POLLERR)) &&
 254                             (p->events & POLLRDNORM)) {
 255                                 if ((*in & m) == 0)
 256                                         rv++;   /* wasn't already set */
 257                                 *in |= m;
 258                         }
 259                         /*
 260                          * Only set this bit on return if we asked about
 261                          * output conditions.
 262                          */
 263                         if ((p->revents & (POLLHUP|POLLERR)) &&
 264                             (p->events & POLLWRNORM)) {
 265                                 if ((*out & m) == 0)
 266                                         rv++;   /* wasn't already set */
 267                                 *out |= m;
 268                         }
 269                         /*
 270                          * Only set this bit on return if we asked about
 271                          * output conditions.
 272                          */
 273                         if ((p->revents & (POLLHUP|POLLERR)) &&
 274                             (p->events & POLLRDBAND)) {
 275                                 if ((*ex & m) == 0)
 276                                         rv++;   /* wasn't already set */
 277                                 *ex |= m;
 278                         }
 279                 }
 280         }
 281         return (rv);
 282 }
 283 
 284 int
 285 select(int nfds, fd_set *in0, fd_set *out0, fd_set *ex0, struct timeval *tv)
 286 {
 287         timespec_t ts;
 288         timespec_t *tsp;
 289 
 290         if (tv == NULL)
 291                 tsp = NULL;
 292         else {
 293                 /* check timeval validity */
 294                 if (tv->tv_usec < 0 || tv->tv_usec >= MICROSEC) {
 295                         errno = EINVAL;
 296                         return (-1);
 297                 }
 298                 /*
 299                  * Convert timeval to timespec.
 300                  * To preserve compatibility with past behavior,
 301                  * when select was built upon poll(2), which has a
 302                  * minimum non-zero timeout of 1 millisecond, force
 303                  * a minimum non-zero timeout of 500 microseconds.
 304                  */
 305                 ts.tv_sec = tv->tv_sec;
 306                 ts.tv_nsec = tv->tv_usec * 1000;
 307                 if (ts.tv_nsec != 0 && ts.tv_nsec < 500000)
 308                         ts.tv_nsec = 500000;
 309                 tsp = &ts;
 310         }
 311 
 312         return (pselect(nfds, in0, out0, ex0, tsp, NULL));
 313 }