Skip to content

Commit 7992579

Browse files
authored
bpo-40422: Move _Py_closerange to fileutils.c (GH-22680)
This API is relatively lightweight and organizationally, given that it's used by multiple modules, it makes sense to move it to fileutils. Requires making sure that _posixsubprocess is compiled with the appropriate Py_BUIILD_CORE_BUILTIN macro.
1 parent 8b2ff4c commit 7992579

File tree

7 files changed

+83
-80
lines changed

7 files changed

+83
-80
lines changed

Include/internal/pycore_fileutils.h

+2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ PyAPI_FUNC(int) _Py_GetLocaleconvNumeric(
4848
PyObject **decimal_point,
4949
PyObject **thousands_sep);
5050

51+
PyAPI_FUNC(void) _Py_closerange(int first, int last);
52+
5153
#ifdef __cplusplus
5254
}
5355
#endif

Modules/Setup

+1-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ _symtable symtablemodule.c
226226
#termios termios.c # Steen Lumholt's termios module
227227
#resource resource.c # Jeremy Hylton's rlimit interface
228228

229-
#_posixsubprocess _posixsubprocess.c # POSIX subprocess module helper
229+
#_posixsubprocess -DPy_BUILD_CORE_BUILTIN _posixsubprocess.c # POSIX subprocess module helper
230230

231231
# Multimedia modules -- off by default.
232232
# These don't work for 64-bit platforms!!!

Modules/_posixsubprocess.c

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* Authors: Gregory P. Smith & Jeffrey Yasskin */
22
#include "Python.h"
3+
#include "pycore_fileutils.h"
34
#if defined(HAVE_PIPE2) && !defined(_GNU_SOURCE)
45
# define _GNU_SOURCE
56
#endif

Modules/posixmodule.c

+1-76
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#define PY_SSIZE_T_CLEAN
2323

2424
#include "Python.h"
25+
#include "pycore_fileutils.h"
2526
#ifdef MS_WINDOWS
2627
/* include <windows.h> early to avoid conflict with pycore_condvar.h:
2728
@@ -8740,82 +8741,6 @@ os_close_impl(PyObject *module, int fd)
87408741
Py_RETURN_NONE;
87418742
}
87428743

8743-
/* Our selection logic for which function to use is as follows:
8744-
* 1. If close_range(2) is available, always prefer that; it's better for
8745-
* contiguous ranges like this than fdwalk(3) which entails iterating over
8746-
* the entire fd space and simply doing nothing for those outside the range.
8747-
* 2. If closefrom(2) is available, we'll attempt to use that next if we're
8748-
* closing up to sysconf(_SC_OPEN_MAX).
8749-
* 2a. Fallback to fdwalk(3) if we're not closing up to sysconf(_SC_OPEN_MAX),
8750-
* as that will be more performant if the range happens to have any chunk of
8751-
* non-opened fd in the middle.
8752-
* 2b. If fdwalk(3) isn't available, just do a plain close(2) loop.
8753-
*/
8754-
#ifdef __FreeBSD__
8755-
#define USE_CLOSEFROM
8756-
#endif /* __FreeBSD__ */
8757-
8758-
#ifdef HAVE_FDWALK
8759-
#define USE_FDWALK
8760-
#endif /* HAVE_FDWALK */
8761-
8762-
#ifdef USE_FDWALK
8763-
static int
8764-
_fdwalk_close_func(void *lohi, int fd)
8765-
{
8766-
int lo = ((int *)lohi)[0];
8767-
int hi = ((int *)lohi)[1];
8768-
8769-
if (fd >= hi) {
8770-
return 1;
8771-
}
8772-
else if (fd >= lo) {
8773-
/* Ignore errors */
8774-
(void)close(fd);
8775-
}
8776-
return 0;
8777-
}
8778-
#endif /* USE_FDWALK */
8779-
8780-
/* Closes all file descriptors in [first, last], ignoring errors. */
8781-
void
8782-
_Py_closerange(int first, int last)
8783-
{
8784-
first = Py_MAX(first, 0);
8785-
_Py_BEGIN_SUPPRESS_IPH
8786-
#ifdef HAVE_CLOSE_RANGE
8787-
if (close_range(first, last, 0) == 0 || errno != ENOSYS) {
8788-
/* Any errors encountered while closing file descriptors are ignored;
8789-
* ENOSYS means no kernel support, though,
8790-
* so we'll fallback to the other methods. */
8791-
}
8792-
else
8793-
#endif /* HAVE_CLOSE_RANGE */
8794-
#ifdef USE_CLOSEFROM
8795-
if (last >= sysconf(_SC_OPEN_MAX)) {
8796-
/* Any errors encountered while closing file descriptors are ignored */
8797-
closefrom(first);
8798-
}
8799-
else
8800-
#endif /* USE_CLOSEFROM */
8801-
#ifdef USE_FDWALK
8802-
{
8803-
int lohi[2];
8804-
lohi[0] = first;
8805-
lohi[1] = last + 1;
8806-
fdwalk(_fdwalk_close_func, lohi);
8807-
}
8808-
#else
8809-
{
8810-
for (int i = first; i <= last; i++) {
8811-
/* Ignore errors */
8812-
(void)close(i);
8813-
}
8814-
}
8815-
#endif /* USE_FDWALK */
8816-
_Py_END_SUPPRESS_IPH
8817-
}
8818-
88198744
/*[clinic input]
88208745
os.closerange
88218746

Modules/posixmodule.h

-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ PyAPI_FUNC(int) _Py_Sigset_Converter(PyObject *, void *);
2828
#endif /* HAVE_SIGSET_T */
2929
#endif /* Py_LIMITED_API */
3030

31-
PyAPI_FUNC(void) _Py_closerange(int first, int last);
32-
3331
#ifdef __cplusplus
3432
}
3533
#endif

Python/fileutils.c

+76
Original file line numberDiff line numberDiff line change
@@ -2106,3 +2106,79 @@ _Py_GetLocaleconvNumeric(struct lconv *lc,
21062106
PyMem_Free(oldloc);
21072107
return res;
21082108
}
2109+
2110+
/* Our selection logic for which function to use is as follows:
2111+
* 1. If close_range(2) is available, always prefer that; it's better for
2112+
* contiguous ranges like this than fdwalk(3) which entails iterating over
2113+
* the entire fd space and simply doing nothing for those outside the range.
2114+
* 2. If closefrom(2) is available, we'll attempt to use that next if we're
2115+
* closing up to sysconf(_SC_OPEN_MAX).
2116+
* 2a. Fallback to fdwalk(3) if we're not closing up to sysconf(_SC_OPEN_MAX),
2117+
* as that will be more performant if the range happens to have any chunk of
2118+
* non-opened fd in the middle.
2119+
* 2b. If fdwalk(3) isn't available, just do a plain close(2) loop.
2120+
*/
2121+
#ifdef __FreeBSD__
2122+
# define USE_CLOSEFROM
2123+
#endif /* __FreeBSD__ */
2124+
2125+
#ifdef HAVE_FDWALK
2126+
# define USE_FDWALK
2127+
#endif /* HAVE_FDWALK */
2128+
2129+
#ifdef USE_FDWALK
2130+
static int
2131+
_fdwalk_close_func(void *lohi, int fd)
2132+
{
2133+
int lo = ((int *)lohi)[0];
2134+
int hi = ((int *)lohi)[1];
2135+
2136+
if (fd >= hi) {
2137+
return 1;
2138+
}
2139+
else if (fd >= lo) {
2140+
/* Ignore errors */
2141+
(void)close(fd);
2142+
}
2143+
return 0;
2144+
}
2145+
#endif /* USE_FDWALK */
2146+
2147+
/* Closes all file descriptors in [first, last], ignoring errors. */
2148+
void
2149+
_Py_closerange(int first, int last)
2150+
{
2151+
first = Py_MAX(first, 0);
2152+
_Py_BEGIN_SUPPRESS_IPH
2153+
#ifdef HAVE_CLOSE_RANGE
2154+
if (close_range(first, last, 0) == 0 || errno != ENOSYS) {
2155+
/* Any errors encountered while closing file descriptors are ignored;
2156+
* ENOSYS means no kernel support, though,
2157+
* so we'll fallback to the other methods. */
2158+
}
2159+
else
2160+
#endif /* HAVE_CLOSE_RANGE */
2161+
#ifdef USE_CLOSEFROM
2162+
if (last >= sysconf(_SC_OPEN_MAX)) {
2163+
/* Any errors encountered while closing file descriptors are ignored */
2164+
closefrom(first);
2165+
}
2166+
else
2167+
#endif /* USE_CLOSEFROM */
2168+
#ifdef USE_FDWALK
2169+
{
2170+
int lohi[2];
2171+
lohi[0] = first;
2172+
lohi[1] = last + 1;
2173+
fdwalk(_fdwalk_close_func, lohi);
2174+
}
2175+
#else
2176+
{
2177+
for (int i = first; i <= last; i++) {
2178+
/* Ignore errors */
2179+
(void)close(i);
2180+
}
2181+
}
2182+
#endif /* USE_FDWALK */
2183+
_Py_END_SUPPRESS_IPH
2184+
}

setup.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,8 @@ def detect_simple_extensions(self):
950950
self.add(Extension('_csv', ['_csv.c']))
951951

952952
# POSIX subprocess module helper.
953-
self.add(Extension('_posixsubprocess', ['_posixsubprocess.c']))
953+
self.add(Extension('_posixsubprocess', ['_posixsubprocess.c'],
954+
extra_compile_args=['-DPy_BUILD_CORE_MODULE']))
954955

955956
def detect_test_extensions(self):
956957
# Python C API test module

0 commit comments

Comments
 (0)