From 7977ce07470558dbc26b3bc97548aa6e263f4d4c Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 22 Feb 2010 10:12:22 +0000 Subject: 27721: rationalise initialisation of file descriptors --- Src/compat.c | 63 ++++++++++++++++++++++++++++++++---------------------------- Src/exec.c | 2 +- Src/system.h | 10 ++++++++-- Src/utils.c | 38 +++++++++++++++++++++++++----------- 4 files changed, 70 insertions(+), 43 deletions(-) diff --git a/Src/compat.c b/Src/compat.c index ec3a8bc39..5400f627f 100644 --- a/Src/compat.c +++ b/Src/compat.c @@ -187,40 +187,45 @@ zpathmax(char *dir) #endif /* 0 */ #ifdef HAVE_SYSCONF -/* This is replaced by a macro from system.h if not HAVE_SYSCONF. * - * 0 is returned by sysconf if _SC_OPEN_MAX is unavailable; * - * -1 is returned on error * - * * - * Neither of these should happen, but resort to OPEN_MAX rather * - * than return 0 or -1 just in case. */ +/* + * This is replaced by a macro from system.h if not HAVE_SYSCONF. + * 0 is returned by sysconf if _SC_OPEN_MAX is unavailable; + * -1 is returned on error + * + * Neither of these should happen, but resort to OPEN_MAX rather + * than return 0 or -1 just in case. + * + * We'll limit the open maximum to ZSH_INITIAL_OPEN_MAX to + * avoid probing ridiculous numbers of file descriptors. + */ /**/ mod_export long zopenmax(void) { - static long openmax = 0; - - if (openmax < 1) { - if ((openmax = sysconf(_SC_OPEN_MAX)) < 1) { - openmax = OPEN_MAX; - } else if (openmax > OPEN_MAX) { - /* On some systems, "limit descriptors unlimited" or the * - * equivalent will set openmax to a huge number. Unless * - * there actually is a file descriptor > OPEN_MAX already * - * open, nothing in zsh requires the true maximum, and in * - * fact it causes inefficiency elsewhere if we report it. * - * So, report the maximum of OPEN_MAX or the largest open * - * descriptor (is there a better way to find that?). */ - long i, j = OPEN_MAX; - for (i = j; i < openmax; i += (errno != EINTR)) { - errno = 0; - if (fcntl(i, F_GETFL, 0) < 0 && - (errno == EBADF || errno == EINTR)) - continue; - j = i; - } - openmax = j; + long openmax; + + if ((openmax = sysconf(_SC_OPEN_MAX)) < 1) { + openmax = OPEN_MAX; + } else if (openmax > OPEN_MAX) { + /* On some systems, "limit descriptors unlimited" or the * + * equivalent will set openmax to a huge number. Unless * + * there actually is a file descriptor > OPEN_MAX already * + * open, nothing in zsh requires the true maximum, and in * + * fact it causes inefficiency elsewhere if we report it. * + * So, report the maximum of OPEN_MAX or the largest open * + * descriptor (is there a better way to find that?). */ + long i, j = OPEN_MAX; + if (openmax > ZSH_INITIAL_OPEN_MAX) + openmax = ZSH_INITIAL_OPEN_MAX; + for (i = j; i < openmax; i += (errno != EINTR)) { + errno = 0; + if (fcntl(i, F_GETFL, 0) < 0 && + (errno == EBADF || errno == EINTR)) + continue; + j = i; } + openmax = j; } return (max_zsh_fd > openmax) ? max_zsh_fd : openmax; @@ -771,7 +776,7 @@ mk_wcwidth(wchar_t ucs) /* if we arrive here, ucs is not a combining or C0/C1 control character */ - return 1 + + return 1 + (ucs >= 0x1100 && (ucs <= 0x115f || /* Hangul Jamo init. consonants */ ucs == 0x2329 || ucs == 0x232a || diff --git a/Src/exec.c b/Src/exec.c index 02887e1aa..7ba80d986 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1928,7 +1928,7 @@ closeallelse(struct multio *mn) int i, j; long openmax; - openmax = zopenmax(); + openmax = fdtable_size; for (i = 0; i < openmax; i++) if (mn->pipe != i) { diff --git a/Src/system.h b/Src/system.h index 2707d20c9..1c737087f 100644 --- a/Src/system.h +++ b/Src/system.h @@ -304,16 +304,22 @@ struct timezone { # endif #endif +/* + * The number of file descriptors we'll allocate initially. + * We will reallocate later if necessary. + */ +#define ZSH_INITIAL_OPEN_MAX 64 #ifndef OPEN_MAX # ifdef NOFILE # define OPEN_MAX NOFILE # else /* so we will just pick something */ -# define OPEN_MAX 64 +# define OPEN_MAX ZSH_INITIAL_OPEN_MAX # endif #endif #ifndef HAVE_SYSCONF -# define zopenmax() ((long) OPEN_MAX) +# define zopenmax() ((long) (OPEN_MAX > ZSH_INITIAL_OPEN_MAX ? \ + ZSH_INITIAL_OPEN_MAX : OPEN_MAX)) #endif #ifdef HAVE_FCNTL_H diff --git a/Src/utils.c b/Src/utils.c index 221d10d5d..0168c8287 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1621,6 +1621,27 @@ adjustwinsize(int from) } } +/* + * Ensure the fdtable is large enough for fd, and that the + * maximum fd is set appropriately. + */ +static void +check_fd_table(int fd) +{ + if (fd <= max_zsh_fd) + return; + + if (fd >= fdtable_size) { + int old_size = fdtable_size; + while (fd >= fdtable_size) + fdtable = zrealloc(fdtable, + (fdtable_size *= 2)*sizeof(*fdtable)); + memset(fdtable + old_size, 0, + (fdtable_size - old_size) * sizeof(*fdtable)); + } + max_zsh_fd = fd; +} + /* Move a fd to a place >= 10 and mark the new fd in fdtable. If the fd * * is already >= 10, it is not moved. If it is invalid, -1 is returned. */ @@ -1644,12 +1665,7 @@ movefd(int fd) fd = fe; } if(fd != -1) { - if (fd > max_zsh_fd) { - while (fd >= fdtable_size) - fdtable = zrealloc(fdtable, - (fdtable_size *= 2)*sizeof(*fdtable)); - max_zsh_fd = fd; - } + check_fd_table(fd); fdtable[fd] = FDT_INTERNAL; } return fd; @@ -1669,12 +1685,12 @@ redup(int x, int y) if(x < 0) zclose(y); else if (x != y) { - while (y >= fdtable_size) - fdtable = zrealloc(fdtable, (fdtable_size *= 2)*sizeof(*fdtable)); - if (dup2(x, y) == -1) + if (dup2(x, y) == -1) { ret = -1; - if ((fdtable[y] = fdtable[x]) && y > max_zsh_fd) - max_zsh_fd = y; + } else { + check_fd_table(y); + fdtable[y] = fdtable[x]; + } zclose(x); } -- cgit 1.4.1