changeset 37188:ae8079a89eec

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 <eblake@redhat.com>
author Eric Blake <eblake@redhat.com>
date Thu, 26 Sep 2013 11:26:29 -0600
parents 7baf7a9d759f
children 82ff83d5d4a7
files ChangeLog doc/glibc-functions/getdtablesize.texi lib/getdtablesize.c lib/unistd.in.h m4/getdtablesize.m4 m4/unistd_h.m4 modules/getdtablesize modules/unistd tests/test-getdtablesize.c
diffstat 9 files changed, 92 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Sep 25 22:27:03 2013 +0200
+++ b/ChangeLog	Thu Sep 26 11:26:29 2013 -0600
@@ -1,3 +1,15 @@
+2013-09-26  Eric Blake  <eblake@redhat.com>
+
+	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  <gnu@gisladisker.se>
 
 	pmccabe2html: escaping of special characters
--- a/doc/glibc-functions/getdtablesize.texi	Wed Sep 25 22:27:03 2013 +0200
+++ b/doc/glibc-functions/getdtablesize.texi	Thu Sep 26 11:26:29 2013 -0600
@@ -9,6 +9,11 @@
 @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:
--- a/lib/getdtablesize.c	Wed Sep 25 22:27:03 2013 +0200
+++ b/lib/getdtablesize.c	Thu Sep 26 11:26:29 2013 -0600
@@ -22,11 +22,11 @@
 
 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 
-#include <stdio.h>
+# include <stdio.h>
 
-#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 @@
 
   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 @@
   return dtablesize;
 }
 
+#elif HAVE_GETDTABLESIZE
+
+# include <sys/resource.h>
+# 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
--- a/lib/unistd.in.h	Wed Sep 25 22:27:03 2013 +0200
+++ b/lib/unistd.in.h	Thu Sep 26 11:26:29 2013 -0600
@@ -654,10 +654,19 @@
 #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
+_GL_CXXALIAS_SYS (getdtablesize, int, (void));
 # endif
-_GL_CXXALIAS_SYS (getdtablesize, int, (void));
 _GL_CXXALIASWARN (getdtablesize);
 #elif defined GNULIB_POSIXCHECK
 # undef getdtablesize
--- a/m4/getdtablesize.m4	Wed Sep 25 22:27:03 2013 +0200
+++ b/m4/getdtablesize.m4	Thu Sep 26 11:26:29 2013 -0600
@@ -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 @@
 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 <unistd.h>]],
+          [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
 ])
--- a/m4/unistd_h.m4	Wed Sep 25 22:27:03 2013 +0200
+++ b/m4/unistd_h.m4	Thu Sep 26 11:26:29 2013 -0600
@@ -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 @@
   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])
--- a/modules/getdtablesize	Wed Sep 25 22:27:03 2013 +0200
+++ b/modules/getdtablesize	Thu Sep 26 11:26:29 2013 -0600
@@ -7,11 +7,12 @@
 
 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 @@
 LGPLv2+
 
 Maintainer:
-Bruno Haible
+Bruno Haible, Eric Blake
 
--- a/modules/unistd	Wed Sep 25 22:27:03 2013 +0200
+++ b/modules/unistd	Thu Sep 26 11:26:29 2013 -0600
@@ -137,6 +137,7 @@
 	      -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' \
--- a/tests/test-getdtablesize.c	Wed Sep 25 22:27:03 2013 +0200
+++ b/tests/test-getdtablesize.c	Thu Sep 26 11:26:29 2013 -0600
@@ -29,6 +29,8 @@
 main (int argc, char *argv[])
 {
   ASSERT (getdtablesize () >= 3);
+  ASSERT (dup2 (0, getdtablesize() - 1) == getdtablesize () - 1);
+  ASSERT (dup2 (0, getdtablesize()) == -1);
 
   return 0;
 }