--- py3k/configure.in 2010-11-27 18:34:12.000000000 +0200 +++ py3k-subprocess2/configure.in 2010-12-11 01:35:45.000000000 +0200 @@ -4235,7 +4235,10 @@ OSF*) AC_MSG_ERROR(OSF* systems are deprecated unless somebody volunteers. Check http://bugs.python.org/issue8606) ;; esac - +case $ac_sys_system in + GNU*|Linux*) + AC_CHECK_FUNC(pipe2, AC_DEFINE(HAVE_PIPE2, 1, [Define if the OS supports pipe2()]), ) +esac AC_SUBST(THREADHEADERS) --- py3k/Modules/_posixsubprocess.c 2010-12-10 20:09:57.000000000 +0200 +++ py3k-subprocess2/Modules/_posixsubprocess.c 2010-12-11 03:03:17.000000000 +0200 @@ -1,6 +1,10 @@ /* Authors: Gregory P. Smith & Jeffrey Yasskin */ #include "Python.h" +#ifdef HAVE_PIPE2 +#define _GNU_SOURCE +#endif #include +#include #define POSIX_CALL(call) if ((call) == -1) goto error @@ -398,6 +402,45 @@ Raises: Only on an error in the parent process.\n\ "); +PyDoc_STRVAR(subprocess_cloexec_pipe_doc, +"cloexec_pipe() -> (read_end, write_end)\n\n\ +Create a pipe whose ends have the cloexec flag set."); + +static PyObject * +subprocess_cloexec_pipe(PyObject *self, PyObject *noargs) +{ + int fds[2]; + int res; +#ifdef HAVE_PIPE2 + Py_BEGIN_ALLOW_THREADS + res = pipe2(fds, O_CLOEXEC); + Py_END_ALLOW_THREADS +#else + /* XXX This isn't atomic, but since subprocess_fork_exec doesn't release the + GIL this shouldn't lead to a race on fork_exec. Still this probably isn't + safe enough. :( */ + long oldflags; + + res = pipe(fds); + + if (res == 0) { + oldflags = fcntl(fds[0], F_GETFD, 0); + if (oldflags < 0) res = oldflags; + } + if (res == 0) + res = fcntl(fds[0], F_SETFD, oldflags | FD_CLOEXEC); + + if (res == 0) { + oldflags = fcntl(fds[1], F_GETFD, 0); + if (oldflags < 0) res = oldflags; + } + if (res == 0) + res = fcntl(fds[1], F_SETFD, oldflags | FD_CLOEXEC); +#endif + if (res != 0) + return PyErr_SetFromErrno(PyExc_OSError); + return Py_BuildValue("(ii)", fds[0], fds[1]); +} /* module level code ********************************************************/ @@ -407,6 +450,7 @@ static PyMethodDef module_methods[] = { {"fork_exec", subprocess_fork_exec, METH_VARARGS, subprocess_fork_exec_doc}, + {"cloexec_pipe", subprocess_cloexec_pipe, METH_NOARGS, subprocess_cloexec_pipe_doc}, {NULL, NULL} /* sentinel */ }; --- py3k/Lib/subprocess.py 2010-12-10 20:09:56.000000000 +0200 +++ py3k-subprocess2/Lib/subprocess.py 2010-12-11 02:31:37.000000000 +0200 @@ -388,6 +388,23 @@ # POSIX defines PIPE_BUF as >= 512. _PIPE_BUF = getattr(select, 'PIPE_BUF', 512) + if _posixsubprocess: + _create_pipe = _posixsubprocess.cloexec_pipe + else: + def _create_pipe(): + try: + cloexec_flag = fcntl.FD_CLOEXEC + except AttributeError: + cloexec_flag = 1 + + fds = os.pipe() + + old = fcntl.fcntl(fds[0], fcntl.F_GETFD) + fcntl.fcntl(fds[0], fcntl.F_SETFD, old | cloexec_flag) + old = fcntl.fcntl(fds[1], fcntl.F_GETFD) + fcntl.fcntl(fds[1], fcntl.F_SETFD, old | cloexec_flag) + + return fds __all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "getstatusoutput", "getoutput", "check_output", "CalledProcessError"] @@ -1032,7 +1049,7 @@ if stdin is None: pass elif stdin == PIPE: - p2cread, p2cwrite = os.pipe() + p2cread, p2cwrite = _create_pipe() elif isinstance(stdin, int): p2cread = stdin else: @@ -1042,7 +1059,7 @@ if stdout is None: pass elif stdout == PIPE: - c2pread, c2pwrite = os.pipe() + c2pread, c2pwrite = _create_pipe() elif isinstance(stdout, int): c2pwrite = stdout else: @@ -1052,7 +1069,7 @@ if stderr is None: pass elif stderr == PIPE: - errread, errwrite = os.pipe() + errread, errwrite = _create_pipe() elif stderr == STDOUT: errwrite = c2pwrite elif isinstance(stderr, int): @@ -1066,16 +1083,6 @@ errread, errwrite) - def _set_cloexec_flag(self, fd): - try: - cloexec_flag = fcntl.FD_CLOEXEC - except AttributeError: - cloexec_flag = 1 - - old = fcntl.fcntl(fd, fcntl.F_GETFD) - fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag) - - def _close_fds(self, but): os.closerange(3, but) os.closerange(but + 1, MAXFD) @@ -1117,10 +1124,9 @@ # For transferring possible exec failure from child to parent. # Data format: "exception name:hex errno:description" # Pickle is not used; it is complex and involves memory allocation. - errpipe_read, errpipe_write = os.pipe() + errpipe_read, errpipe_write = _create_pipe() try: try: - self._set_cloexec_flag(errpipe_write) if _posixsubprocess: # We must avoid complex work that could involve