From 3bd0d48db800994cc10c3340c41d3242390dc68f Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 26 Sep 2013 11:26:29 -0600 Subject: [PATCH] getdtablesize: work around cygwin issue Cygwin 1.7.25 has a bug that even though it claims to support RLIMIT_NOFILE inheritance, there is no enforcement of the soft limit, and getdtablesize() automatically grows until it reaches the hard limit which cannot be changed by setrlimit(). Best is to just treat things as an invariant limit, as several other modules assume that getdtablesize() will not change without an intervening setrlimit(). * m4/getdtablesize.m4 (gl_FUNC_GETDTABLESIZE): Detect problem. * modules/getdtablesize (configure.ac): Build replacement. * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Set up a witness. * modules/unistd (Makefile.am): Expose the witness. * lib/unistd.in.h (getdtablesize): Declare replacement. * lib/getdtablesize.c (rpl_getdtablesize): Work around it. * tests/test-getdtablesize.c (main): Test it. * doc/glibc-functions/getdtablesize.texi (getdtablesize): Document it. Signed-off-by: Eric Blake --- ChangeLog | 12 ++++++++++++ doc/glibc-functions/getdtablesize.texi | 5 +++++ lib/getdtablesize.c | 33 +++++++++++++++++++++++++++------ lib/unistd.in.h | 13 +++++++++++-- m4/getdtablesize.m4 | 31 +++++++++++++++++++++++++++++-- m4/unistd_h.m4 | 3 ++- modules/getdtablesize | 5 +++-- modules/unistd | 1 + tests/test-getdtablesize.c | 2 ++ 9 files changed, 92 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index 770710c0b..812ea5483 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2013-09-26 Eric Blake + + getdtablesize: work around cygwin issue + * m4/getdtablesize.m4 (gl_FUNC_GETDTABLESIZE): Detect problem. + * modules/getdtablesize (configure.ac): Build replacement. + * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Set up a witness. + * modules/unistd (Makefile.am): Expose the witness. + * lib/unistd.in.h (getdtablesize): Declare replacement. + * lib/getdtablesize.c (rpl_getdtablesize): Work around it. + * tests/test-getdtablesize.c (main): Test it. + * doc/glibc-functions/getdtablesize.texi (getdtablesize): Document it. + 2013-09-25 Mats Erik Andersson pmccabe2html: escaping of special characters diff --git a/doc/glibc-functions/getdtablesize.texi b/doc/glibc-functions/getdtablesize.texi index d342b2f52..c28a54653 100644 --- a/doc/glibc-functions/getdtablesize.texi +++ b/doc/glibc-functions/getdtablesize.texi @@ -9,6 +9,11 @@ Portability problems fixed by Gnulib: @item This function is missing on some platforms: mingw, MSVC 9. + +@item +This function does not represent the true @code{RLIMIT_NOFILE} soft +limit on some platforms: +Cygwin 1.7.25. @end itemize Portability problems not fixed by Gnulib: diff --git a/lib/getdtablesize.c b/lib/getdtablesize.c index 9947405af..355c17e3b 100644 --- a/lib/getdtablesize.c +++ b/lib/getdtablesize.c @@ -22,11 +22,11 @@ #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ -#include +# include -#include "msvc-inval.h" +# include "msvc-inval.h" -#if HAVE_MSVC_INVALID_PARAMETER_HANDLER +# if HAVE_MSVC_INVALID_PARAMETER_HANDLER static int _setmaxstdio_nothrow (int newmax) { @@ -44,10 +44,11 @@ _setmaxstdio_nothrow (int newmax) return result; } -# define _setmaxstdio _setmaxstdio_nothrow -#endif +# define _setmaxstdio _setmaxstdio_nothrow +# endif -/* Cache for the previous getdtablesize () result. */ +/* Cache for the previous getdtablesize () result. Safe to cache because + Windows also lacks setrlimit. */ static int dtablesize; int @@ -83,4 +84,24 @@ getdtablesize (void) return dtablesize; } +#elif HAVE_GETDTABLESIZE + +# include +# undef getdtablesize + +int +rpl_getdtablesize(void) +{ + /* To date, this replacement is only compiled for Cygwin 1.7.25, + which auto-increased the RLIMIT_NOFILE soft limit until it + hits the compile-time constant hard limit of 3200. Although + that version of cygwin supported a child process inheriting + a smaller soft limit, the smaller limit is not enforced, so + we might as well just report the hard limit. */ + struct rlimit lim; + if (!getrlimit (RLIMIT_NOFILE, &lim) && lim.rlim_max != RLIM_INFINITY) + return lim.rlim_max; + return getdtablesize (); +} + #endif diff --git a/lib/unistd.in.h b/lib/unistd.in.h index 2543a4000..bd2b09961 100644 --- a/lib/unistd.in.h +++ b/lib/unistd.in.h @@ -654,10 +654,19 @@ _GL_WARN_ON_USE (getdomainname, "getdomainname is unportable - " #if @GNULIB_GETDTABLESIZE@ /* Return the maximum number of file descriptors in the current process. In POSIX, this is same as sysconf (_SC_OPEN_MAX). */ -# if !@HAVE_GETDTABLESIZE@ +# if @REPLACE_GETDTABLESIZE@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef getdtablesize +# define getdtablesize rpl_getdtablesize +# endif +_GL_FUNCDECL_RPL (getdtablesize, int, (void)); +_GL_CXXALIAS_RPL (getdtablesize, int, (void)); +# else +# if !@HAVE_GETDTABLESIZE@ _GL_FUNCDECL_SYS (getdtablesize, int, (void)); -# endif +# endif _GL_CXXALIAS_SYS (getdtablesize, int, (void)); +# endif _GL_CXXALIASWARN (getdtablesize); #elif defined GNULIB_POSIXCHECK # undef getdtablesize diff --git a/m4/getdtablesize.m4 b/m4/getdtablesize.m4 index 8f04b3b8c..b3fa1af6a 100644 --- a/m4/getdtablesize.m4 +++ b/m4/getdtablesize.m4 @@ -1,4 +1,4 @@ -# getdtablesize.m4 serial 4 +# getdtablesize.m4 serial 5 dnl Copyright (C) 2008-2013 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -7,8 +7,35 @@ dnl with or without modifications, as long as this notice is preserved. AC_DEFUN([gl_FUNC_GETDTABLESIZE], [ AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) + AC_REQUIRE([AC_CANONICAL_HOST]) AC_CHECK_FUNCS_ONCE([getdtablesize]) - if test $ac_cv_func_getdtablesize != yes; then + if test $ac_cv_func_getdtablesize = yes; then + # Cygwin 1.7.25 automatically increases the RLIMIT_NOFILE soft limit + # up to an unchangeable hard limit; all other platforms correctly + # require setrlimit before getdtablesize() can report a larger value. + AC_CACHE_CHECK([whether getdtablesize works], + [gl_cv_func_getdtablesize_works], + [AC_RUN_IFELSE([ + AC_LANG_PROGRAM([[#include ]], + [int size = getdtablesize(); + if (dup2 (0, getdtablesize()) != -1) + return 1; + if (size != getdtablesize()) + return 2; + ])], + [gl_cv_func_getdtablesize_works=yes], + [gl_cv_func_getdtablesize_works=no], + [case "$host_os" in + cygwin*) # on cygwin 1.5.25, getdtablesize() automatically grows + gl_cv_func_getdtablesize_works="guessing no" ;; + *) gl_cv_func_getdtablesize_works="guessing yes" ;; + esac]) + ]) + case "$gl_cv_func_getdtablesize_works" in + *yes) ;; + *) REPLACE_GETDTABLESIZE=1 ;; + esac + else HAVE_GETDTABLESIZE=0 fi ]) diff --git a/m4/unistd_h.m4 b/m4/unistd_h.m4 index 32dcfa582..4231578cf 100644 --- a/m4/unistd_h.m4 +++ b/m4/unistd_h.m4 @@ -1,4 +1,4 @@ -# unistd_h.m4 serial 66 +# unistd_h.m4 serial 67 dnl Copyright (C) 2006-2013 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -160,6 +160,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS], REPLACE_FTRUNCATE=0; AC_SUBST([REPLACE_FTRUNCATE]) REPLACE_GETCWD=0; AC_SUBST([REPLACE_GETCWD]) REPLACE_GETDOMAINNAME=0; AC_SUBST([REPLACE_GETDOMAINNAME]) + REPLACE_GETDTABLESIZE=0; AC_SUBST([REPLACE_GETDTABLESIZE]) REPLACE_GETLOGIN_R=0; AC_SUBST([REPLACE_GETLOGIN_R]) REPLACE_GETGROUPS=0; AC_SUBST([REPLACE_GETGROUPS]) REPLACE_GETPAGESIZE=0; AC_SUBST([REPLACE_GETPAGESIZE]) diff --git a/modules/getdtablesize b/modules/getdtablesize index 109be1fda..1c2d64277 100644 --- a/modules/getdtablesize +++ b/modules/getdtablesize @@ -7,11 +7,12 @@ m4/getdtablesize.m4 Depends-on: unistd +extensions msvc-inval [test $HAVE_GETDTABLESIZE = 0] configure.ac: gl_FUNC_GETDTABLESIZE -if test $HAVE_GETDTABLESIZE = 0; then +if test $HAVE_GETDTABLESIZE = 0 || test $REPLACE_GETDTABLESIZE = 1; then AC_LIBOBJ([getdtablesize]) gl_PREREQ_GETDTABLESIZE fi @@ -26,5 +27,5 @@ License: LGPLv2+ Maintainer: -Bruno Haible +Bruno Haible, Eric Blake diff --git a/modules/unistd b/modules/unistd index c887d4f16..c470ba602 100644 --- a/modules/unistd +++ b/modules/unistd @@ -137,6 +137,7 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H -e 's|@''REPLACE_FTRUNCATE''@|$(REPLACE_FTRUNCATE)|g' \ -e 's|@''REPLACE_GETCWD''@|$(REPLACE_GETCWD)|g' \ -e 's|@''REPLACE_GETDOMAINNAME''@|$(REPLACE_GETDOMAINNAME)|g' \ + -e 's|@''REPLACE_GETDTABLESIZE''@|$(REPLACE_GETDTABLESIZE)|g' \ -e 's|@''REPLACE_GETLOGIN_R''@|$(REPLACE_GETLOGIN_R)|g' \ -e 's|@''REPLACE_GETGROUPS''@|$(REPLACE_GETGROUPS)|g' \ -e 's|@''REPLACE_GETPAGESIZE''@|$(REPLACE_GETPAGESIZE)|g' \ diff --git a/tests/test-getdtablesize.c b/tests/test-getdtablesize.c index 7046481ba..b371ccf0d 100644 --- a/tests/test-getdtablesize.c +++ b/tests/test-getdtablesize.c @@ -29,6 +29,8 @@ int main (int argc, char *argv[]) { ASSERT (getdtablesize () >= 3); + ASSERT (dup2 (0, getdtablesize() - 1) == getdtablesize () - 1); + ASSERT (dup2 (0, getdtablesize()) == -1); return 0; } -- 2.11.0