summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal Norwitz <nnorwitz@gmail.com>2006-02-05 05:45:43 (GMT)
committerNeal Norwitz <nnorwitz@gmail.com>2006-02-05 05:45:43 (GMT)
commit0e6bc8c260f640ceee515e9873353778472e0a00 (patch)
treef567d2bbbde27ae16288e1e94edc4ff0acf13441
parentd1cfc8ade1f661f02286f2b81123d4d436c6d9d0 (diff)
downloadcpython-0e6bc8c260f640ceee515e9873353778472e0a00.zip
cpython-0e6bc8c260f640ceee515e9873353778472e0a00.tar.gz
cpython-0e6bc8c260f640ceee515e9873353778472e0a00.tar.bz2
Patch #1407135, bug #1424041, make mmap.mmap(-1, length) work the same
on both Unix (SVR4 and BSD) and Windows. Restores behaviour of passing -1 for anonymous memory on Unix. Use MAP_ANONYMOUS instead of _ANON since the latter is deprecated according to Linux (gentoo) man pages. Should we continue to allow mmap.mmap(0, length) to work on Windows? 0 is a valid fd. Will backport bugfix portions.
-rw-r--r--Doc/lib/libmmap.tex3
-rw-r--r--Lib/test/output/test_mmap1
-rw-r--r--Lib/test/test_mmap.py14
-rw-r--r--Misc/NEWS4
-rw-r--r--Modules/mmapmodule.c59
5 files changed, 68 insertions, 13 deletions
diff --git a/Doc/lib/libmmap.tex b/Doc/lib/libmmap.tex
index e7db814..3dca40f 100644
--- a/Doc/lib/libmmap.tex
+++ b/Doc/lib/libmmap.tex
@@ -37,7 +37,8 @@ taken from the specified file. Assignment to an
exception. Assignment to an \constant{ACCESS_WRITE} memory map
affects both memory and the underlying file. Assignment to an
\constant{ACCESS_COPY} memory map affects memory but does not update
-the underlying file.
+the underlying file. \versionchanged[To map anonymous memory,
+-1 should be passed as the fileno along with the length]{2.5}
\begin{funcdesc}{mmap}{fileno, length\optional{, tagname\optional{, access}}}
\strong{(Windows version)} Maps \var{length} bytes from the file
diff --git a/Lib/test/output/test_mmap b/Lib/test/output/test_mmap
index 1ce4943..605f840 100644
--- a/Lib/test/output/test_mmap
+++ b/Lib/test/output/test_mmap
@@ -34,4 +34,5 @@ test_mmap
Try opening a bad file descriptor...
Ensuring that passing 0 as map length sets map size to current file size.
Ensuring that passing 0 as map length sets map size to current file size.
+ anonymous mmap.mmap(-1, PAGESIZE)...
Test passed
diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py
index 6930317..d2a2477 100644
--- a/Lib/test/test_mmap.py
+++ b/Lib/test/test_mmap.py
@@ -283,7 +283,7 @@ def test_both():
print ' Try opening a bad file descriptor...'
try:
- mmap.mmap(-1, 4096)
+ mmap.mmap(-2, 4096)
except mmap.error:
pass
else:
@@ -380,6 +380,16 @@ def test_both():
finally:
os.unlink(TESTFN)
- print ' Test passed'
+def test_anon():
+ print " anonymous mmap.mmap(-1, PAGESIZE)..."
+ m = mmap.mmap(-1, PAGESIZE)
+ for x in xrange(PAGESIZE):
+ verify(m[x] == '\0', "anonymously mmap'ed contents should be zero")
+
+ for x in xrange(PAGESIZE):
+ m[x] = ch = chr(x & 255)
+ vereq(m[x], ch)
test_both()
+test_anon()
+print ' Test passed'
diff --git a/Misc/NEWS b/Misc/NEWS
index 7fe0393..1e828d6 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -216,6 +216,10 @@ Core and builtins
Extension Modules
-----------------
+- Patch #1407135, bug #1424041: harmonize mmap behavior of anonymous memory.
+ mmap.mmap(-1, size) now returns anonymous memory in both Unix and Windows.
+ mmap.mmap(0, size) should not be used on Windows for anonymous memory.
+
- Patch #1422385: The nis module now supports access to domains other
than the system default domain.
diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c
index b01f42f..b6b2d85 100644
--- a/Modules/mmapmodule.c
+++ b/Modules/mmapmodule.c
@@ -54,6 +54,11 @@ my_getpagesize(void)
#include <string.h>
#include <sys/types.h>
+/* maybe define MAP_ANON in terms of MAP_ANONYMOUS */
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+# define MAP_ANONYMOUS MAP_ANON
+#endif
+
static PyObject *mmap_module_error;
typedef enum
@@ -863,6 +868,7 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
PyObject *map_size_obj = NULL;
int map_size;
int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
+ int devzero = -1;
int access = (int)ACCESS_DEFAULT;
static const char *keywords[] = {"fileno", "length",
"flags", "prot",
@@ -921,15 +927,41 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
m_obj->data = NULL;
m_obj->size = (size_t) map_size;
m_obj->pos = (size_t) 0;
- m_obj->fd = dup(fd);
- if (m_obj->fd == -1) {
- Py_DECREF(m_obj);
- PyErr_SetFromErrno(mmap_module_error);
- return NULL;
+ if (fd == -1) {
+ m_obj->fd = -1;
+ /* Assume the caller wants to map anonymous memory.
+ This is the same behaviour as Windows. mmap.mmap(-1, size)
+ on both Windows and Unix map anonymous memory.
+ */
+#ifdef MAP_ANONYMOUS
+ /* BSD way to map anonymous memory */
+ flags |= MAP_ANONYMOUS;
+#else
+ /* SVR4 method to map anonymous memory is to open /dev/zero */
+ fd = devzero = open("/dev/zero", O_RDWR);
+ if (devzero == -1) {
+ Py_DECREF(m_obj);
+ PyErr_SetFromErrno(mmap_module_error);
+ return NULL;
+ }
+#endif
+ } else {
+ m_obj->fd = dup(fd);
+ if (m_obj->fd == -1) {
+ Py_DECREF(m_obj);
+ PyErr_SetFromErrno(mmap_module_error);
+ return NULL;
+ }
}
+
m_obj->data = mmap(NULL, map_size,
prot, flags,
fd, 0);
+
+ if (devzero != -1) {
+ close(devzero);
+ }
+
if (m_obj->data == (char *)-1) {
m_obj->data = NULL;
Py_DECREF(m_obj);
@@ -986,8 +1018,15 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
if (map_size < 0)
return NULL;
- /* if an actual filename has been specified */
- if (fileno != 0) {
+ /* assume -1 and 0 both mean invalid filedescriptor
+ to 'anonymously' map memory.
+ XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
+ XXX: Should this code be added?
+ if (fileno == 0)
+ PyErr_Warn(PyExc_DeprecationWarning,
+ "don't use 0 for anonymous memory");
+ */
+ if (fileno != -1 && fileno != 0) {
fh = (HANDLE)_get_osfhandle(fileno);
if (fh==(HANDLE)-1) {
PyErr_SetFromErrno(mmap_module_error);
@@ -1123,10 +1162,10 @@ PyMODINIT_FUNC
PyDict_SetItemString (dict, "MAP_EXECUTABLE",
PyInt_FromLong(MAP_EXECUTABLE) );
#endif
-#ifdef MAP_ANON
- PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
+#ifdef MAP_ANONYMOUS
+ PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANONYMOUS) );
PyDict_SetItemString (dict, "MAP_ANONYMOUS",
- PyInt_FromLong(MAP_ANON) );
+ PyInt_FromLong(MAP_ANONYMOUS) );
#endif
PyDict_SetItemString (dict, "PAGESIZE",