bpo-31368: Expose preadv and pwritev in the os module (#5239)

This commit is contained in:
Pablo Galindo 2018-01-27 16:16:37 +00:00 committed by Victor Stinner
parent 60da99b8e2
commit 4defba3b95
9 changed files with 470 additions and 79 deletions

View file

@ -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;