From daafdd5bea1edb0fa980727cf8c52bfe7928d6b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charles-Fran=C3=A7ois=20Natali?= Date: Sun, 29 May 2011 20:07:40 +0200 Subject: [PATCH] Issue #12196: Add pipe2() to the os module. --- Doc/library/os.rst | 13 +++++++++++++ Lib/test/test_posix.py | 25 +++++++++++++++++++++++++ Misc/NEWS | 2 ++ Modules/posixmodule.c | 28 ++++++++++++++++++++++++++++ configure | 10 +--------- configure.in | 4 +--- pyconfig.h.in | 2 +- 7 files changed, 71 insertions(+), 13 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 6ef6d9d25ab..c62a00db7a2 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1019,6 +1019,19 @@ as internal buffering of data. 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. + + .. versionadded:: 3.3 + + .. function:: posix_fallocate(fd, offset, len) Ensures that enough disk space is allocated for the file specified by *fd* diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 9d9802bb7e4..e9103cd8803 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -478,6 +478,31 @@ class PosixTester(unittest.TestCase): 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) + # 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: this should either + # fail or perform a partial write, not block + try: + os.write(w, b'x' * support.PIPE_MAX_SIZE) + except OSError: + pass + def test_utime(self): if hasattr(posix, 'utime'): now = time.time() diff --git a/Misc/NEWS b/Misc/NEWS index 09ad49fee6a..fde085b527d 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -175,6 +175,8 @@ Core and Builtins Library ------- +- Issue #12196: Add pipe2() to the os module. + - Issue #985064: Make plistlib more resilient to faulty input plists. Patch by Mher Movsisyan. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index add3b35c9fc..e529afdb350 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -6547,6 +6547,31 @@ posix_pipe(PyObject *self, PyObject *noargs) } #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 @@ static PyMethodDef posix_methods[] = { #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 diff --git a/configure b/configure index e1ab99b81e9..89a5d704eca 100755 --- a/configure +++ b/configure @@ -9307,7 +9307,7 @@ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \ getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \ if_nameindex \ initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \ - mkfifoat mknod mknodat mktime mremap nice openat pathconf pause plock poll \ + mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \ posix_fallocate posix_fadvise pread \ pthread_init pthread_kill putenv pwrite readlink readlinkat readv realpath renameat \ select sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \ @@ -13824,14 +13824,6 @@ $as_echo "#define HAVE_BROKEN_PIPE_BUF 1" >>confdefs.h esac -ac_fn_c_check_func "$LINENO" "pipe2" "ac_cv_func_pipe2" -if test "x$ac_cv_func_pipe2" = x""yes; then : - -$as_echo "#define HAVE_PIPE2 1" >>confdefs.h - -fi - - for h in `(cd $srcdir;echo Python/thread_*.h)` diff --git a/configure.in b/configure.in index 3bf46b0ed8d..b5f155d7bbf 100644 --- a/configure.in +++ b/configure.in @@ -2531,7 +2531,7 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \ getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \ if_nameindex \ initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \ - mkfifoat mknod mknodat mktime mremap nice openat pathconf pause plock poll \ + mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \ posix_fallocate posix_fadvise pread \ pthread_init pthread_kill putenv pwrite readlink readlinkat readv realpath renameat \ select sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \ @@ -4244,8 +4244,6 @@ AIX*) esac -AC_CHECK_FUNC(pipe2, AC_DEFINE(HAVE_PIPE2, 1, [Define if the OS supports pipe2()]), ) - AC_SUBST(THREADHEADERS) for h in `(cd $srcdir;echo Python/thread_*.h)` diff --git a/pyconfig.h.in b/pyconfig.h.in index 95d71c9c7fb..6c45460e53a 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -560,7 +560,7 @@ /* Define to 1 if you have the `pause' function. */ #undef HAVE_PAUSE -/* Define if the OS supports pipe2() */ +/* Define to 1 if you have the `pipe2' function. */ #undef HAVE_PIPE2 /* Define to 1 if you have the `plock' function. */