Author: Armin Rigo <[email protected]>
Branch: use-mmap
Changeset: r85676:ae84c87cdd28
Date: 2016-07-13 15:46 +0100
http://bitbucket.org/pypy/pypy/changeset/ae84c87cdd28/

Log:    Try to clean up rmmap and use hints for all internal mmap()s

diff --git a/rpython/rlib/rmmap.py b/rpython/rlib/rmmap.py
--- a/rpython/rlib/rmmap.py
+++ b/rpython/rlib/rmmap.py
@@ -694,15 +694,10 @@
 
     def allocate_memory_chunk(map_size):
         # used by the memory allocator (in llarena.py, from minimarkpage.py)
-        flags = MAP_PRIVATE | MAP_ANONYMOUS
-        prot = PROT_READ | PROT_WRITE
+        hint = hint_regular
         if we_are_translated():
-            flags = NonConstant(flags)
-            prot = NonConstant(prot)
-        res = c_mmap_safe(rffi.cast(PTR, 0), map_size, prot, flags, -1, 0)
-        if res == rffi.cast(PTR, -1):
-            res = rffi.cast(PTR, 0)
-        return res
+            hint = NonConstant(hint)
+        return mmap_hinted(hint, map_size)
 
     def reset_memory_chunk(addr, map_size):
         # used by the memory allocator (in llarena.py, from minimarkpage.py)
@@ -715,14 +710,50 @@
             flags = NonConstant(flags)
             prot = NonConstant(prot)
         c_mmap_safe(rffi.cast(PTR, addr), map_size, prot, flags, -1, 0)
+        # ignore unlikely errors
 
-    def alloc_hinted(hintp, map_size):
+    def mmap_hinted(hint, map_size):
+        from errno import ENOMEM
+        from rpython.rlib import debug
+
+        if _CYGWIN:
+            # XXX: JIT memory should be using mmap MAP_PRIVATE with
+            #      PROT_EXEC but Cygwin's fork() fails.  mprotect()
+            #      cannot be used, but seems to be unnecessary there.
+            #      Just use malloc().
+            return c_malloc_safe(map_size)
+
         flags = MAP_PRIVATE | MAP_ANONYMOUS
-        prot = PROT_EXEC | PROT_READ | PROT_WRITE
         if we_are_translated():
             flags = NonConstant(flags)
-            prot = NonConstant(prot)
-        return c_mmap_safe(hintp, map_size, prot, flags, -1, 0)
+        pos = hint.pos
+        if hint.direction < 0:
+            pos -= map_size
+        res = c_mmap_safe(rffi.cast(PTR, pos), map_size,
+                          hint.prot, flags, -1, 0)
+        if res == rffi.cast(PTR, -1):
+            # some systems (some versions of OS/X?) complain if they
+            # are passed a non-zero address.  Try again without a hint.
+            res = c_mmap_safe(rffi.cast(PTR, 0), map_size,
+                              hint.prot, flags, -1, 0)
+            if res == rffi.cast(PTR, -1):
+                # ENOMEM simply raises MemoryError, but other errors are fatal
+                if rposix.get_saved_errno() != ENOMEM:
+                    if hint.prot & PROT_EXEC:
+                        debug.fatalerror_notb(
+                            "Got an unexpected error trying to allocate some "
+                            "memory for the JIT (tried to do mmap() with "
+                            "PROT_EXEC|PROT_READ|PROT_WRITE).  This can be 
caused "
+                            "by a system policy like PAX.  You need to find 
how "
+                            "to work around the policy on your system.")
+                    else:
+                        debug.fatalerror_notb(
+                            "Got an unexpected error trying to allocate memory 
"
+                            "with mmap().  Cannot continue.")
+                return rffi.cast(PTR, 0)
+        else:
+            hint.pos += map_size * hint.direction
+        return res
 
     def clear_large_memory_chunk_aligned(addr, map_size):
         addr = rffi.cast(PTR, addr)
@@ -734,47 +765,51 @@
         res = c_mmap_safe(addr, map_size, prot, flags, -1, 0)
         return res == addr
 
-    # XXX is this really necessary?
-    class Hint:
-        if sys.maxint <= 2**32:
-            pos = -0x4fff0000   # for reproducible results
-        else:
-            pos = 0x4fde00000000
-    hint = Hint()
+    # gives a hint to mmap(), for reproducible results, but also to
+    # avoid the following problem.  We use both malloc() for all large
+    # objects, and direct mmap() of 512KB arenas for small objects.
+    # Without any hint, the mmap() tend to go just after the malloc()
+    # zone; and then the malloc() zone cannot grow and fragments.  We
+    # avoid that by hinting the mmap()s to go somewhere else.
+    #
+    # The 'hint_regular' decrements.  We also allocate a few smaller
+    # executable zones for the JIT's machine code; this is 'hint_jit'
+    # which increments.
+    #
+    # These hints are valid on Linux.  XXX check on OS/X and possibly
+    # elsewhere.
+    #
+    # Using a 'Struct' instead of a regular 'class' as a way to work
+    # around the multiple steps of a translation.
+
+    HINT = lltype.Struct('HINT', ('pos', lltype.Signed),
+                                 ('direction', lltype.Signed),
+                                 ('prot', lltype.Signed))
+
+    hint_regular = lltype.malloc(HINT, flavor='raw', immortal=True)
+    if sys.maxint <= 2**32:
+        hint_regular.pos = -0x20000000
+    else:
+        hint_regular.pos = 0x4fde00000000
+    hint_regular.direction = -1
+    hint_regular.prot = PROT_READ | PROT_WRITE
+
+    hint_jit = lltype.malloc(HINT, flavor='raw', immortal=True)
+    hint_jit.pos = hint_regular.pos
+    hint_jit.direction = +1
+    hint_jit.prot = PROT_EXEC | PROT_READ | PROT_WRITE
 
     def alloc(map_size):
         """Allocate memory.  This is intended to be used by the JIT,
         so the memory has the executable bit set and gets allocated
         internally in case of a sandboxed process.
         """
-        from errno import ENOMEM
-        from rpython.rlib import debug
-
-        if _CYGWIN:
-            # XXX: JIT memory should be using mmap MAP_PRIVATE with
-            #      PROT_EXEC but Cygwin's fork() fails.  mprotect()
-            #      cannot be used, but seems to be unnecessary there.
-            res = c_malloc_safe(map_size)
-            if res == rffi.cast(PTR, 0):
-                raise MemoryError
-            return res
-        res = alloc_hinted(rffi.cast(PTR, hint.pos), map_size)
-        if res == rffi.cast(PTR, -1):
-            # some systems (some versions of OS/X?) complain if they
-            # are passed a non-zero address.  Try again.
-            res = alloc_hinted(rffi.cast(PTR, 0), map_size)
-            if res == rffi.cast(PTR, -1):
-                # ENOMEM simply raises MemoryError, but other errors are fatal
-                if rposix.get_saved_errno() != ENOMEM:
-                    debug.fatalerror_notb(
-                        "Got an unexpected error trying to allocate some "
-                        "memory for the JIT (tried to do mmap() with "
-                        "PROT_EXEC|PROT_READ|PROT_WRITE).  This can be caused "
-                        "by a system policy like PAX.  You need to find how "
-                        "to work around the policy on your system.")
-                raise MemoryError
-        else:
-            hint.pos += map_size
+        hint = hint_jit
+        if we_are_translated():
+            hint = NonConstant(hint)
+        res = mmap_hinted(hint, map_size)
+        if res == rffi.cast(PTR, 0):
+            raise MemoryError
         return res
     alloc._annenforceargs_ = (int,)
 
@@ -909,11 +944,6 @@
         m.map_handle = INVALID_HANDLE
         raise winerror
 
-    class Hint:
-        pos = -0x4fff0000   # for reproducible results
-    hint = Hint()
-    # XXX this has no effect on windows
-
     def alloc(map_size):
         """Allocate memory.  This is intended to be used by the JIT,
         so the memory has the executable bit set.
diff --git a/rpython/rlib/test/test_rmmap.py b/rpython/rlib/test/test_rmmap.py
--- a/rpython/rlib/test/test_rmmap.py
+++ b/rpython/rlib/test/test_rmmap.py
@@ -73,6 +73,11 @@
         f.write(size*4096*"c")
         f.flush()
 
+        class Hint:
+            prot = mmap.PROT_EXEC | mmap.PROT_READ | mmap.PROT_WRITE
+            direction = -1
+        hint = Hint()
+
         def func(no):
             m = mmap.mmap(no, size*4096)
             m.unmap_range(left*4096, (right-left)*4096)
@@ -84,7 +89,8 @@
                 return rffi.ptradd(m.data, offset)
             def as_num(ptr):
                 return rffi.cast(lltype.Unsigned, ptr)
-            res = mmap.alloc_hinted(in_map(m, (left+right)/2 * 4096), 4096)
+            hint.pos = rffi.cast(lltype.Signed, in_map(m, (left+right)/2 * 
4096))
+            res = mmap.mmap_hinted(hint, 4096)
             assert as_num(in_map(m, left*4096)) <= as_num(res) < 
as_num(in_map(m, right*4096))
         interpret(func, [f.fileno()])
         f.close()
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to