diff --git a/Misc/NEWS.d/next/C API/2020-10-11-19-17-44.bpo-40423.GsmgEj.rst b/Misc/NEWS.d/next/C API/2020-10-11-19-17-44.bpo-40423.GsmgEj.rst new file mode 100644 index 00000000000..44e571ebf86 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-10-11-19-17-44.bpo-40423.GsmgEj.rst @@ -0,0 +1,3 @@ +The :mod:`subprocess` module and ``os.closerange`` will now use the +``close_range(low, high, flags)`` syscall when it is available for more +efficient closing of ranges of descriptors. \ No newline at end of file diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 321eaec63c4..2e0caaa3e56 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -8741,12 +8741,15 @@ os_close_impl(PyObject *module, int fd) } /* Our selection logic for which function to use is as follows: - * 1. If closefrom(2) is available, we'll attempt to use that next if we're + * 1. If close_range(2) is available, always prefer that; it's better for + * contiguous ranges like this than fdwalk(3) which entails iterating over + * the entire fd space and simply doing nothing for those outside the range. + * 2. If closefrom(2) is available, we'll attempt to use that next if we're * closing up to sysconf(_SC_OPEN_MAX). - * 1a. Fallback to fdwalk(3) if we're not closing up to sysconf(_SC_OPEN_MAX), + * 2a. Fallback to fdwalk(3) if we're not closing up to sysconf(_SC_OPEN_MAX), * as that will be more performant if the range happens to have any chunk of * non-opened fd in the middle. - * 1b. If fdwalk(3) isn't available, just do a plain close(2) loop. + * 2b. If fdwalk(3) isn't available, just do a plain close(2) loop. */ #ifdef __FreeBSD__ #define USE_CLOSEFROM @@ -8779,6 +8782,14 @@ void _Py_closerange(int first, int last) { first = Py_MAX(first, 0); +#ifdef HAVE_CLOSE_RANGE + if (close_range(first, last, 0) == 0 || errno != ENOSYS) { + /* Any errors encountered while closing file descriptors are ignored; + * ENOSYS means no kernel support, though, + * so we'll fallback to the other methods. */ + } + else +#endif /* HAVE_CLOSE_RANGE */ #ifdef USE_CLOSEFROM if (last >= sysconf(_SC_OPEN_MAX)) { /* Any errors encountered while closing file descriptors are ignored */ diff --git a/configure b/configure index ad74754e9a7..89577d85a41 100755 --- a/configure +++ b/configure @@ -11672,8 +11672,8 @@ fi # checks for library functions for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \ - clock confstr copy_file_range ctermid dup3 execv explicit_bzero explicit_memset \ - faccessat fchmod fchmodat fchown fchownat \ + clock confstr close_range copy_file_range ctermid dup3 execv explicit_bzero \ + explicit_memset faccessat fchmod fchmodat fchown fchownat \ fdwalk fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat \ futimens futimes gai_strerror getentropy \ getgrgid_r getgrnam_r \ diff --git a/configure.ac b/configure.ac index f0bc8c62584..3ec274c576e 100644 --- a/configure.ac +++ b/configure.ac @@ -3664,8 +3664,8 @@ fi # checks for library functions AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \ - clock confstr copy_file_range ctermid dup3 execv explicit_bzero explicit_memset \ - faccessat fchmod fchmodat fchown fchownat \ + clock confstr close_range copy_file_range ctermid dup3 execv explicit_bzero \ + explicit_memset faccessat fchmod fchmodat fchown fchownat \ fdwalk fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat \ futimens futimes gai_strerror getentropy \ getgrgid_r getgrnam_r \ diff --git a/pyconfig.h.in b/pyconfig.h.in index c162a3c33e5..298cb4fa12f 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -139,6 +139,9 @@ /* Define to 1 if you have the `clock_settime' function. */ #undef HAVE_CLOCK_SETTIME +/* Define to 1 if you have the `close_range' function. */ +#undef HAVE_CLOSE_RANGE + /* Define if the C compiler supports computed gotos. */ #undef HAVE_COMPUTED_GOTOS