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