summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorPablo Galindo <Pablogsal@gmail.com>2018-01-27 16:16:37 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2018-01-27 16:16:37 (GMT)
commit4defba3b95ec0f52ce75b8466831d30fb5d333f3 (patch)
treeafd798704c96cc3f12a1ae38ede0863ffef56938 /Modules
parent60da99b8e2f7bf497569ae4d6c218866575729bf (diff)
downloadcpython-4defba3b95ec0f52ce75b8466831d30fb5d333f3.zip
cpython-4defba3b95ec0f52ce75b8466831d30fb5d333f3.tar.gz
cpython-4defba3b95ec0f52ce75b8466831d30fb5d333f3.tar.bz2
bpo-31368: Expose preadv and pwritev in the os module (#5239)
Diffstat (limited to 'Modules')
-rw-r--r--Modules/clinic/posixmodule.c.h120
-rw-r--r--Modules/posixmodule.c194
2 files changed, 313 insertions, 1 deletions
diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h
index 6f4c028..f432437 100644
--- a/Modules/clinic/posixmodule.c.h
+++ b/Modules/clinic/posixmodule.c.h
@@ -3705,6 +3705,61 @@ exit:
#endif /* defined(HAVE_PREAD) */
+#if (defined(HAVE_PREADV) || defined (HAVE_PREADV2))
+
+PyDoc_STRVAR(os_preadv__doc__,
+"preadv($module, fd, buffers, offset, flags=0, /)\n"
+"--\n"
+"\n"
+"Reads from a file descriptor into a number of mutable bytes-like objects.\n"
+"\n"
+"Combines the functionality of readv() and pread(). As readv(), it will\n"
+"transfer data into each buffer until it is full and then move on to the next\n"
+"buffer in the sequence to hold the rest of the data. Its fourth argument,\n"
+"specifies the file offset at which the input operation is to be performed. It\n"
+"will return the total number of bytes read (which can be less than the total\n"
+"capacity of all the objects).\n"
+"\n"
+"The flags argument contains a bitwise OR of zero or more of the following flags:\n"
+"\n"
+"- RWF_HIPRI\n"
+"- RWF_NOWAIT\n"
+"\n"
+"Using non-zero flags requires Linux 4.6 or newer.");
+
+#define OS_PREADV_METHODDEF \
+ {"preadv", (PyCFunction)os_preadv, METH_FASTCALL, os_preadv__doc__},
+
+static Py_ssize_t
+os_preadv_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset,
+ int flags);
+
+static PyObject *
+os_preadv(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ int fd;
+ PyObject *buffers;
+ Py_off_t offset;
+ int flags = 0;
+ Py_ssize_t _return_value;
+
+ if (!_PyArg_ParseStack(args, nargs, "iOO&|i:preadv",
+ &fd, &buffers, Py_off_t_converter, &offset, &flags)) {
+ goto exit;
+ }
+ _return_value = os_preadv_impl(module, fd, buffers, offset, flags);
+ if ((_return_value == -1) && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = PyLong_FromSsize_t(_return_value);
+
+exit:
+ return return_value;
+}
+
+#endif /* (defined(HAVE_PREADV) || defined (HAVE_PREADV2)) */
+
PyDoc_STRVAR(os_write__doc__,
"write($module, fd, data, /)\n"
"--\n"
@@ -3963,6 +4018,61 @@ exit:
#endif /* defined(HAVE_PWRITE) */
+#if (defined(HAVE_PWRITEV) || defined (HAVE_PWRITEV2))
+
+PyDoc_STRVAR(os_pwritev__doc__,
+"pwritev($module, fd, buffers, offset, flags=0, /)\n"
+"--\n"
+"\n"
+"Writes the contents of bytes-like objects to a file descriptor at a given offset.\n"
+"\n"
+"Combines the functionality of writev() and pwrite(). All buffers must be a sequence\n"
+"of bytes-like objects. Buffers are processed in array order. Entire contents of first\n"
+"buffer is written before proceeding to second, and so on. The operating system may\n"
+"set a limit (sysconf() value SC_IOV_MAX) on the number of buffers that can be used.\n"
+"This function writes the contents of each object to the file descriptor and returns\n"
+"the total number of bytes written.\n"
+"\n"
+"The flags argument contains a bitwise OR of zero or more of the following flags:\n"
+"\n"
+"- RWF_DSYNC\n"
+"- RWF_SYNC\n"
+"\n"
+"Using non-zero flags requires Linux 4.7 or newer.");
+
+#define OS_PWRITEV_METHODDEF \
+ {"pwritev", (PyCFunction)os_pwritev, METH_FASTCALL, os_pwritev__doc__},
+
+static Py_ssize_t
+os_pwritev_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset,
+ int flags);
+
+static PyObject *
+os_pwritev(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ int fd;
+ PyObject *buffers;
+ Py_off_t offset;
+ int flags = 0;
+ Py_ssize_t _return_value;
+
+ if (!_PyArg_ParseStack(args, nargs, "iOO&|i:pwritev",
+ &fd, &buffers, Py_off_t_converter, &offset, &flags)) {
+ goto exit;
+ }
+ _return_value = os_pwritev_impl(module, fd, buffers, offset, flags);
+ if ((_return_value == -1) && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = PyLong_FromSsize_t(_return_value);
+
+exit:
+ return return_value;
+}
+
+#endif /* (defined(HAVE_PWRITEV) || defined (HAVE_PWRITEV2)) */
+
#if defined(HAVE_MKFIFO)
PyDoc_STRVAR(os_mkfifo__doc__,
@@ -6239,6 +6349,10 @@ exit:
#define OS_PREAD_METHODDEF
#endif /* !defined(OS_PREAD_METHODDEF) */
+#ifndef OS_PREADV_METHODDEF
+ #define OS_PREADV_METHODDEF
+#endif /* !defined(OS_PREADV_METHODDEF) */
+
#ifndef OS_PIPE_METHODDEF
#define OS_PIPE_METHODDEF
#endif /* !defined(OS_PIPE_METHODDEF) */
@@ -6255,6 +6369,10 @@ exit:
#define OS_PWRITE_METHODDEF
#endif /* !defined(OS_PWRITE_METHODDEF) */
+#ifndef OS_PWRITEV_METHODDEF
+ #define OS_PWRITEV_METHODDEF
+#endif /* !defined(OS_PWRITEV_METHODDEF) */
+
#ifndef OS_MKFIFO_METHODDEF
#define OS_MKFIFO_METHODDEF
#endif /* !defined(OS_MKFIFO_METHODDEF) */
@@ -6410,4 +6528,4 @@ exit:
#ifndef OS_GETRANDOM_METHODDEF
#define OS_GETRANDOM_METHODDEF
#endif /* !defined(OS_GETRANDOM_METHODDEF) */
-/*[clinic end generated code: output=6345053cd5992caf input=a9049054013a1b77]*/
+/*[clinic end generated code: output=06ace805893aa10c input=a9049054013a1b77]*/
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index b0e48da..a1a38eb 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -8163,6 +8163,94 @@ os_pread_impl(PyObject *module, int fd, int length, Py_off_t offset)
}
#endif /* HAVE_PREAD */
+#if defined(HAVE_PREADV) || defined (HAVE_PREADV2)
+/*[clinic input]
+os.preadv -> Py_ssize_t
+
+ fd: int
+ buffers: object
+ offset: Py_off_t
+ flags: int = 0
+ /
+
+Reads from a file descriptor into a number of mutable bytes-like objects.
+
+Combines the functionality of readv() and pread(). As readv(), it will
+transfer data into each buffer until it is full and then move on to the next
+buffer in the sequence to hold the rest of the data. Its fourth argument,
+specifies the file offset at which the input operation is to be performed. It
+will return the total number of bytes read (which can be less than the total
+capacity of all the objects).
+
+The flags argument contains a bitwise OR of zero or more of the following flags:
+
+- RWF_HIPRI
+- RWF_NOWAIT
+
+Using non-zero flags requires Linux 4.6 or newer.
+[clinic start generated code]*/
+
+static Py_ssize_t
+os_preadv_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset,
+ int flags)
+/*[clinic end generated code: output=26fc9c6e58e7ada5 input=4173919dc1f7ed99]*/
+{
+ Py_ssize_t cnt, n;
+ int async_err = 0;
+ struct iovec *iov;
+ Py_buffer *buf;
+
+ if (!PySequence_Check(buffers)) {
+ PyErr_SetString(PyExc_TypeError,
+ "preadv2() arg 2 must be a sequence");
+ return -1;
+ }
+
+ cnt = PySequence_Size(buffers);
+ if (cnt < 0) {
+ return -1;
+ }
+
+#ifndef HAVE_PREADV2
+ if(flags != 0) {
+ argument_unavailable_error("preadv2", "flags");
+ return -1;
+ }
+#endif
+
+ if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_WRITABLE) < 0) {
+ return -1;
+ }
+#ifdef HAVE_PREADV2
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ _Py_BEGIN_SUPPRESS_IPH
+ n = preadv2(fd, iov, cnt, offset, flags);
+ _Py_END_SUPPRESS_IPH
+ Py_END_ALLOW_THREADS
+ } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+#else
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ _Py_BEGIN_SUPPRESS_IPH
+ n = preadv(fd, iov, cnt, offset);
+ _Py_END_SUPPRESS_IPH
+ Py_END_ALLOW_THREADS
+ } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+#endif
+
+ iov_cleanup(iov, buf, cnt);
+ if (n < 0) {
+ if (!async_err) {
+ posix_error();
+ }
+ return -1;
+ }
+
+ return n;
+}
+#endif /* HAVE_PREADV */
+
/*[clinic input]
os.write -> Py_ssize_t
@@ -8613,6 +8701,97 @@ os_pwrite_impl(PyObject *module, int fd, Py_buffer *buffer, Py_off_t offset)
}
#endif /* HAVE_PWRITE */
+#if defined(HAVE_PWRITEV) || defined (HAVE_PWRITEV2)
+/*[clinic input]
+os.pwritev -> Py_ssize_t
+
+ fd: int
+ buffers: object
+ offset: Py_off_t
+ flags: int = 0
+ /
+
+Writes the contents of bytes-like objects to a file descriptor at a given offset.
+
+Combines the functionality of writev() and pwrite(). All buffers must be a sequence
+of bytes-like objects. Buffers are processed in array order. Entire contents of first
+buffer is written before proceeding to second, and so on. The operating system may
+set a limit (sysconf() value SC_IOV_MAX) on the number of buffers that can be used.
+This function writes the contents of each object to the file descriptor and returns
+the total number of bytes written.
+
+The flags argument contains a bitwise OR of zero or more of the following flags:
+
+- RWF_DSYNC
+- RWF_SYNC
+
+Using non-zero flags requires Linux 4.7 or newer.
+[clinic start generated code]*/
+
+static Py_ssize_t
+os_pwritev_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset,
+ int flags)
+/*[clinic end generated code: output=e3dd3e9d11a6a5c7 input=803dc5ddbf0cfd3b]*/
+{
+ Py_ssize_t cnt;
+ Py_ssize_t result;
+ int async_err = 0;
+ struct iovec *iov;
+ Py_buffer *buf;
+
+ if (!PySequence_Check(buffers)) {
+ PyErr_SetString(PyExc_TypeError,
+ "pwritev() arg 2 must be a sequence");
+ return -1;
+ }
+
+ cnt = PySequence_Size(buffers);
+ if (cnt < 0) {
+ return -1;
+ }
+
+#ifndef HAVE_PWRITEV2
+ if(flags != 0) {
+ argument_unavailable_error("pwritev2", "flags");
+ return -1;
+ }
+#endif
+
+ if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_SIMPLE) < 0) {
+ return -1;
+ }
+#ifdef HAVE_PWRITEV2
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ _Py_BEGIN_SUPPRESS_IPH
+ result = pwritev2(fd, iov, cnt, offset, flags);
+ _Py_END_SUPPRESS_IPH
+ Py_END_ALLOW_THREADS
+ } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+#else
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ _Py_BEGIN_SUPPRESS_IPH
+ result = pwritev(fd, iov, cnt, offset);
+ _Py_END_SUPPRESS_IPH
+ Py_END_ALLOW_THREADS
+ } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+#endif
+
+ iov_cleanup(iov, buf, cnt);
+ if (result < 0) {
+ if (!async_err) {
+ posix_error();
+ }
+ return -1;
+ }
+
+ return result;
+}
+#endif /* HAVE_PWRITEV */
+
+
+
#ifdef HAVE_MKFIFO
/*[clinic input]
@@ -12506,9 +12685,11 @@ static PyMethodDef posix_methods[] = {
OS_READ_METHODDEF
OS_READV_METHODDEF
OS_PREAD_METHODDEF
+ OS_PREADV_METHODDEF
OS_WRITE_METHODDEF
OS_WRITEV_METHODDEF
OS_PWRITE_METHODDEF
+ OS_PWRITEV_METHODDEF
#ifdef HAVE_SENDFILE
{"sendfile", (PyCFunction)posix_sendfile, METH_VARARGS | METH_KEYWORDS,
posix_sendfile__doc__},
@@ -12953,6 +13134,19 @@ all_ins(PyObject *m)
if (PyModule_AddIntMacro(m, F_TEST)) return -1;
#endif
+#ifdef RWF_DSYNC
+ if (PyModule_AddIntConstant(m, "RWF_DSYNC", RWF_DSYNC)) return -1;
+#endif
+#ifdef RWF_HIPRI
+ if (PyModule_AddIntConstant(m, "RWF_HIPRI", RWF_HIPRI)) return -1;
+#endif
+#ifdef RWF_SYNC
+ if (PyModule_AddIntConstant(m, "RWF_SYNC", RWF_SYNC)) return -1;
+#endif
+#ifdef RWF_NOWAIT
+ if (PyModule_AddIntConstant(m, "RWF_NOWAIT", RWF_NOWAIT)) return -1;
+#endif
+
#ifdef HAVE_SPAWNV
if (PyModule_AddIntConstant(m, "P_WAIT", _P_WAIT)) return -1;
if (PyModule_AddIntConstant(m, "P_NOWAIT", _P_NOWAIT)) return -1;