diff options
author | Neal Norwitz <nnorwitz@gmail.com> | 2006-02-05 05:45:43 (GMT) |
---|---|---|
committer | Neal Norwitz <nnorwitz@gmail.com> | 2006-02-05 05:45:43 (GMT) |
commit | 0e6bc8c260f640ceee515e9873353778472e0a00 (patch) | |
tree | f567d2bbbde27ae16288e1e94edc4ff0acf13441 | |
parent | d1cfc8ade1f661f02286f2b81123d4d436c6d9d0 (diff) | |
download | cpython-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.tex | 3 | ||||
-rw-r--r-- | Lib/test/output/test_mmap | 1 | ||||
-rw-r--r-- | Lib/test/test_mmap.py | 14 | ||||
-rw-r--r-- | Misc/NEWS | 4 | ||||
-rw-r--r-- | Modules/mmapmodule.c | 59 |
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' @@ -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", |