Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4defba3

Browse files
pablogsalvstinner
authored andcommitted
bpo-31368: Expose preadv and pwritev in the os module (#5239)
1 parent 60da99b commit 4defba3

9 files changed

Lines changed: 470 additions & 79 deletions

File tree

Doc/library/os.rst

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,45 @@ or `the MSDN <https://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Windo
11021102
.. versionadded:: 3.3
11031103

11041104

1105+
.. function:: pwritev(fd, buffers, offset, flags=0)
1106+
1107+
Combines the functionality of :func:`os.writev` and :func:`os.pwrite`. It
1108+
writes the contents of *buffers* to file descriptor *fd* at offset *offset*.
1109+
*buffers* must be a sequence of :term:`bytes-like objects <bytes-like object>`.
1110+
Buffers are processed in array order. Entire contents of first buffer is written
1111+
before proceeding to second, and so on. The operating system may set a limit
1112+
(sysconf() value SC_IOV_MAX) on the number of buffers that can be used.
1113+
:func:`~os.pwritev` writes the contents of each object to the file descriptor
1114+
and returns the total number of bytes written.
1115+
1116+
The *flags* argument contains a bitwise OR of zero or more of the following
1117+
flags:
1118+
1119+
- RWF_DSYNC
1120+
- RWF_SYNC
1121+
1122+
Using non-zero flags requires Linux 4.7 or newer.
1123+
1124+
Availability: Linux (version 2.6.30), FreeBSD 6.0 and newer,
1125+
OpenBSD (version 2.7 and newer).
1126+
1127+
.. versionadded:: 3.7
1128+
1129+
.. data:: RWF_DSYNC (since Linux 4.7)
1130+
Provide a per-write equivalent of the O_DSYNC open(2) flag. This flag
1131+
is meaningful only for pwritev2(), and its effect applies only to the
1132+
data range written by the system call.
1133+
1134+
.. versionadded:: 3.7
1135+
1136+
.. data:: RWF_SYNC (since Linux 4.7)
1137+
Provide a per-write equivalent of the O_SYNC open(2) flag. This flag is
1138+
meaningful only for pwritev2(), and its effect applies only to the data
1139+
range written by the system call.
1140+
1141+
.. versionadded:: 3.7
1142+
1143+
11051144
.. function:: read(fd, n)
11061145

11071146
Read at most *n* bytes from file descriptor *fd*. Return a bytestring containing the
@@ -1196,6 +1235,51 @@ or `the MSDN <https://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Windo
11961235
.. versionadded:: 3.3
11971236

11981237

1238+
.. function:: preadv(fd, buffers, offset, flags=0)
1239+
1240+
Combines the functionality of :func:`os.readv` and :func:`os.pread`. It
1241+
reads from a file descriptor *fd* into a number of mutable :term:`bytes-like
1242+
objects <bytes-like object>` *buffers*. As :func:`os.readv`, it will transfer
1243+
data into each buffer until it is full and then move on to the next buffer in
1244+
the sequence to hold the rest of the data. Its fourth argument, *offset*,
1245+
specifies the file offset at which the input operation is to be performed.
1246+
:func:`~os.preadv` return the total number of bytes read (which can be less than
1247+
the total capacity of all the objects).
1248+
1249+
The flags argument contains a bitwise OR of zero or more of the following
1250+
flags:
1251+
1252+
- RWF_HIPRI
1253+
- RWF_NOWAIT
1254+
1255+
Using non-zero flags requires Linux 4.6 or newer.
1256+
1257+
Availability: Linux (version 2.6.30), FreeBSD 6.0 and newer,
1258+
OpenBSD (version 2.7 and newer).
1259+
1260+
.. versionadded:: 3.7
1261+
1262+
1263+
.. data:: RWF_HIPRI (since Linux 4.6)
1264+
High priority read/write. Allows block-based filesystems to use polling
1265+
of the device, which provides lower latency, but may use additional
1266+
resources. (Currently, this feature is usable only on a file descriptor
1267+
opened using the O_DIRECT flag.)
1268+
1269+
.. versionadded:: 3.7
1270+
1271+
1272+
.. data:: RWF_NOWAIT (since Linux 4.14)
1273+
Do not wait for data which is not immediately available. If this flag
1274+
is specified, the preadv2() system call will return instantly
1275+
if it would have to read data from the backing storage or wait for a lock.
1276+
If some data was successfully read, it will return the number of bytes
1277+
read. If no bytes were read, it will return -1 and set errno to EAGAIN.
1278+
Currently, this flag is meaningful only for preadv2().
1279+
1280+
.. versionadded:: 3.7
1281+
1282+
11991283
.. function:: tcgetpgrp(fd)
12001284

12011285
Return the process group associated with the terminal given by *fd* (an open

Lib/test/test_posix.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,28 @@ def test_pread(self):
272272
finally:
273273
os.close(fd)
274274

275+
@unittest.skipUnless(hasattr(posix, 'preadv'), "test needs posix.preadv()")
276+
def test_preadv(self):
277+
fd = os.open(support.TESTFN, os.O_RDWR | os.O_CREAT)
278+
try:
279+
os.write(fd, b'test1tt2t3t5t6t6t8')
280+
buf = [bytearray(i) for i in [5, 3, 2]]
281+
self.assertEqual(posix.preadv(fd, buf, 3), 10)
282+
self.assertEqual([b't1tt2', b't3t', b'5t'], list(buf))
283+
finally:
284+
os.close(fd)
285+
286+
@unittest.skipUnless(hasattr(posix, 'RWF_HIPRI'), "test needs posix.RWF_HIPRI")
287+
def test_preadv_flags(self):
288+
fd = os.open(support.TESTFN, os.O_RDWR | os.O_CREAT)
289+
try:
290+
os.write(fd, b'test1tt2t3t5t6t6t8')
291+
buf = [bytearray(i) for i in [5, 3, 2]]
292+
self.assertEqual(posix.preadv(fd, buf, 3, os.RWF_HIPRI), 10)
293+
self.assertEqual([b't1tt2', b't3t', b'5t'], list(buf))
294+
finally:
295+
os.close(fd)
296+
275297
@unittest.skipUnless(hasattr(posix, 'pwrite'), "test needs posix.pwrite()")
276298
def test_pwrite(self):
277299
fd = os.open(support.TESTFN, os.O_RDWR | os.O_CREAT)
@@ -283,6 +305,34 @@ def test_pwrite(self):
283305
finally:
284306
os.close(fd)
285307

308+
@unittest.skipUnless(hasattr(posix, 'pwritev'), "test needs posix.pwritev()")
309+
def test_pwritev(self):
310+
fd = os.open(support.TESTFN, os.O_RDWR | os.O_CREAT)
311+
try:
312+
os.write(fd, b"xx")
313+
os.lseek(fd, 0, os.SEEK_SET)
314+
n = os.pwritev(fd, [b'test1', b'tt2', b't3'], 2)
315+
self.assertEqual(n, 10)
316+
317+
os.lseek(fd, 0, os.SEEK_SET)
318+
self.assertEqual(b'xxtest1tt2t3', posix.read(fd, 100))
319+
finally:
320+
os.close(fd)
321+
322+
@unittest.skipUnless(hasattr(posix, 'os.RWF_SYNC'), "test needs os.RWF_SYNC")
323+
def test_pwritev_flags(self):
324+
fd = os.open(support.TESTFN, os.O_RDWR | os.O_CREAT)
325+
try:
326+
os.write(fd,b"xx")
327+
os.lseek(fd, 0, os.SEEK_SET)
328+
n = os.pwritev(fd, [b'test1', b'tt2', b't3'], 2, os.RWF_SYNC)
329+
self.assertEqual(n, 10)
330+
331+
os.lseek(fd, 0, os.SEEK_SET)
332+
self.assertEqual(b'xxtest1tt2', posix.read(fd, 100))
333+
finally:
334+
os.close(fd)
335+
286336
@unittest.skipUnless(hasattr(posix, 'posix_fallocate'),
287337
"test needs posix.posix_fallocate()")
288338
def test_posix_fallocate(self):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Expose preadv and pwritev system calls in the os module. Patch by Pablo Galindo

Modules/clinic/posixmodule.c.h

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3705,6 +3705,61 @@ os_pread(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
37053705

37063706
#endif /* defined(HAVE_PREAD) */
37073707

3708+
#if (defined(HAVE_PREADV) || defined (HAVE_PREADV2))
3709+
3710+
PyDoc_STRVAR(os_preadv__doc__,
3711+
"preadv($module, fd, buffers, offset, flags=0, /)\n"
3712+
"--\n"
3713+
"\n"
3714+
"Reads from a file descriptor into a number of mutable bytes-like objects.\n"
3715+
"\n"
3716+
"Combines the functionality of readv() and pread(). As readv(), it will\n"
3717+
"transfer data into each buffer until it is full and then move on to the next\n"
3718+
"buffer in the sequence to hold the rest of the data. Its fourth argument,\n"
3719+
"specifies the file offset at which the input operation is to be performed. It\n"
3720+
"will return the total number of bytes read (which can be less than the total\n"
3721+
"capacity of all the objects).\n"
3722+
"\n"
3723+
"The flags argument contains a bitwise OR of zero or more of the following flags:\n"
3724+
"\n"
3725+
"- RWF_HIPRI\n"
3726+
"- RWF_NOWAIT\n"
3727+
"\n"
3728+
"Using non-zero flags requires Linux 4.6 or newer.");
3729+
3730+
#define OS_PREADV_METHODDEF \
3731+
{"preadv", (PyCFunction)os_preadv, METH_FASTCALL, os_preadv__doc__},
3732+
3733+
static Py_ssize_t
3734+
os_preadv_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset,
3735+
int flags);
3736+
3737+
static PyObject *
3738+
os_preadv(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
3739+
{
3740+
PyObject *return_value = NULL;
3741+
int fd;
3742+
PyObject *buffers;
3743+
Py_off_t offset;
3744+
int flags = 0;
3745+
Py_ssize_t _return_value;
3746+
3747+
if (!_PyArg_ParseStack(args, nargs, "iOO&|i:preadv",
3748+
&fd, &buffers, Py_off_t_converter, &offset, &flags)) {
3749+
goto exit;
3750+
}
3751+
_return_value = os_preadv_impl(module, fd, buffers, offset, flags);
3752+
if ((_return_value == -1) && PyErr_Occurred()) {
3753+
goto exit;
3754+
}
3755+
return_value = PyLong_FromSsize_t(_return_value);
3756+
3757+
exit:
3758+
return return_value;
3759+
}
3760+
3761+
#endif /* (defined(HAVE_PREADV) || defined (HAVE_PREADV2)) */
3762+
37083763
PyDoc_STRVAR(os_write__doc__,
37093764
"write($module, fd, data, /)\n"
37103765
"--\n"
@@ -3963,6 +4018,61 @@ os_pwrite(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
39634018

39644019
#endif /* defined(HAVE_PWRITE) */
39654020

4021+
#if (defined(HAVE_PWRITEV) || defined (HAVE_PWRITEV2))
4022+
4023+
PyDoc_STRVAR(os_pwritev__doc__,
4024+
"pwritev($module, fd, buffers, offset, flags=0, /)\n"
4025+
"--\n"
4026+
"\n"
4027+
"Writes the contents of bytes-like objects to a file descriptor at a given offset.\n"
4028+
"\n"
4029+
"Combines the functionality of writev() and pwrite(). All buffers must be a sequence\n"
4030+
"of bytes-like objects. Buffers are processed in array order. Entire contents of first\n"
4031+
"buffer is written before proceeding to second, and so on. The operating system may\n"
4032+
"set a limit (sysconf() value SC_IOV_MAX) on the number of buffers that can be used.\n"
4033+
"This function writes the contents of each object to the file descriptor and returns\n"
4034+
"the total number of bytes written.\n"
4035+
"\n"
4036+
"The flags argument contains a bitwise OR of zero or more of the following flags:\n"
4037+
"\n"
4038+
"- RWF_DSYNC\n"
4039+
"- RWF_SYNC\n"
4040+
"\n"
4041+
"Using non-zero flags requires Linux 4.7 or newer.");
4042+
4043+
#define OS_PWRITEV_METHODDEF \
4044+
{"pwritev", (PyCFunction)os_pwritev, METH_FASTCALL, os_pwritev__doc__},
4045+
4046+
static Py_ssize_t
4047+
os_pwritev_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset,
4048+
int flags);
4049+
4050+
static PyObject *
4051+
os_pwritev(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
4052+
{
4053+
PyObject *return_value = NULL;
4054+
int fd;
4055+
PyObject *buffers;
4056+
Py_off_t offset;
4057+
int flags = 0;
4058+
Py_ssize_t _return_value;
4059+
4060+
if (!_PyArg_ParseStack(args, nargs, "iOO&|i:pwritev",
4061+
&fd, &buffers, Py_off_t_converter, &offset, &flags)) {
4062+
goto exit;
4063+
}
4064+
_return_value = os_pwritev_impl(module, fd, buffers, offset, flags);
4065+
if ((_return_value == -1) && PyErr_Occurred()) {
4066+
goto exit;
4067+
}
4068+
return_value = PyLong_FromSsize_t(_return_value);
4069+
4070+
exit:
4071+
return return_value;
4072+
}
4073+
4074+
#endif /* (defined(HAVE_PWRITEV) || defined (HAVE_PWRITEV2)) */
4075+
39664076
#if defined(HAVE_MKFIFO)
39674077

39684078
PyDoc_STRVAR(os_mkfifo__doc__,
@@ -6239,6 +6349,10 @@ os_getrandom(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
62396349
#define OS_PREAD_METHODDEF
62406350
#endif /* !defined(OS_PREAD_METHODDEF) */
62416351

6352+
#ifndef OS_PREADV_METHODDEF
6353+
#define OS_PREADV_METHODDEF
6354+
#endif /* !defined(OS_PREADV_METHODDEF) */
6355+
62426356
#ifndef OS_PIPE_METHODDEF
62436357
#define OS_PIPE_METHODDEF
62446358
#endif /* !defined(OS_PIPE_METHODDEF) */
@@ -6255,6 +6369,10 @@ os_getrandom(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
62556369
#define OS_PWRITE_METHODDEF
62566370
#endif /* !defined(OS_PWRITE_METHODDEF) */
62576371

6372+
#ifndef OS_PWRITEV_METHODDEF
6373+
#define OS_PWRITEV_METHODDEF
6374+
#endif /* !defined(OS_PWRITEV_METHODDEF) */
6375+
62586376
#ifndef OS_MKFIFO_METHODDEF
62596377
#define OS_MKFIFO_METHODDEF
62606378
#endif /* !defined(OS_MKFIFO_METHODDEF) */
@@ -6410,4 +6528,4 @@ os_getrandom(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
64106528
#ifndef OS_GETRANDOM_METHODDEF
64116529
#define OS_GETRANDOM_METHODDEF
64126530
#endif /* !defined(OS_GETRANDOM_METHODDEF) */
6413-
/*[clinic end generated code: output=6345053cd5992caf input=a9049054013a1b77]*/
6531+
/*[clinic end generated code: output=06ace805893aa10c input=a9049054013a1b77]*/

0 commit comments

Comments
 (0)