Skip to content

Commit d42762c

Browse files
committed
bpo-34321: Add a trackfd parameter to mmap.mmap()
If *trackfd* is False, the file descriptor specified by *fileno* will not be duplicated.
1 parent e692f55 commit d42762c

File tree

5 files changed

+37
-6
lines changed

5 files changed

+37
-6
lines changed

Doc/library/mmap.rst

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
6969

7070
.. audit-event:: mmap.__new__ fileno,length,access,offset mmap.mmap
7171

72-
.. class:: mmap(fileno, length, flags=MAP_SHARED, prot=PROT_WRITE|PROT_READ, access=ACCESS_DEFAULT[, offset])
72+
.. class:: mmap(fileno, length, flags=MAP_SHARED, prot=PROT_WRITE|PROT_READ, \
73+
access=ACCESS_DEFAULT[, offset], trackfd=True)
7374
:noindex:
7475

7576
**(Unix version)** Maps *length* bytes from the file specified by the file
@@ -100,10 +101,16 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
100101
defaults to 0. *offset* must be a multiple of :const:`ALLOCATIONGRANULARITY`
101102
which is equal to :const:`PAGESIZE` on Unix systems.
102103

104+
If *trackfd* is ``False``, the file descriptor specified by *fileno* will
105+
not be duplicated.
106+
103107
To ensure validity of the created memory mapping the file specified
104108
by the descriptor *fileno* is internally automatically synchronized
105109
with physical backing store on Mac OS X and OpenVMS.
106110

111+
.. versionchanged:: 3.10
112+
The *trackfd* parameter was added.
113+
107114
This example shows a simple way of using :class:`~mmap.mmap`::
108115

109116
import mmap

Doc/whatsnew/3.10.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,13 @@ linecache
831831
When a module does not define ``__loader__``, fall back to ``__spec__.loader``.
832832
(Contributed by Brett Cannon in :issue:`42133`.)
833833
834+
mmap
835+
----
836+
837+
:class:`mmap.mmap` now has a *trackfd* parameter on Unix; if it is ``False``,
838+
the file descriptor specified by *fileno* will not be duplicated.
839+
(Contributed by Zackery Spytz in :issue:`34321`.)
840+
834841
os
835842
--
836843

Lib/test/test_mmap.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,16 @@ def test_access_parameter(self):
246246
self.assertRaises(TypeError, m.write_byte, 0)
247247
m.close()
248248

249+
@unittest.skipIf(os.name == 'nt', 'trackfd not present on Windows')
250+
def test_trackfd_parameter(self):
251+
size = 64
252+
with open(TESTFN, "wb") as f:
253+
f.write(b"a"*size)
254+
with open(TESTFN, "r+b") as f:
255+
m = mmap.mmap(f.fileno(), size, trackfd=False)
256+
self.assertEqual(len(m), size)
257+
m.close()
258+
249259
def test_bad_file_desc(self):
250260
# Try opening a bad file descriptor...
251261
self.assertRaises(OSError, mmap.mmap, -2, 4096)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:class:`mmap.mmap` now has a *trackfd* parameter on Unix; if it is
2+
``False``, the file descriptor specified by *fileno* will not be duplicated.

Modules/mmapmodule.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,15 +1136,17 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
11361136
off_t offset = 0;
11371137
int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
11381138
int devzero = -1;
1139-
int access = (int)ACCESS_DEFAULT;
1139+
int access = (int)ACCESS_DEFAULT, trackfd = 1;
11401140
static char *keywords[] = {"fileno", "length",
11411141
"flags", "prot",
1142-
"access", "offset", NULL};
1142+
"access", "offset", "trackfd", NULL};
11431143

1144-
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords,
1144+
if (!PyArg_ParseTupleAndKeywords(args, kwdict,
1145+
"in|iii" _Py_PARSE_OFF_T "p", keywords,
11451146
&fd, &map_size, &flags, &prot,
1146-
&access, &offset))
1147+
&access, &offset, &trackfd)) {
11471148
return NULL;
1149+
}
11481150
if (map_size < 0) {
11491151
PyErr_SetString(PyExc_OverflowError,
11501152
"memory mapped length must be positive");
@@ -1265,13 +1267,16 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
12651267
}
12661268
#endif
12671269
}
1268-
else {
1270+
else if (trackfd) {
12691271
m_obj->fd = _Py_dup(fd);
12701272
if (m_obj->fd == -1) {
12711273
Py_DECREF(m_obj);
12721274
return NULL;
12731275
}
12741276
}
1277+
else {
1278+
m_obj->fd = -1;
1279+
}
12751280

12761281
m_obj->data = mmap(NULL, map_size,
12771282
prot, flags,

0 commit comments

Comments
 (0)