17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5a5c23cccSraf * Common Development and Distribution License (the "License"). 6a5c23cccSraf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21a5c23cccSraf 227c478bd9Sstevel@tonic-gate /* 238cd45542Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 30*7257d1b4Sraf #pragma ident "%Z%%M% %I% %E% SMI" 31*7257d1b4Sraf 327c478bd9Sstevel@tonic-gate /* 337c478bd9Sstevel@tonic-gate * Emulation of select() system call using poll() system call. 347c478bd9Sstevel@tonic-gate * 357c478bd9Sstevel@tonic-gate * Assumptions: 367c478bd9Sstevel@tonic-gate * polling for input only is most common. 377c478bd9Sstevel@tonic-gate * polling for exceptional conditions is very rare. 387c478bd9Sstevel@tonic-gate * 397c478bd9Sstevel@tonic-gate * Note that is it not feasible to emulate all error conditions, 407c478bd9Sstevel@tonic-gate * in particular conditions that would return EFAULT are far too 417c478bd9Sstevel@tonic-gate * difficult to check for in a library routine. 427c478bd9Sstevel@tonic-gate */ 437c478bd9Sstevel@tonic-gate 44*7257d1b4Sraf #pragma weak _select = select 457c478bd9Sstevel@tonic-gate 46*7257d1b4Sraf #include "lint.h" 477c478bd9Sstevel@tonic-gate #include <values.h> 488cd45542Sraf #include <pthread.h> 497c478bd9Sstevel@tonic-gate #include <errno.h> 507c478bd9Sstevel@tonic-gate #include <sys/time.h> 517c478bd9Sstevel@tonic-gate #include <sys/types.h> 527c478bd9Sstevel@tonic-gate #include <sys/select.h> 537c478bd9Sstevel@tonic-gate #include <sys/poll.h> 547c478bd9Sstevel@tonic-gate #include <alloca.h> 557c478bd9Sstevel@tonic-gate #include "libc.h" 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate int 587c478bd9Sstevel@tonic-gate pselect(int nfds, fd_set *in0, fd_set *out0, fd_set *ex0, 597c478bd9Sstevel@tonic-gate const timespec_t *tsp, const sigset_t *sigmask) 607c478bd9Sstevel@tonic-gate { 617c478bd9Sstevel@tonic-gate long *in, *out, *ex; 627c478bd9Sstevel@tonic-gate ulong_t m; /* bit mask */ 637c478bd9Sstevel@tonic-gate int j; /* loop counter */ 647c478bd9Sstevel@tonic-gate ulong_t b; /* bits to test */ 657c478bd9Sstevel@tonic-gate int n, rv; 667c478bd9Sstevel@tonic-gate struct pollfd *pfd; 677c478bd9Sstevel@tonic-gate struct pollfd *p; 687c478bd9Sstevel@tonic-gate int lastj = -1; 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate /* "zero" is read-only, it could go in the text segment */ 717c478bd9Sstevel@tonic-gate static fd_set zero = { 0 }; 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * Check for invalid conditions at outset. 757c478bd9Sstevel@tonic-gate * Required for spec1170. 767c478bd9Sstevel@tonic-gate * SUSV3: We must behave as a cancellation point even if we fail early. 777c478bd9Sstevel@tonic-gate */ 787c478bd9Sstevel@tonic-gate if (nfds < 0 || nfds > FD_SETSIZE) { 798cd45542Sraf pthread_testcancel(); 807c478bd9Sstevel@tonic-gate errno = EINVAL; 817c478bd9Sstevel@tonic-gate return (-1); 827c478bd9Sstevel@tonic-gate } 837c478bd9Sstevel@tonic-gate p = pfd = (struct pollfd *)alloca(nfds * sizeof (struct pollfd)); 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate if (tsp != NULL) { 867c478bd9Sstevel@tonic-gate /* check timespec validity */ 877c478bd9Sstevel@tonic-gate if (tsp->tv_nsec < 0 || tsp->tv_nsec >= NANOSEC || 887c478bd9Sstevel@tonic-gate tsp->tv_sec < 0) { 898cd45542Sraf pthread_testcancel(); 907c478bd9Sstevel@tonic-gate errno = EINVAL; 917c478bd9Sstevel@tonic-gate return (-1); 927c478bd9Sstevel@tonic-gate } 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * If any input args are null, point them at the null array. 977c478bd9Sstevel@tonic-gate */ 987c478bd9Sstevel@tonic-gate if (in0 == NULL) 997c478bd9Sstevel@tonic-gate in0 = &zero; 1007c478bd9Sstevel@tonic-gate if (out0 == NULL) 1017c478bd9Sstevel@tonic-gate out0 = &zero; 1027c478bd9Sstevel@tonic-gate if (ex0 == NULL) 1037c478bd9Sstevel@tonic-gate ex0 = &zero; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate /* 1067c478bd9Sstevel@tonic-gate * For each fd, if any bits are set convert them into 1077c478bd9Sstevel@tonic-gate * the appropriate pollfd struct. 1087c478bd9Sstevel@tonic-gate */ 1097c478bd9Sstevel@tonic-gate in = (long *)in0->fds_bits; 1107c478bd9Sstevel@tonic-gate out = (long *)out0->fds_bits; 1117c478bd9Sstevel@tonic-gate ex = (long *)ex0->fds_bits; 1127c478bd9Sstevel@tonic-gate for (n = 0; n < nfds; n += NFDBITS) { 1137c478bd9Sstevel@tonic-gate b = (ulong_t)(*in | *out | *ex); 1147c478bd9Sstevel@tonic-gate for (j = 0, m = 1; b != 0; j++, b >>= 1, m <<= 1) { 1157c478bd9Sstevel@tonic-gate if (b & 1) { 1167c478bd9Sstevel@tonic-gate p->fd = n + j; 1177c478bd9Sstevel@tonic-gate if (p->fd >= nfds) 1187c478bd9Sstevel@tonic-gate goto done; 1197c478bd9Sstevel@tonic-gate p->events = 0; 1207c478bd9Sstevel@tonic-gate if (*in & m) 1217c478bd9Sstevel@tonic-gate p->events |= POLLRDNORM; 1227c478bd9Sstevel@tonic-gate if (*out & m) 1237c478bd9Sstevel@tonic-gate p->events |= POLLWRNORM; 1247c478bd9Sstevel@tonic-gate if (*ex & m) 1257c478bd9Sstevel@tonic-gate p->events |= POLLRDBAND; 1267c478bd9Sstevel@tonic-gate p++; 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate in++; 1307c478bd9Sstevel@tonic-gate out++; 1317c478bd9Sstevel@tonic-gate ex++; 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate done: 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * Now do the poll. 1367c478bd9Sstevel@tonic-gate */ 1377c478bd9Sstevel@tonic-gate n = (int)(p - pfd); /* number of pollfd's */ 1387c478bd9Sstevel@tonic-gate do { 1397c478bd9Sstevel@tonic-gate rv = _pollsys(pfd, (nfds_t)n, tsp, sigmask); 1407c478bd9Sstevel@tonic-gate } while (rv < 0 && errno == EAGAIN); 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate if (rv < 0) /* no need to set bit masks */ 1437c478bd9Sstevel@tonic-gate return (rv); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate if (rv == 0) { 1467c478bd9Sstevel@tonic-gate /* 1477c478bd9Sstevel@tonic-gate * Clear out bit masks, just in case. 1487c478bd9Sstevel@tonic-gate * On the assumption that usually only 1497c478bd9Sstevel@tonic-gate * one bit mask is set, use three loops. 1507c478bd9Sstevel@tonic-gate */ 1517c478bd9Sstevel@tonic-gate if (in0 != &zero) { 1527c478bd9Sstevel@tonic-gate in = (long *)in0->fds_bits; 1537c478bd9Sstevel@tonic-gate for (n = 0; n < nfds; n += NFDBITS) 1547c478bd9Sstevel@tonic-gate *in++ = 0; 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate if (out0 != &zero) { 1577c478bd9Sstevel@tonic-gate out = (long *)out0->fds_bits; 1587c478bd9Sstevel@tonic-gate for (n = 0; n < nfds; n += NFDBITS) 1597c478bd9Sstevel@tonic-gate *out++ = 0; 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate if (ex0 != &zero) { 1627c478bd9Sstevel@tonic-gate ex = (long *)ex0->fds_bits; 1637c478bd9Sstevel@tonic-gate for (n = 0; n < nfds; n += NFDBITS) 1647c478bd9Sstevel@tonic-gate *ex++ = 0; 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate return (0); 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * Check for EINVAL error case first to avoid changing any bits 1717c478bd9Sstevel@tonic-gate * if we're going to return an error. 1727c478bd9Sstevel@tonic-gate */ 1737c478bd9Sstevel@tonic-gate for (p = pfd, j = n; j-- > 0; p++) { 1747c478bd9Sstevel@tonic-gate /* 1757c478bd9Sstevel@tonic-gate * select will return EBADF immediately if any fd's 1767c478bd9Sstevel@tonic-gate * are bad. poll will complete the poll on the 1777c478bd9Sstevel@tonic-gate * rest of the fd's and include the error indication 1787c478bd9Sstevel@tonic-gate * in the returned bits. This is a rare case so we 1797c478bd9Sstevel@tonic-gate * accept this difference and return the error after 1807c478bd9Sstevel@tonic-gate * doing more work than select would've done. 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate if (p->revents & POLLNVAL) { 1837c478bd9Sstevel@tonic-gate errno = EBADF; 1847c478bd9Sstevel@tonic-gate return (-1); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate /* 1877c478bd9Sstevel@tonic-gate * We would like to make POLLHUP available to select, 1887c478bd9Sstevel@tonic-gate * checking to see if we have pending data to be read. 1897c478bd9Sstevel@tonic-gate * BUT until we figure out how not to break Xsun's 1907c478bd9Sstevel@tonic-gate * dependencies on select's existing features... 1917c478bd9Sstevel@tonic-gate * This is what we _thought_ would work ... sigh! 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate /* 1947c478bd9Sstevel@tonic-gate * if ((p->revents & POLLHUP) && 1957c478bd9Sstevel@tonic-gate * !(p->revents & (POLLRDNORM|POLLRDBAND))) { 1967c478bd9Sstevel@tonic-gate * errno = EINTR; 1977c478bd9Sstevel@tonic-gate * return (-1); 1987c478bd9Sstevel@tonic-gate * } 1997c478bd9Sstevel@tonic-gate */ 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate /* 2037c478bd9Sstevel@tonic-gate * Convert results of poll back into bits 2047c478bd9Sstevel@tonic-gate * in the argument arrays. 2057c478bd9Sstevel@tonic-gate * 2067c478bd9Sstevel@tonic-gate * We assume POLLRDNORM, POLLWRNORM, and POLLRDBAND will only be set 2077c478bd9Sstevel@tonic-gate * on return from poll if they were set on input, thus we don't 2087c478bd9Sstevel@tonic-gate * worry about accidentally setting the corresponding bits in the 2097c478bd9Sstevel@tonic-gate * zero array if the input bit masks were null. 2107c478bd9Sstevel@tonic-gate * 2117c478bd9Sstevel@tonic-gate * Must return number of bits set, not number of ready descriptors 2127c478bd9Sstevel@tonic-gate * (as the man page says, and as poll() does). 2137c478bd9Sstevel@tonic-gate */ 2147c478bd9Sstevel@tonic-gate rv = 0; 2157c478bd9Sstevel@tonic-gate for (p = pfd; n-- > 0; p++) { 2167c478bd9Sstevel@tonic-gate j = (int)(p->fd / NFDBITS); 2177c478bd9Sstevel@tonic-gate /* have we moved into another word of the bit mask yet? */ 2187c478bd9Sstevel@tonic-gate if (j != lastj) { 2197c478bd9Sstevel@tonic-gate /* clear all output bits to start with */ 2207c478bd9Sstevel@tonic-gate in = (long *)&in0->fds_bits[j]; 2217c478bd9Sstevel@tonic-gate out = (long *)&out0->fds_bits[j]; 2227c478bd9Sstevel@tonic-gate ex = (long *)&ex0->fds_bits[j]; 2237c478bd9Sstevel@tonic-gate /* 2247c478bd9Sstevel@tonic-gate * In case we made "zero" read-only (e.g., with 2257c478bd9Sstevel@tonic-gate * cc -R), avoid actually storing into it. 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate if (in0 != &zero) 2287c478bd9Sstevel@tonic-gate *in = 0; 2297c478bd9Sstevel@tonic-gate if (out0 != &zero) 2307c478bd9Sstevel@tonic-gate *out = 0; 2317c478bd9Sstevel@tonic-gate if (ex0 != &zero) 2327c478bd9Sstevel@tonic-gate *ex = 0; 2337c478bd9Sstevel@tonic-gate lastj = j; 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate if (p->revents) { 2367c478bd9Sstevel@tonic-gate m = 1L << (p->fd % NFDBITS); 2377c478bd9Sstevel@tonic-gate if (p->revents & POLLRDNORM) { 2387c478bd9Sstevel@tonic-gate *in |= m; 2397c478bd9Sstevel@tonic-gate rv++; 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate if (p->revents & POLLWRNORM) { 2427c478bd9Sstevel@tonic-gate *out |= m; 2437c478bd9Sstevel@tonic-gate rv++; 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate if (p->revents & POLLRDBAND) { 2467c478bd9Sstevel@tonic-gate *ex |= m; 2477c478bd9Sstevel@tonic-gate rv++; 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * Only set this bit on return if we asked about 2517c478bd9Sstevel@tonic-gate * input conditions. 2527c478bd9Sstevel@tonic-gate */ 2537c478bd9Sstevel@tonic-gate if ((p->revents & (POLLHUP|POLLERR)) && 2547c478bd9Sstevel@tonic-gate (p->events & POLLRDNORM)) { 2557c478bd9Sstevel@tonic-gate if ((*in & m) == 0) 2567c478bd9Sstevel@tonic-gate rv++; /* wasn't already set */ 2577c478bd9Sstevel@tonic-gate *in |= m; 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate /* 2607c478bd9Sstevel@tonic-gate * Only set this bit on return if we asked about 2617c478bd9Sstevel@tonic-gate * output conditions. 2627c478bd9Sstevel@tonic-gate */ 2637c478bd9Sstevel@tonic-gate if ((p->revents & (POLLHUP|POLLERR)) && 2647c478bd9Sstevel@tonic-gate (p->events & POLLWRNORM)) { 2657c478bd9Sstevel@tonic-gate if ((*out & m) == 0) 2667c478bd9Sstevel@tonic-gate rv++; /* wasn't already set */ 2677c478bd9Sstevel@tonic-gate *out |= m; 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate /* 2707c478bd9Sstevel@tonic-gate * Only set this bit on return if we asked about 2717c478bd9Sstevel@tonic-gate * output conditions. 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate if ((p->revents & (POLLHUP|POLLERR)) && 2747c478bd9Sstevel@tonic-gate (p->events & POLLRDBAND)) { 2757c478bd9Sstevel@tonic-gate if ((*ex & m) == 0) 2767c478bd9Sstevel@tonic-gate rv++; /* wasn't already set */ 2777c478bd9Sstevel@tonic-gate *ex |= m; 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate return (rv); 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate int 2857c478bd9Sstevel@tonic-gate select(int nfds, fd_set *in0, fd_set *out0, fd_set *ex0, struct timeval *tv) 2867c478bd9Sstevel@tonic-gate { 2877c478bd9Sstevel@tonic-gate timespec_t ts; 2887c478bd9Sstevel@tonic-gate timespec_t *tsp; 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate if (tv == NULL) 2917c478bd9Sstevel@tonic-gate tsp = NULL; 2927c478bd9Sstevel@tonic-gate else { 2937c478bd9Sstevel@tonic-gate /* check timeval validity */ 2947c478bd9Sstevel@tonic-gate if (tv->tv_usec < 0 || tv->tv_usec >= MICROSEC) { 2957c478bd9Sstevel@tonic-gate errno = EINVAL; 2967c478bd9Sstevel@tonic-gate return (-1); 2977c478bd9Sstevel@tonic-gate } 298a5c23cccSraf /* 299a5c23cccSraf * Convert timeval to timespec. 300a5c23cccSraf * To preserve compatibility with past behavior, 301a5c23cccSraf * when select was built upon poll(2), which has a 302a5c23cccSraf * minimum non-zero timeout of 1 millisecond, force 303a5c23cccSraf * a minimum non-zero timeout of 500 microseconds. 304a5c23cccSraf */ 3057c478bd9Sstevel@tonic-gate ts.tv_sec = tv->tv_sec; 3067c478bd9Sstevel@tonic-gate ts.tv_nsec = tv->tv_usec * 1000; 307a5c23cccSraf if (ts.tv_nsec != 0 && ts.tv_nsec < 500000) 308a5c23cccSraf ts.tv_nsec = 500000; 3097c478bd9Sstevel@tonic-gate tsp = &ts; 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate return (pselect(nfds, in0, out0, ex0, tsp, NULL)); 3137c478bd9Sstevel@tonic-gate } 314