Skip to main content

Modules/mmapmodule.c (part 2)

Source:

cpython 3.14 @ ab2d84fe1023/Modules/mmapmodule.c

This annotation covers I/O methods and the buffer protocol. See modules_mmap_detail for mmap.__new__, ACCESS_READ/WRITE/COPY, mmap.close, and the POSIX/Windows platform differences.

Map

LinesSymbolRole
1-80mmap.readRead bytes from the current position
81-160mmap.writeWrite bytes at the current position
161-260mmap.seek / mmap.tellRandom access by file-position cursor
261-380mmap.find / mmap.rfindBoyer-Moore-Horspool search within the mapped memory
381-500mmap.resizeChange the mapping size (mremap / SetEndOfFile)
501-700Buffer protocolExport the mapped region as a writable Py_buffer

Reading

mmap.read

// CPython: Modules/mmapmodule.c:480 mmap_read_method
static PyObject *
mmap_read_method(mmap_object *self, PyObject *args)
{
Py_ssize_t num_bytes = PY_SSIZE_T_MAX; /* default: read to end */
PyArg_ParseTuple(args, "|n:read", &num_bytes);
CHECK_VALID(NULL);
if (num_bytes < 0) {
PyErr_SetString(PyExc_ValueError, "read length must be non-negative");
return NULL;
}
Py_ssize_t available = self->size - self->pos;
if (num_bytes > available) num_bytes = available;
PyObject *result = PyBytes_FromStringAndSize(self->data + self->pos, num_bytes);
self->pos += num_bytes;
return result;
}

mmap.read(n) copies from mapped memory into a new bytes object. No system call is made — the kernel handles page faults lazily.

mmap.find

// CPython: Modules/mmapmodule.c:620 mmap_find_method
static PyObject *
mmap_find_method(mmap_object *self, PyObject *args, int forward)
{
Py_ssize_t start = self->pos, end = self->size;
Py_buffer sub;
/* Search self->data[start:end] for sub using memmem/a linear scan */
const char *p = memmem(self->data + start, end - start,
sub.buf, sub.len);
if (p == NULL) {
PyBuffer_Release(&sub);
return PyLong_FromSsize_t(-1);
}
PyBuffer_Release(&sub);
return PyLong_FromSsize_t(p - self->data);
}

m.find(b'pattern') uses memmem (glibc) or a portable fallback for fast byte-pattern search in the mapped region. Returns the byte offset or -1.

mmap.resize

// CPython: Modules/mmapmodule.c:700 mmap_resize_method
static PyObject *
mmap_resize_method(mmap_object *self, PyObject *args)
{
Py_ssize_t new_size;
/* POSIX: ftruncate + mremap */
ftruncate(self->fd, new_size);
void *new_data = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
if (new_data == MAP_FAILED) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
self->data = new_data;
self->size = new_size;
Py_RETURN_NONE;
}

resize changes the backing file size and remaps. Only supported on POSIX with PROT_WRITE access and on Windows with ACCESS_WRITE.

Buffer protocol

// CPython: Modules/mmapmodule.c:820 mmap_buffer_getbuf
static int
mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
{
/* Export the full mapped region as a flat, writable bytes buffer. */
if (PyBuffer_FillInfo(view, (PyObject *)self,
self->data, self->size,
self->access == ACCESS_READ ? 1 : 0,
flags) < 0) return -1;
self->exports++;
return 0;
}

mmap objects support struct.pack_into(fmt, m, 0, ...) and bytes(m) without copying. ACCESS_READ maps export a read-only buffer.

gopy notes

mmap.read/write are in module/mmap/module.go. The mapped region is a []byte backed by syscall.Mmap. mmap.find uses bytes.Index. mmap.resize uses syscall.Ftruncate + remapping. The buffer protocol exports the []byte slice directly via objects.GetWritableBuffer.