summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2008-01-19 20:22:13 (GMT)
committerGeorg Brandl <georg@python.org>2008-01-19 20:22:13 (GMT)
commit309501a61772f4cb72f1004fcbe73964b4130672 (patch)
tree8737924e043d901d7c62910a97c6aebdd8e62f8e
parent15ce880cc8c3de29e91e2e867b2db0b19a48e5f3 (diff)
downloadcpython-309501a61772f4cb72f1004fcbe73964b4130672.zip
cpython-309501a61772f4cb72f1004fcbe73964b4130672.tar.gz
cpython-309501a61772f4cb72f1004fcbe73964b4130672.tar.bz2
#1663329: add os.closerange() to close a range of fds,
ignoring errors, and use this in subprocess to speed up subprocess creation in close_fds mode. Patch by Mike Klaas.
-rw-r--r--Doc/library/os.rst14
-rw-r--r--Lib/subprocess.py9
-rw-r--r--Lib/test/test_os.py6
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/posixmodule.c19
5 files changed, 44 insertions, 7 deletions
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index b39ec1b..ff37d10 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -481,6 +481,20 @@ by file descriptors.
:func:`fdopen`, use its :meth:`close` method.
+.. function:: closerange(fd_low, fd_high)
+
+ Close all file descriptors from *fd_low* (inclusive) to *fd_high* (exclusive),
+ ignoring errors. Availability: Macintosh, Unix, Windows. Equivalent to::
+
+ for fd in xrange(fd_low, fd_high):
+ try:
+ os.close(fd)
+ except OSError:
+ pass
+
+ .. versionadded:: 2.6
+
+
.. function:: dup(fd)
Return a duplicate of file descriptor *fd*. Availability: Macintosh, Unix,
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index ca9489e..29c25bc 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -965,13 +965,8 @@ class Popen(object):
def _close_fds(self, but):
- for i in xrange(3, MAXFD):
- if i == but:
- continue
- try:
- os.close(i)
- except:
- pass
+ os.closerange(3, but)
+ os.closerange(but + 1, MAXFD)
def _execute_child(self, args, executable, preexec_fn, close_fds,
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 52fdd8a..a6fe40e 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -23,6 +23,12 @@ class FileTests(unittest.TestCase):
os.close(f)
self.assert_(os.access(test_support.TESTFN, os.W_OK))
+ def test_closerange(self):
+ f = os.open(test_support.TESTFN, os.O_CREAT|os.O_RDWR)
+ # close a fd that is open, and one that isn't
+ os.closerange(f, f+2)
+ self.assertRaises(OSError, os.write, f, "a")
+
class TemporaryFileTests(unittest.TestCase):
def setUp(self):
diff --git a/Misc/NEWS b/Misc/NEWS
index fdf1e86..f7c7aac 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -1019,6 +1019,9 @@ Library
Extension Modules
-----------------
+- Patch #1663329: added ``os.closerange()`` function to quickly close a range
+ of file descriptors without considering errors.
+
- Patch 976880: ``mmap`` objects now have an ``rfind`` method that
works as expected. ``mmap.find`` also takes an optional ``end``
parameter.
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 696df0d..0038703 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -6156,6 +6156,24 @@ posix_close(PyObject *self, PyObject *args)
}
+PyDoc_STRVAR(posix_closerange__doc__,
+"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++)
+ close(i);
+ Py_END_ALLOW_THREADS
+ Py_RETURN_NONE;
+}
+
+
PyDoc_STRVAR(posix_dup__doc__,
"dup(fd) -> fd2\n\n\
Return a duplicate of a file descriptor.");
@@ -8451,6 +8469,7 @@ static PyMethodDef posix_methods[] = {
#endif /* HAVE_TCSETPGRP */
{"open", posix_open, METH_VARARGS, posix_open__doc__},
{"close", posix_close, METH_VARARGS, posix_close__doc__},
+ {"closerange", posix_closerange, METH_VARARGS, posix_closerange__doc__},
{"dup", posix_dup, METH_VARARGS, posix_dup__doc__},
{"dup2", posix_dup2, METH_VARARGS, posix_dup2__doc__},
{"lseek", posix_lseek, METH_VARARGS, posix_lseek__doc__},