# HG changeset patch # User Brian Harring # Date 1326601474 28800 # Branch legacy-trunk # Node ID f01f10b6864cab7374a09be54b5b079f656ddf82 # Parent b77918288f7d20e82b61020826cc9dfa09be4fd2 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 b77918288f7d -r f01f10b6864c Modules/posixmodule.c --- a/Modules/posixmodule.c Sat Mar 05 14:57:44 2011 +0100 +++ b/Modules/posixmodule.c Sat Jan 14 20:24:34 2012 -0800 @@ -6375,16 +6375,58 @@ "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 +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; }