[pypy-commit] pypy default: Found out how, in general on POSIX, we're supposed to get fresh
arigo
noreply at buildbot.pypy.org
Fri Feb 21 09:26:28 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r69235:992e29624c5f
Date: 2014-02-21 09:25 +0100
http://bitbucket.org/pypy/pypy/changeset/992e29624c5f/
Log: Found out how, in general on POSIX, we're supposed to get fresh
zero-mapped pages inside an mmap. Replaces the hacks with madvise()
or reading /dev/zero. The answer is simply to call mmap(MAP_FIXED)
again.
diff --git a/rpython/rlib/rmmap.py b/rpython/rlib/rmmap.py
--- a/rpython/rlib/rmmap.py
+++ b/rpython/rlib/rmmap.py
@@ -55,7 +55,7 @@
# constants, look in sys/mman.h and platform docs for the meaning
# some constants are linux only so they will be correctly exposed outside
# depending on the OS
- constant_names = ['MAP_SHARED', 'MAP_PRIVATE',
+ constant_names = ['MAP_SHARED', 'MAP_PRIVATE', 'MAP_FIXED',
'PROT_READ', 'PROT_WRITE',
'MS_SYNC']
opt_constant_names = ['MAP_ANON', 'MAP_ANONYMOUS', 'MAP_NORESERVE',
@@ -675,10 +675,17 @@
return m
def alloc_hinted(hintp, map_size):
- flags = MAP_PRIVATE | MAP_ANONYMOUS
- prot = PROT_EXEC | PROT_READ | PROT_WRITE
+ flags = NonConstant(MAP_PRIVATE | MAP_ANONYMOUS)
+ prot = NonConstant(PROT_EXEC | PROT_READ | PROT_WRITE)
return c_mmap_safe(hintp, map_size, prot, flags, -1, 0)
+ def clear_large_memory_chunk_aligned(addr, map_size):
+ addr = rffi.cast(PTR, addr)
+ flags = NonConstant(MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS)
+ prot = NonConstant(PROT_READ | PROT_WRITE)
+ res = c_mmap_safe(addr, map_size, prot, flags, -1, 0)
+ return res == addr
+
# XXX is this really necessary?
class Hint:
pos = -0x4fff0000 # for reproducible results
diff --git a/rpython/rtyper/lltypesystem/llarena.py b/rpython/rtyper/lltypesystem/llarena.py
--- a/rpython/rtyper/lltypesystem/llarena.py
+++ b/rpython/rtyper/lltypesystem/llarena.py
@@ -409,41 +409,28 @@
MEMORY_ALIGNMENT = memory_alignment()
-if sys.platform.startswith('linux'):
- # This only works with linux's madvise(), which is really not a memory
- # usage hint but a real command. It guarantees that after MADV_DONTNEED
- # the pages are cleared again.
+if os.name == 'posix':
+ # The general Posix solution to clear a large range of memory that
+ # was obtained with mmap() is to call mmap() again with MAP_FIXED.
- # Note that the trick of the general 'posix' section below, i.e.
- # reading /dev/zero, does not seem to have the correct effect of
- # lazily-allocating pages on all Linux systems.
+ legacy_getpagesize = rffi.llexternal('getpagesize', [], rffi.INT,
+ sandboxsafe=True, _nowrapper=True)
- from rpython.rtyper.tool import rffi_platform
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- _eci = ExternalCompilationInfo(includes=['sys/mman.h'])
- MADV_DONTNEED = rffi_platform.getconstantinteger('MADV_DONTNEED',
- '#include <sys/mman.h>')
- linux_madvise = rffi.llexternal('madvise',
- [llmemory.Address, rffi.SIZE_T, rffi.INT],
- rffi.INT,
- sandboxsafe=True, _nowrapper=True,
- compilation_info=_eci)
- linux_getpagesize = rffi.llexternal('getpagesize', [], rffi.INT,
- sandboxsafe=True, _nowrapper=True,
- compilation_info=_eci)
-
- class LinuxPageSize:
+ class PosixPageSize:
def __init__(self):
self.pagesize = 0
def _cleanup_(self):
self.pagesize = 0
- linuxpagesize = LinuxPageSize()
+ posixpagesize = PosixPageSize()
def clear_large_memory_chunk(baseaddr, size):
- pagesize = linuxpagesize.pagesize
+ from rpython.rlib import rmmap
+
+ pagesize = posixpagesize.pagesize
if pagesize == 0:
- pagesize = rffi.cast(lltype.Signed, linux_getpagesize())
- linuxpagesize.pagesize = pagesize
+ pagesize = rffi.cast(lltype.Signed, legacy_getpagesize())
+ posixpagesize.pagesize = pagesize
+
if size > 2 * pagesize:
lowbits = rffi.cast(lltype.Signed, baseaddr) & (pagesize - 1)
if lowbits: # clear the initial misaligned part, if any
@@ -452,56 +439,13 @@
baseaddr += partpage
size -= partpage
length = size & -pagesize
- madv_length = rffi.cast(rffi.SIZE_T, length)
- madv_flags = rffi.cast(rffi.INT, MADV_DONTNEED)
- err = linux_madvise(baseaddr, madv_length, madv_flags)
- if rffi.cast(lltype.Signed, err) == 0:
- baseaddr += length # madvise() worked
+ if rmmap.clear_large_memory_chunk_aligned(baseaddr, length):
+ baseaddr += length # clearing worked
size -= length
+
if size > 0: # clear the final misaligned part, if any
llmemory.raw_memclear(baseaddr, size)
-elif os.name == 'posix':
- READ_MAX = (sys.maxint//4) + 1 # upper bound on reads to avoid surprises
- raw_os_open = rffi.llexternal('open',
- [rffi.CCHARP, rffi.INT, rffi.MODE_T],
- rffi.INT,
- sandboxsafe=True, _nowrapper=True)
- raw_os_read = rffi.llexternal('read',
- [rffi.INT, llmemory.Address, rffi.SIZE_T],
- rffi.SIZE_T,
- sandboxsafe=True, _nowrapper=True)
- raw_os_close = rffi.llexternal('close',
- [rffi.INT],
- rffi.INT,
- sandboxsafe=True, _nowrapper=True)
- _dev_zero = rffi.str2charp('/dev/zero') # prebuilt
- lltype.render_immortal(_dev_zero)
-
- def clear_large_memory_chunk(baseaddr, size):
- # on some Unixy platforms, reading from /dev/zero is the fastest way
- # to clear arenas, because the kernel knows that it doesn't
- # need to even allocate the pages before they are used.
-
- # NB.: careful, don't do anything that could malloc here!
- # this code is called during GC initialization.
- fd = raw_os_open(_dev_zero,
- rffi.cast(rffi.INT, os.O_RDONLY),
- rffi.cast(rffi.MODE_T, 0644))
- if rffi.cast(lltype.Signed, fd) != -1:
- while size > 0:
- size1 = rffi.cast(rffi.SIZE_T, min(READ_MAX, size))
- count = raw_os_read(fd, baseaddr, size1)
- count = rffi.cast(lltype.Signed, count)
- if count <= 0:
- break
- size -= count
- baseaddr += count
- raw_os_close(fd)
-
- if size > 0: # reading from /dev/zero failed, fallback
- llmemory.raw_memclear(baseaddr, size)
-
else:
# XXX any better implementation on Windows?
# Should use VirtualAlloc() to reserve the range of pages,
More information about the pypy-commit
mailing list