# HG changeset patch # User Brian Harring # Date 1326602553 28800 # Node ID b1adb2aa57f69f6fb5c2560a9b4ad427b2325ca7 # Parent 40e1be1e0707f25bd493ca6afc0abe69fe1c92d8 optimize closerange to make use of procfs if available For systems where procfs is available, we can pull a list of open file descriptors from it- via this, we can limit closerange to just those open fds rather than iterating over the whole range and issuing close (brute force, basically). If available, this has the benefit of being far faster for common usage of it (primarily subprocess.Popen's close_fds); additionally, it removes a significant amount of noise from strace logs. diff -r 40e1be1e0707 -r b1adb2aa57f6 Modules/posixmodule.c --- a/Modules/posixmodule.c Sat Jan 14 15:45:13 2012 -0800 +++ b/Modules/posixmodule.c Sat Jan 14 20:42:33 2012 -0800 @@ -6866,16 +6866,59 @@ "closerange(fd_low, fd_high)\n\n\ Closes all file descriptors in [fd_low, fd_high), ignoring errors."); -static PyObject * -posix_closerange(PyObject *self, PyObject *args) -{ - int fd_from, fd_to, i; - if (!PyArg_ParseTuple(args, "ii:closerange", &fd_from, &fd_to)) - return NULL; - Py_BEGIN_ALLOW_THREADS - for (i = fd_from; i < fd_to; i++) +static void +posix_slow_closerange(int fd_from, int fd_to) +{ + int i; + for (i = fd_from; i < fd_to; i++) { if (_PyVerify_fd(i)) close(i); + } +} + + +static PyObject * +posix_closerange(PyObject *self, PyObject *args) +{ + int fd_from, fd_to, i; + +#ifndef MSDOS_WINDOWS + DIR *fd_dir; + struct dirent *entry; + char path[MAXPATHLEN]; +#endif + + if (!PyArg_ParseTuple(args, "ii:closerange", &fd_from, &fd_to)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + +#ifdef MSDOS_WINDOWS + posix_slow_closerange(fd_from, fd_to); +#else + PyOS_snprintf(path, MAXPATHLEN, "/proc/%i/fd", getpid()); + fd_dir = opendir(path); + if (fd_dir < 0) { + // We're on a system that lacks /proc fs- + // fallback to brute force closing. + posix_slow_closerange(fd_from, fd_to); + } else { + while ((entry = readdir(fd_dir))) { + // skip .. and . + if (entry->d_name[0] == '.' && ( + (entry->d_name[1] == '.' && entry->d_name[2] == '\0') || + (entry->d_name[2] == '\0'))) + continue; + + i = atoi(entry->d_name); + if (i >= fd_from && i < fd_to && _PyVerify_fd(i)) { + close(i); + } + } + closedir(fd_dir); + } +#endif + Py_END_ALLOW_THREADS Py_RETURN_NONE; }