Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Doc/library/mmap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,16 @@ To map anonymous memory, -1 should be passed as the fileno along with the length

.. versionadded:: 3.13

.. method:: set_name(name)

Annotate the memory map with the given *name* for easier identification
in ``/proc/<pid>/maps`` if the kernel supports the feature and :option:`-X dev <-X>` is passed
to the Python or Python is built in :ref:`debug mode <debug-build>`

Availability: Linux kernel 5.17 or newer.

.. versionadded:: 3.15

.. method:: size()

Return the length of the file, which can be larger than the size of the
Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,10 @@ mmap
not be duplicated.
(Contributed by Serhiy Storchaka in :gh:`78502`.)

* :meth:`mmap.mmap.set_name` method added to annotation an anonymous memory map
if Linux kernel supports :manpage:`PR_SET_VMA_ANON_NAME <PR_SET_VMA(2const)>` (Linux 5.17 or newer).
(Contributed by Donghee Na in :gh:`142419`.)


os
--
Expand Down
29 changes: 29 additions & 0 deletions Lib/test/test_mmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -1165,6 +1165,35 @@ def test_flush_parameters(self):
m.flush(PAGESIZE)
m.flush(PAGESIZE, PAGESIZE)

@unittest.skipUnless(hasattr(mmap, 'MAP_ANONYMOUS'), 'requires MAP_ANONYMOUS')
def test_set_name(self):
# Test setting name on anonymous mmap
m = mmap.mmap(-1, PAGESIZE)
self.addCleanup(m.close)
result = m.set_name('test_mapping')
self.assertIsNone(result)

# Test name length limit (80 chars including prefix "cpython:mmap:")
# Prefix is 13 chars, so max name is 67 chars
long_name = 'x' * 30
result = m.set_name(long_name)
self.assertIsNone(result)

# Test name too long
too_long_name = 'x' * 80
with self.assertRaises(ValueError):
m.set_name(too_long_name)

# Test that file-backed mmap raises error
with open(TESTFN, 'wb+') as f:
f.write(b'x' * PAGESIZE)
f.flush()
m2 = mmap.mmap(f.fileno(), PAGESIZE)
self.addCleanup(m2.close)

with self.assertRaises(ValueError):
m2.set_name('should_fail')


class LargeMmapTests(unittest.TestCase):

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:meth:`mmap.mmap.set_name` method added to annotation an anonymous memory map
if Linux kernel supports ``PR_SET_VMA_ANON_NAME`` (Linux 5.17 or newer).
Patch by Donghee Na.
38 changes: 37 additions & 1 deletion Modules/clinic/mmapmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 46 additions & 1 deletion Modules/mmapmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,46 @@ mmap_mmap_seek_impl(mmap_object *self, Py_ssize_t dist, int how)
return NULL;
}

/*clinic*/

/*[clinic input]
mmap.mmap.set_name

name: str
/

[clinic start generated code]*/

static PyObject *
mmap_mmap_set_name_impl(mmap_object *self, const char *name)
/*[clinic end generated code: output=1edaf4fd51277760 input=6c7dd91cad205f07]*/
{
const char* prefix = "cpython:mmap:";
if (strlen(name) + strlen(prefix) > 80) {
PyErr_SetString(PyExc_ValueError, "name is too long");
return NULL;
}
#ifdef MAP_ANONYMOUS
if (self->flags & MAP_ANONYMOUS) {
char buf[80] = {0, };
sprintf(buf, "%s%s", prefix, name);
_PyAnnotateMemoryMap(self->data, self->size, buf);
}
else {
/* cannot name non-anonymous mappings */
PyErr_SetString(PyExc_ValueError,
"Cannot set annotation on non-anonymous mappings");
return NULL;
}
#else
/* naming not supported on this platform */
PyErr_SetString(PyExc_ValueError,
"Annotation of mmap is not supported on this platform");
return NULL;
#endif
Py_RETURN_NONE;
}

/*[clinic input]
mmap.mmap.seekable

Expand Down Expand Up @@ -1397,6 +1437,7 @@ static struct PyMethodDef mmap_object_methods[] = {
MMAP_MMAP_RESIZE_METHODDEF
MMAP_MMAP_SEEK_METHODDEF
MMAP_MMAP_SEEKABLE_METHODDEF
MMAP_MMAP_SET_NAME_METHODDEF
MMAP_MMAP_SIZE_METHODDEF
MMAP_MMAP_TELL_METHODDEF
MMAP_MMAP_WRITE_METHODDEF
Expand Down Expand Up @@ -1952,7 +1993,11 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
_PyAnnotateMemoryMap(m_obj->data, map_size, "cpython:mmap");
#ifdef MAP_ANONYMOUS
if (m_obj->flags & MAP_ANONYMOUS) {
_PyAnnotateMemoryMap(m_obj->data, map_size, "cpython:mmap");
}
#endif
m_obj->access = (access_mode)access;
return (PyObject *)m_obj;
}
Expand Down
Loading