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

Skip to content

Commit 02db696

Browse files
ZackerySpytzpitrou
authored andcommitted
bpo-32941: Add madvise() for mmap objects (GH-6172)
Allow mmap objects to access the madvise() system call.
1 parent 331a6a5 commit 02db696

8 files changed

Lines changed: 202 additions & 2 deletions

File tree

Doc/library/mmap.rst

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,20 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
203203
exception was raised on error under Unix.
204204

205205

206+
.. method:: madvise(option[, start[, length]])
207+
208+
Send advice *option* to the kernel about the memory region beginning at
209+
*start* and extending *length* bytes. *option* must be one of the
210+
:ref:`MADV_* constants <madvise-constants>` available on the system. If
211+
*start* and *length* are omitted, the entire mapping is spanned. On
212+
some systems (including Linux), *start* must be a multiple of the
213+
:const:`PAGESIZE`.
214+
215+
Availability: Systems with the ``madvise()`` system call.
216+
217+
.. versionadded:: 3.8
218+
219+
206220
.. method:: move(dest, src, count)
207221

208222
Copy the *count* bytes starting at offset *src* to the destination index
@@ -292,3 +306,38 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
292306
position of the file pointer; the file position is advanced by ``1``. If
293307
the mmap was created with :const:`ACCESS_READ`, then writing to it will
294308
raise a :exc:`TypeError` exception.
309+
310+
.. _madvise-constants:
311+
312+
MADV_* Constants
313+
++++++++++++++++
314+
315+
.. data:: MADV_NORMAL
316+
MADV_RANDOM
317+
MADV_SEQUENTIAL
318+
MADV_WILLNEED
319+
MADV_DONTNEED
320+
MADV_REMOVE
321+
MADV_DONTFORK
322+
MADV_DOFORK
323+
MADV_HWPOISON
324+
MADV_MERGEABLE
325+
MADV_UNMERGEABLE
326+
MADV_SOFT_OFFLINE
327+
MADV_HUGEPAGE
328+
MADV_NOHUGEPAGE
329+
MADV_DONTDUMP
330+
MADV_DODUMP
331+
MADV_FREE
332+
MADV_NOSYNC
333+
MADV_AUTOSYNC
334+
MADV_NOCORE
335+
MADV_CORE
336+
MADV_PROTECT
337+
338+
These options can be passed to :meth:`mmap.madvise`. Not every option will
339+
be present on every system.
340+
341+
Availability: Systems with the madvise() system call.
342+
343+
.. versionadded:: 3.8

Doc/whatsnew/3.8.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,15 @@ numbers. (Contributed by Pablo Galindo in :issue:`35606`)
460460
Added new function :func:`math.isqrt` for computing integer square roots.
461461
(Contributed by Mark Dickinson in :issue:`36887`.)
462462

463+
464+
mmap
465+
----
466+
467+
The :class:`mmap.mmap` class now has an :meth:`~mmap.mmap.madvise` method to
468+
access the ``madvise()`` system call.
469+
(Contributed by Zackery Spytz in :issue:`32941`.)
470+
471+
463472
os
464473
--
465474

Lib/test/test_mmap.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,25 @@ def test_flush_return_value(self):
739739
# See bpo-34754 for details.
740740
self.assertRaises(OSError, mm.flush, 1, len(b'python'))
741741

742+
@unittest.skipUnless(hasattr(mmap.mmap, 'madvise'), 'needs madvise')
743+
def test_madvise(self):
744+
size = 8192
745+
m = mmap.mmap(-1, size)
746+
747+
with self.assertRaisesRegex(ValueError, "madvise start out of bounds"):
748+
m.madvise(mmap.MADV_NORMAL, size)
749+
with self.assertRaisesRegex(ValueError, "madvise start out of bounds"):
750+
m.madvise(mmap.MADV_NORMAL, -1)
751+
with self.assertRaisesRegex(ValueError, "madvise length invalid"):
752+
m.madvise(mmap.MADV_NORMAL, 0, -1)
753+
with self.assertRaisesRegex(OverflowError, "madvise length too large"):
754+
m.madvise(mmap.MADV_NORMAL, PAGESIZE, sys.maxsize)
755+
self.assertEqual(m.madvise(mmap.MADV_NORMAL), None)
756+
self.assertEqual(m.madvise(mmap.MADV_NORMAL, PAGESIZE), None)
757+
self.assertEqual(m.madvise(mmap.MADV_NORMAL, PAGESIZE, size), None)
758+
self.assertEqual(m.madvise(mmap.MADV_NORMAL, 0, 2), None)
759+
self.assertEqual(m.madvise(mmap.MADV_NORMAL, 0, size), None)
760+
742761

743762
class LargeMmapTests(unittest.TestCase):
744763

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Allow :class:`mmap.mmap` objects to access the madvise() system call
2+
(through :meth:`mmap.mmap.madvise`).

Modules/mmapmodule.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,11 +708,54 @@ mmap__sizeof__method(mmap_object *self, void *unused)
708708
}
709709
#endif
710710

711+
#ifdef HAVE_MADVISE
712+
static PyObject *
713+
mmap_madvise_method(mmap_object *self, PyObject *args)
714+
{
715+
int option;
716+
Py_ssize_t start = 0, length;
717+
718+
CHECK_VALID(NULL);
719+
length = self->size;
720+
721+
if (!PyArg_ParseTuple(args, "i|nn:madvise", &option, &start, &length)) {
722+
return NULL;
723+
}
724+
725+
if (start < 0 || start >= self->size) {
726+
PyErr_SetString(PyExc_ValueError, "madvise start out of bounds");
727+
return NULL;
728+
}
729+
if (length < 0) {
730+
PyErr_SetString(PyExc_ValueError, "madvise length invalid");
731+
return NULL;
732+
}
733+
if (PY_SSIZE_T_MAX - start < length) {
734+
PyErr_SetString(PyExc_OverflowError, "madvise length too large");
735+
return NULL;
736+
}
737+
738+
if (start + length > self->size) {
739+
length = self->size - start;
740+
}
741+
742+
if (madvise(self->data + start, length, option) != 0) {
743+
PyErr_SetFromErrno(PyExc_OSError);
744+
return NULL;
745+
}
746+
747+
Py_RETURN_NONE;
748+
}
749+
#endif // HAVE_MADVISE
750+
711751
static struct PyMethodDef mmap_object_methods[] = {
712752
{"close", (PyCFunction) mmap_close_method, METH_NOARGS},
713753
{"find", (PyCFunction) mmap_find_method, METH_VARARGS},
714754
{"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
715755
{"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
756+
#ifdef HAVE_MADVISE
757+
{"madvise", (PyCFunction) mmap_madvise_method, METH_VARARGS},
758+
#endif
716759
{"move", (PyCFunction) mmap_move_method, METH_VARARGS},
717760
{"read", (PyCFunction) mmap_read_method, METH_VARARGS},
718761
{"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
@@ -1494,5 +1537,80 @@ PyInit_mmap(void)
14941537
setint(dict, "ACCESS_READ", ACCESS_READ);
14951538
setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
14961539
setint(dict, "ACCESS_COPY", ACCESS_COPY);
1540+
1541+
#ifdef HAVE_MADVISE
1542+
// Conventional advice values
1543+
#ifdef MADV_NORMAL
1544+
setint(dict, "MADV_NORMAL", MADV_NORMAL);
1545+
#endif
1546+
#ifdef MADV_RANDOM
1547+
setint(dict, "MADV_RANDOM", MADV_RANDOM);
1548+
#endif
1549+
#ifdef MADV_SEQUENTIAL
1550+
setint(dict, "MADV_SEQUENTIAL", MADV_SEQUENTIAL);
1551+
#endif
1552+
#ifdef MADV_WILLNEED
1553+
setint(dict, "MADV_WILLNEED", MADV_WILLNEED);
1554+
#endif
1555+
#ifdef MADV_DONTNEED
1556+
setint(dict, "MADV_DONTNEED", MADV_DONTNEED);
1557+
#endif
1558+
1559+
// Linux-specific advice values
1560+
#ifdef MADV_REMOVE
1561+
setint(dict, "MADV_REMOVE", MADV_REMOVE);
1562+
#endif
1563+
#ifdef MADV_DONTFORK
1564+
setint(dict, "MADV_DONTFORK", MADV_DONTFORK);
1565+
#endif
1566+
#ifdef MADV_DOFORK
1567+
setint(dict, "MADV_DOFORK", MADV_DOFORK);
1568+
#endif
1569+
#ifdef MADV_HWPOISON
1570+
setint(dict, "MADV_HWPOISON", MADV_HWPOISON);
1571+
#endif
1572+
#ifdef MADV_MERGEABLE
1573+
setint(dict, "MADV_MERGEABLE", MADV_MERGEABLE);
1574+
#endif
1575+
#ifdef MADV_UNMERGEABLE
1576+
setint(dict, "MADV_UNMERGEABLE", MADV_UNMERGEABLE);
1577+
#endif
1578+
#ifdef MADV_SOFT_OFFLINE
1579+
setint(dict, "MADV_SOFT_OFFLINE", MADV_SOFT_OFFLINE);
1580+
#endif
1581+
#ifdef MADV_HUGEPAGE
1582+
setint(dict, "MADV_HUGEPAGE", MADV_HUGEPAGE);
1583+
#endif
1584+
#ifdef MADV_NOHUGEPAGE
1585+
setint(dict, "MADV_NOHUGEPAGE", MADV_NOHUGEPAGE);
1586+
#endif
1587+
#ifdef MADV_DONTDUMP
1588+
setint(dict, "MADV_DONTDUMP", MADV_DONTDUMP);
1589+
#endif
1590+
#ifdef MADV_DODUMP
1591+
setint(dict, "MADV_DODUMP", MADV_DODUMP);
1592+
#endif
1593+
#ifdef MADV_FREE // (Also present on FreeBSD and macOS.)
1594+
setint(dict, "MADV_FREE", MADV_FREE);
1595+
#endif
1596+
1597+
// FreeBSD-specific
1598+
#ifdef MADV_NOSYNC
1599+
setint(dict, "MADV_NOSYNC", MADV_NOSYNC);
1600+
#endif
1601+
#ifdef MADV_AUTOSYNC
1602+
setint(dict, "MADV_AUTOSYNC", MADV_AUTOSYNC);
1603+
#endif
1604+
#ifdef MADV_NOCORE
1605+
setint(dict, "MADV_NOCORE", MADV_NOCORE);
1606+
#endif
1607+
#ifdef MADV_CORE
1608+
setint(dict, "MADV_CORE", MADV_CORE);
1609+
#endif
1610+
#ifdef MADV_PROTECT
1611+
setint(dict, "MADV_PROTECT", MADV_PROTECT);
1612+
#endif
1613+
#endif // HAVE_MADVISE
1614+
14971615
return module;
14981616
}

configure

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11471,7 +11471,7 @@ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
1147111471
getgrouplist getgroups getlogin getloadavg getpeername getpgid getpid \
1147211472
getpriority getresuid getresgid getpwent getpwnam_r getpwuid_r getspnam getspent getsid getwd \
1147311473
if_nameindex \
11474-
initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mmap \
11474+
initgroups kill killpg lchmod lchown lockf linkat lstat lutimes madvise mmap \
1147511475
memrchr mbrtowc mkdirat mkfifo \
1147611476
mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \
1147711477
posix_fallocate posix_fadvise posix_spawn posix_spawnp pread preadv preadv2 \

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3527,7 +3527,7 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
35273527
getgrouplist getgroups getlogin getloadavg getpeername getpgid getpid \
35283528
getpriority getresuid getresgid getpwent getpwnam_r getpwuid_r getspnam getspent getsid getwd \
35293529
if_nameindex \
3530-
mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \
3530+
madvise mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \
35313531
posix_fallocate posix_fadvise posix_spawn posix_spawnp pread preadv preadv2 \
35323532
pthread_condattr_setclock pthread_init pthread_kill putenv pwrite pwritev pwritev2 \
35333533
readlink readlinkat readv realpath renameat \

pyconfig.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,9 @@
658658
/* Define to 1 if you have the `lutimes' function. */
659659
#undef HAVE_LUTIMES
660660

661+
/* Define to 1 if you have the `madvise' function. */
662+
#undef HAVE_MADVISE
663+
661664
/* Define this if you have the makedev macro. */
662665
#undef HAVE_MAKEDEV
663666

0 commit comments

Comments
 (0)