diff -r 170fad802bb9 Doc/library/os.rst --- a/Doc/library/os.rst Fri May 27 02:03:06 2011 +0200 +++ b/Doc/library/os.rst Fri May 27 16:01:41 2011 +0200 @@ -1019,6 +1019,17 @@ Availability: Unix, Windows. +.. function:: pipe2(flags=0) + + Create a pipe with *flags* set atomically. + *flags* is optional and can be constructed by ORing together zero or more of + these values: :data:`O_NONBLOCK`, :data:`O_CLOEXEC`. + Return a pair of file descriptors ``(r, w)`` usable for reading and writing, + respectively. + + Availability: some flavors of Unix. + + .. function:: posix_fallocate(fd, offset, len) Ensures that enough disk space is allocated for the file specified by *fd* diff -r 170fad802bb9 Lib/test/test_posix.py --- a/Lib/test/test_posix.py Fri May 27 02:03:06 2011 +0200 +++ b/Lib/test/test_posix.py Fri May 27 16:01:41 2011 +0200 @@ -477,6 +477,31 @@ reader, writer = posix.pipe() os.close(reader) os.close(writer) + + @unittest.skipUnless(hasattr(os, 'pipe2'), "test needs os.pipe2()") + def test_pipe2(self): + self.assertRaises(TypeError, os.pipe2, 'DEADBEEF') + self.assertRaises(TypeError, os.pipe2, (0, 0)) + + # try calling without flag, like os.pipe() + r, w = os.pipe2() + os.close(r) + os.close(w) + + # test flags + r, w = os.pipe2(os.O_CLOEXEC|os.O_NONBLOCK) + self.addCleanup(os.close, r) + self.addCleanup(os.close, w) + self.assertTrue(fcntl.fcntl(r, fcntl.F_GETFD) & fcntl.FD_CLOEXEC) + self.assertTrue(fcntl.fcntl(w, fcntl.F_GETFD) & fcntl.FD_CLOEXEC) + start = time.time() + # try reading from an empty pipe: this should fail, not block + self.assertRaises(OSError, os.read, r, 1) + # try a write big enough to fill-up the pipe (64K on most kernels): this + # should perform a partial write, not block + os.write(w, b'x' * 100000) + # check that this completed quickly + self.assertTrue((time.time() - start) < 1.0, "Test took too long for O_NONBLOCK.") def test_utime(self): if hasattr(posix, 'utime'): diff -r 170fad802bb9 Modules/posixmodule.c --- a/Modules/posixmodule.c Fri May 27 02:03:06 2011 +0200 +++ b/Modules/posixmodule.c Fri May 27 16:01:41 2011 +0200 @@ -6547,6 +6547,31 @@ } #endif /* HAVE_PIPE */ +#ifdef HAVE_PIPE2 +PyDoc_STRVAR(posix_pipe2__doc__, +"pipe2(flags=0) -> (read_end, write_end)\n\n\ +Create a pipe with flags set atomically.\ +flags is optional and can be constructed by ORing together zero or more\n\ +of these values: O_NONBLOCK, O_CLOEXEC.\n\ +"); + +static PyObject * +posix_pipe2(PyObject *self, PyObject *args) +{ + int flags = 0; + int fds[2]; + int res; + + if (!PyArg_ParseTuple(args, "|i:pipe2", &flags)) + return NULL; + + res = pipe2(fds, flags); + if (res != 0) + return posix_error(); + return Py_BuildValue("(ii)", fds[0], fds[1]); +} +#endif /* HAVE_PIPE2 */ + #ifdef HAVE_WRITEV PyDoc_STRVAR(posix_writev__doc__, "writev(fd, buffers) -> byteswritten\n\n\ @@ -9441,6 +9466,9 @@ #ifdef HAVE_PIPE {"pipe", posix_pipe, METH_NOARGS, posix_pipe__doc__}, #endif +#ifdef HAVE_PIPE2 + {"pipe2", posix_pipe2, METH_VARARGS, posix_pipe2__doc__}, +#endif #ifdef HAVE_MKFIFO {"mkfifo", posix_mkfifo, METH_VARARGS, posix_mkfifo__doc__}, #endif