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