diff options
author | Richard Lowe <richlowe@richlowe.net> | 2013-06-20 00:27:41 +0000 |
---|---|---|
committer | Richard Lowe <richlowe@richlowe.net> | 2017-01-25 12:40:33 -0500 |
commit | 2209d3c850d80c0681948f966816f28f767575cb (patch) | |
tree | c6b8f9f9f8f3c87f002c2ed6c50eca5304a95da0 /usr/src/lib/libc | |
parent | 2fc78efe68572a35081bd6d8b1deb2560619c3e6 (diff) | |
download | illumos-joyent-2209d3c850d80c0681948f966816f28f767575cb.tar.gz |
3772 consider raising default descriptor soft limit
Reviewed by: Igor Kozhukhov <igor@dilos.org>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Juraj Lutter <juraj@lutter.sk>
Reviewed by: Patrick Mooney <pmooney@pfmooney.com>
Approved by: Dan McDonald <danmcd@omniti.com>
Diffstat (limited to 'usr/src/lib/libc')
-rw-r--r-- | usr/src/lib/libc/i386/Makefile.com | 1 | ||||
-rw-r--r-- | usr/src/lib/libc/port/gen/select.c | 94 | ||||
-rw-r--r-- | usr/src/lib/libc/port/gen/select_large_fdset.c | 392 | ||||
-rw-r--r-- | usr/src/lib/libc/sparc/Makefile.com | 1 |
4 files changed, 82 insertions, 406 deletions
diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com index c99eab68dc..6f2d3fe494 100644 --- a/usr/src/lib/libc/i386/Makefile.com +++ b/usr/src/lib/libc/i386/Makefile.com @@ -551,7 +551,6 @@ PORTGEN= \ scandir.o \ seekdir.o \ select.o \ - select_large_fdset.o \ setlabel.o \ setpriority.o \ settimeofday.o \ diff --git a/usr/src/lib/libc/port/gen/select.c b/usr/src/lib/libc/port/gen/select.c index ed39ba9efb..24852149ed 100644 --- a/usr/src/lib/libc/port/gen/select.c +++ b/usr/src/lib/libc/port/gen/select.c @@ -27,8 +27,6 @@ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * Emulation of select() system call using poll() system call. * @@ -47,6 +45,7 @@ #include <values.h> #include <pthread.h> #include <errno.h> +#include <stdlib.h> #include <sys/time.h> #include <sys/types.h> #include <sys/select.h> @@ -54,9 +53,58 @@ #include <alloca.h> #include "libc.h" +/* + * STACK_PFD_LIM + * + * The limit at which pselect allocates pollfd structures in the heap, + * rather than on the stack. These limits match the historical behaviour + * with the * _large_fdset implementations. + * + * BULK_ALLOC_LIM + * + * The limit below which we'll just allocate nfds pollfds, rather than + * counting how many we actually need. + */ +#if defined(_LP64) +#define STACK_PFD_LIM FD_SETSIZE +#define BULK_ALLOC_LIM 8192 +#else +#define STACK_PFD_LIM 1024 +#define BULK_ALLOC_LIM 1024 +#endif + +/* + * The previous _large_fdset implementations are, unfortunately, baked into + * the ABI. + */ +#pragma weak select_large_fdset = select +#pragma weak pselect_large_fdset = pselect + +#define fd_set_size(nfds) (((nfds) + (NFDBITS - 1)) / NFDBITS) + +static nfds_t +fd_sets_count(int limit, fd_set *in, fd_set *out, fd_set *ex) +{ + nfds_t total = 0; + + if (limit <= 0) + return (0); + + for (int i = 0; i < fd_set_size(limit); i++) { + long v = (in->fds_bits[i] | out->fds_bits[i] | ex->fds_bits[i]); + + while (v != 0) { + v &= v - 1; + total++; + } + } + + return (total); +} + int pselect(int nfds, fd_set *in0, fd_set *out0, fd_set *ex0, - const timespec_t *tsp, const sigset_t *sigmask) + const timespec_t *tsp, const sigset_t *sigmask) { long *in, *out, *ex; ulong_t m; /* bit mask */ @@ -66,6 +114,8 @@ pselect(int nfds, fd_set *in0, fd_set *out0, fd_set *ex0, struct pollfd *pfd; struct pollfd *p; int lastj = -1; + nfds_t npfds = 0; + boolean_t heap_pfds = B_FALSE; /* "zero" is read-only, it could go in the text segment */ static fd_set zero = { 0 }; @@ -80,7 +130,6 @@ pselect(int nfds, fd_set *in0, fd_set *out0, fd_set *ex0, errno = EINVAL; return (-1); } - p = pfd = (struct pollfd *)alloca(nfds * sizeof (struct pollfd)); if (tsp != NULL) { /* check timespec validity */ @@ -102,6 +151,21 @@ pselect(int nfds, fd_set *in0, fd_set *out0, fd_set *ex0, if (ex0 == NULL) ex0 = &zero; + if (nfds <= BULK_ALLOC_LIM) { + p = pfd = alloca(nfds * sizeof (struct pollfd)); + } else { + npfds = fd_sets_count(nfds, in0, out0, ex0); + + if (npfds > STACK_PFD_LIM) { + p = pfd = malloc(npfds * sizeof (struct pollfd)); + if (p == NULL) + return (-1); + heap_pfds = B_TRUE; + } else { + p = pfd = alloca(npfds * sizeof (struct pollfd)); + } + } + /* * For each fd, if any bits are set convert them into * the appropriate pollfd struct. @@ -134,13 +198,13 @@ done: /* * Now do the poll. */ - n = (int)(p - pfd); /* number of pollfd's */ + npfds = (int)(p - pfd); do { - rv = _pollsys(pfd, (nfds_t)n, tsp, sigmask); + rv = _pollsys(pfd, npfds, tsp, sigmask); } while (rv < 0 && errno == EAGAIN); if (rv < 0) /* no need to set bit masks */ - return (rv); + goto out; if (rv == 0) { /* @@ -163,14 +227,15 @@ done: for (n = 0; n < nfds; n += NFDBITS) *ex++ = 0; } - return (0); + rv = 0; + goto out; } /* * Check for EINVAL error case first to avoid changing any bits * if we're going to return an error. */ - for (p = pfd, j = n; j-- > 0; p++) { + for (p = pfd, n = npfds; n-- > 0; p++) { /* * select will return EBADF immediately if any fd's * are bad. poll will complete the poll on the @@ -181,7 +246,8 @@ done: */ if (p->revents & POLLNVAL) { errno = EBADF; - return (-1); + rv = -1; + goto out; } /* * We would like to make POLLHUP available to select, @@ -194,7 +260,8 @@ done: * if ((p->revents & POLLHUP) && * !(p->revents & (POLLRDNORM|POLLRDBAND))) { * errno = EINTR; - * return (-1); + * rv = -1; + * goto out; * } */ } @@ -212,7 +279,7 @@ done: * (as the man page says, and as poll() does). */ rv = 0; - for (p = pfd; n-- > 0; p++) { + for (p = pfd, n = npfds; n-- > 0; p++) { j = (int)(p->fd / NFDBITS); /* have we moved into another word of the bit mask yet? */ if (j != lastj) { @@ -278,6 +345,9 @@ done: } } } +out: + if (heap_pfds) + free(pfd); return (rv); } diff --git a/usr/src/lib/libc/port/gen/select_large_fdset.c b/usr/src/lib/libc/port/gen/select_large_fdset.c deleted file mode 100644 index 4411d38d58..0000000000 --- a/usr/src/lib/libc/port/gen/select_large_fdset.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* Copyright (c) 1988 AT&T */ -/* All Rights Reserved */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Emulation of select() system call using _pollsys() system call. - * - * Assumptions: - * polling for input only is most common. - * polling for exceptional conditions is very rare. - * - * Note that is it not feasible to emulate all error conditions, - * in particular conditions that would return EFAULT are far too - * difficult to check for in a library routine. - * - * This is the alternate large fd_set select. - * - */ - -/* - * Must precede any include files - */ -#ifdef FD_SETSIZE -#undef FD_SETSIZE -#endif -#define FD_SETSIZE 65536 - -#include "lint.h" -#include <values.h> -#include <stdlib.h> -#include <string.h> -#include <pthread.h> -#include <errno.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/poll.h> -#include <string.h> -#include <stdlib.h> -#include "libc.h" - -#define DEFAULT_POLL_SIZE 64 - -static struct pollfd *realloc_fds(int *, struct pollfd **, struct pollfd *); - -int -pselect_large_fdset(int nfds, fd_set *in0, fd_set *out0, fd_set *ex0, - const timespec_t *tsp, const sigset_t *sigmask) -{ - long *in, *out, *ex; - ulong_t m; /* bit mask */ - int j; /* loop counter */ - ulong_t b; /* bits to test */ - int n, rv; - int lastj = -1; - int nused; - - /* - * Rather than have a mammoth pollfd (65K) list on the stack - * we start with a small one and then malloc larger chunks - * on the heap if necessary. - */ - - struct pollfd pfd[DEFAULT_POLL_SIZE]; - struct pollfd *p; - struct pollfd *pfd_list; - int nfds_on_list; - - fd_set zero; - - /* - * Check for invalid conditions at outset. - * Required for spec1170. - * SUSV3: We must behave as a cancellation point even if we fail early. - */ - if (nfds >= 0 && nfds <= FD_SETSIZE) { - if (tsp != NULL) { - if (tsp->tv_nsec < 0 || tsp->tv_nsec >= NANOSEC || - tsp->tv_sec < 0) { - pthread_testcancel(); - errno = EINVAL; - return (-1); - } - } - } else { - pthread_testcancel(); - errno = EINVAL; - return (-1); - } - - /* - * If any input args are null, point them at the null array. - */ - (void) memset(&zero, 0, sizeof (fd_set)); - if (in0 == NULL) - in0 = &zero; - if (out0 == NULL) - out0 = &zero; - if (ex0 == NULL) - ex0 = &zero; - - nfds_on_list = DEFAULT_POLL_SIZE; - pfd_list = pfd; - p = pfd_list; - (void) memset(pfd, 0, sizeof (pfd)); - /* - * For each fd, if any bits are set convert them into - * the appropriate pollfd struct. - */ - in = (long *)in0->fds_bits; - out = (long *)out0->fds_bits; - ex = (long *)ex0->fds_bits; - nused = 0; - /* - * nused reflects the number of pollfd structs currently used - * less one. If realloc_fds returns NULL it is because malloc - * failed. We expect malloc() to have done the proper - * thing with errno. - */ - for (n = 0; n < nfds; n += NFDBITS) { - b = (ulong_t)(*in | *out | *ex); - for (j = 0, m = 1; b != 0; j++, b >>= 1, m <<= 1) { - if (b & 1) { - p->fd = n + j; - if (p->fd < nfds) { - p->events = 0; - if (*in & m) - p->events |= POLLRDNORM; - if (*out & m) - p->events |= POLLWRNORM; - if (*ex & m) - p->events |= POLLRDBAND; - if (nused < (nfds_on_list - 1)) { - p++; - } else if ((p = realloc_fds( - &nfds_on_list, &pfd_list, pfd)) - == NULL) { - if (pfd_list != pfd) - free(pfd_list); - pthread_testcancel(); - return (-1); - } - nused++; - } else - goto done; - } - } - in++; - out++; - ex++; - } -done: - /* - * Now do the poll. - */ - do { - rv = _pollsys(pfd_list, (nfds_t)nused, tsp, sigmask); - } while (rv < 0 && errno == EAGAIN); - - if (rv < 0) { /* no need to set bit masks */ - if (pfd_list != pfd) - free(pfd_list); - return (rv); - } else if (rv == 0) { - /* - * Clear out bit masks, just in case. - * On the assumption that usually only - * one bit mask is set, use three loops. - */ - if (in0 != &zero) { - in = (long *)in0->fds_bits; - for (n = 0; n < nfds; n += NFDBITS) - *in++ = 0; - } - if (out0 != &zero) { - out = (long *)out0->fds_bits; - for (n = 0; n < nfds; n += NFDBITS) - *out++ = 0; - } - if (ex0 != &zero) { - ex = (long *)ex0->fds_bits; - for (n = 0; n < nfds; n += NFDBITS) - *ex++ = 0; - } - if (pfd_list != pfd) - free(pfd_list); - return (0); - } - - /* - * Check for EINVAL error case first to avoid changing any bits - * if we're going to return an error. - */ - for (p = pfd_list, j = nused; j-- > 0; p++) { - /* - * select will return EBADF immediately if any fd's - * are bad. poll will complete the poll on the - * rest of the fd's and include the error indication - * in the returned bits. This is a rare case so we - * accept this difference and return the error after - * doing more work than select would've done. - */ - if (p->revents & POLLNVAL) { - errno = EBADF; - if (pfd_list != pfd) - free(pfd_list); - return (-1); - } - /* - * We would like to make POLLHUP available to select, - * checking to see if we have pending data to be read. - * BUT until we figure out how not to break Xsun's - * dependencies on select's existing features... - * This is what we _thought_ would work ... sigh! - */ - /* - * if ((p->revents & POLLHUP) && - * !(p->revents & (POLLRDNORM|POLLRDBAND))) { - * errno = EINTR; - * return (-1); - * } - */ - } - - /* - * Convert results of poll back into bits - * in the argument arrays. - * - * We assume POLLRDNORM, POLLWRNORM, and POLLRDBAND will only be set - * on return from poll if they were set on input, thus we don't - * worry about accidentally setting the corresponding bits in the - * zero array if the input bit masks were null. - * - * Must return number of bits set, not number of ready descriptors - * (as the man page says, and as poll() does). - */ - rv = 0; - for (p = pfd_list; nused-- > 0; p++) { - j = (int)(p->fd / NFDBITS); - /* have we moved into another word of the bit mask yet? */ - if (j != lastj) { - /* clear all output bits to start with */ - in = (long *)&in0->fds_bits[j]; - out = (long *)&out0->fds_bits[j]; - ex = (long *)&ex0->fds_bits[j]; - /* - * In case we made "zero" read-only (e.g., with - * cc -R), avoid actually storing into it. - */ - if (in0 != &zero) - *in = 0; - if (out0 != &zero) - *out = 0; - if (ex0 != &zero) - *ex = 0; - lastj = j; - } - if (p->revents) { - m = 1L << (p->fd % NFDBITS); - if (p->revents & POLLRDNORM) { - *in |= m; - rv++; - } - if (p->revents & POLLWRNORM) { - *out |= m; - rv++; - } - if (p->revents & POLLRDBAND) { - *ex |= m; - rv++; - } - /* - * Only set this bit on return if we asked about - * input conditions. - */ - if ((p->revents & (POLLHUP|POLLERR)) && - (p->events & POLLRDNORM)) { - if ((*in & m) == 0) - rv++; /* wasn't already set */ - *in |= m; - } - /* - * Only set this bit on return if we asked about - * output conditions. - */ - if ((p->revents & (POLLHUP|POLLERR)) && - (p->events & POLLWRNORM)) { - if ((*out & m) == 0) - rv++; /* wasn't already set */ - *out |= m; - } - /* - * Only set this bit on return if we asked about - * output conditions. - */ - if ((p->revents & (POLLHUP|POLLERR)) && - (p->events & POLLRDBAND)) { - if ((*ex & m) == 0) - rv++; /* wasn't already set */ - *ex |= m; - } - } - } - if (pfd_list != pfd) - free(pfd_list); - return (rv); -} - -int -select_large_fdset(int nfds, fd_set *in0, fd_set *out0, fd_set *ex0, - struct timeval *tv) -{ - timespec_t ts; - timespec_t *tsp; - - if (tv == NULL) - tsp = NULL; - else { - /* check timeval validity */ - if (tv->tv_usec < 0 || tv->tv_usec >= MICROSEC) { - errno = EINVAL; - return (-1); - } - /* - * Convert timeval to timespec. - * To preserve compatibility with past behavior, - * when select was built upon poll(2), which has a - * minimum non-zero timeout of 1 millisecond, force - * a minimum non-zero timeout of 500 microseconds. - */ - ts.tv_sec = tv->tv_sec; - ts.tv_nsec = tv->tv_usec * 1000; - if (ts.tv_nsec != 0 && ts.tv_nsec < 500000) - ts.tv_nsec = 500000; - tsp = &ts; - } - - return (pselect_large_fdset(nfds, in0, out0, ex0, tsp, NULL)); -} - -/* - * Reallocate buffers of pollfds for our list. We malloc a new buffer - * and, in the case where the old buffer does not match what is passed - * in orig, free the buffer after copying the contents. - */ -struct pollfd * -realloc_fds(int *num, struct pollfd **list_head, struct pollfd *orig) -{ - struct pollfd *b; - int nta; - int n2; - - n2 = *num * 2; - nta = n2 * sizeof (struct pollfd); - b = malloc(nta); - if (b) { - (void) memset(b, 0, (size_t)nta); - (void) memcpy(b, *list_head, nta / 2); - if (*list_head != orig) - free(*list_head); - *list_head = b; - b += *num; - *num = n2; - } - return (b); -} diff --git a/usr/src/lib/libc/sparc/Makefile.com b/usr/src/lib/libc/sparc/Makefile.com index f67bae0a76..2f5f67dd8f 100644 --- a/usr/src/lib/libc/sparc/Makefile.com +++ b/usr/src/lib/libc/sparc/Makefile.com @@ -583,7 +583,6 @@ PORTGEN= \ scandir.o \ seekdir.o \ select.o \ - select_large_fdset.o \ setlabel.o \ setpriority.o \ settimeofday.o \ |