diff options
author | Pablo Galindo <Pablogsal@gmail.com> | 2018-01-27 16:16:37 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2018-01-27 16:16:37 (GMT) |
commit | 4defba3b95ec0f52ce75b8466831d30fb5d333f3 (patch) | |
tree | afd798704c96cc3f12a1ae38ede0863ffef56938 /Modules | |
parent | 60da99b8e2f7bf497569ae4d6c218866575729bf (diff) | |
download | cpython-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.h | 120 | ||||
-rw-r--r-- | Modules/posixmodule.c | 194 |
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; |