Author: Armin Rigo <[email protected]>
Branch:
Changeset: r76476:cc84b54369e9
Date: 2015-03-19 17:27 +0100
http://bitbucket.org/pypy/pypy/changeset/cc84b54369e9/
Log: In the incminimark GC, try to find all "raise MemoryError" that
can't be guaranteed to leave the GC in a correct state, and turn
them into clear fatal errors.
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -62,7 +62,8 @@
from rpython.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask, r_uint
from rpython.rlib.rarithmetic import LONG_BIT_SHIFT
from rpython.rlib.debug import ll_assert, debug_print, debug_start, debug_stop
-from rpython.rlib.objectmodel import specialize, we_are_translated
+from rpython.rlib.objectmodel import specialize
+from rpython.memory.gc.minimarkpage import out_of_memory
#
# Handles the objects in 2 generations:
@@ -474,7 +475,7 @@
# anyway so it doesn't even counct.
nursery = llarena.arena_malloc(self._nursery_memory_size(), 0)
if not nursery:
- raise MemoryError("cannot allocate nursery")
+ out_of_memory("cannot allocate nursery")
return nursery
def allocate_nursery(self):
@@ -695,13 +696,9 @@
minor_collection_count = 0
while True:
- if not we_are_translated():
- # debug: don't use 'nursery_free', but only if not translated;
- # in real code we might get a MemoryError in minor_collection()
- # and exit this function unexpectedly, but still catch the
- # MemoryError somewhere and continue afterwards --- if we then
- # see 'nursery_free == NULL', we segfault.
- del self.nursery_free
+ self.nursery_free = llmemory.NULL # debug: don't use me
+ # note: no "raise MemoryError" between here and the next time
+ # we initialize nursery_free!
if self.nursery_barriers.non_empty():
size_gc_header = self.gcheaderbuilder.size_gc_header
@@ -1956,7 +1953,7 @@
#
arena = llarena.arena_malloc(raw_malloc_usage(totalsize), False)
if not arena:
- raise MemoryError("cannot allocate object")
+ out_of_memory("out of memory: couldn't allocate a few KB more")
llarena.arena_reserve(arena, totalsize)
#
size_gc_header = self.gcheaderbuilder.size_gc_header
@@ -2154,9 +2151,9 @@
# even higher memory consumption. To prevent it, if it's
# the second time we are here, then abort the program.
if self.max_heap_size_already_raised:
- llop.debug_fatalerror(lltype.Void,
- "Using too much memory,
aborting")
+ out_of_memory("using too much memory, aborting")
self.max_heap_size_already_raised = True
+ self.gc_state = STATE_SCANNING
raise MemoryError
self.gc_state = STATE_FINALIZING
diff --git a/rpython/memory/gc/minimarkpage.py
b/rpython/memory/gc/minimarkpage.py
--- a/rpython/memory/gc/minimarkpage.py
+++ b/rpython/memory/gc/minimarkpage.py
@@ -2,7 +2,7 @@
from rpython.rtyper.lltypesystem import lltype, llmemory, llarena, rffi
from rpython.rlib.rarithmetic import LONG_BIT, r_uint
from rpython.rlib.objectmodel import we_are_translated
-from rpython.rlib.debug import ll_assert
+from rpython.rlib.debug import ll_assert, fatalerror
WORD = LONG_BIT // 8
NULL = llmemory.NULL
@@ -294,7 +294,7 @@
# be a page-aligned address
arena_base = llarena.arena_malloc(self.arena_size, False)
if not arena_base:
- raise MemoryError("couldn't allocate the next arena")
+ out_of_memory("out of memory: couldn't allocate the next arena")
arena_end = arena_base + self.arena_size
#
# 'firstpage' points to the first unused page
@@ -593,3 +593,10 @@
if isinstance(size, int):
size = llmemory.sizeof(lltype.Char) * size
return size
+
+def out_of_memory(errmsg):
+ """Signal a fatal out-of-memory error and abort. For situations where
+ it is hard to write and test code that would handle a MemoryError
+ exception gracefully.
+ """
+ fatalerror(errmsg)
diff --git a/rpython/translator/c/test/test_newgc.py
b/rpython/translator/c/test/test_newgc.py
--- a/rpython/translator/c/test/test_newgc.py
+++ b/rpython/translator/c/test/test_newgc.py
@@ -1557,26 +1557,6 @@
res = self.run("limited_memory", -1, runner=myrunner)
assert res == 42
- define_limited_memory_linux = define_limited_memory
-
- def test_limited_memory_linux(self):
- if not sys.platform.startswith('linux'):
- py.test.skip("linux only")
- py.test.skip('XXX fix me?')
- #
- import random
- #
- def myrunner(args):
- args1 = ['/bin/bash', '-c', 'ulimit -v %d && %s' %
- (ulimitv, ' '.join(args),)]
- return subprocess.check_output(args1)
- #
- for i in range(10):
- ulimitv = random.randrange(50000, 100000)
- print ulimitv
- res = self.run("limited_memory_linux", -1, runner=myrunner)
- assert res == 42
-
class TestIncrementalMiniMarkGC(TestMiniMarkGC):
gcpolicy = "incminimark"
@@ -1630,6 +1610,29 @@
res = self.run("random_pin")
assert res == 28495
+ define_limited_memory_linux = TestMiniMarkGC.define_limited_memory.im_func
+
+ def test_limited_memory_linux(self):
+ if not sys.platform.startswith('linux'):
+ py.test.skip("linux only")
+ #
+ import random
+ #
+ def myrunner(args):
+ args1 = ['/bin/bash', '-c', 'ulimit -v %d && %s' %
+ (ulimitv, ' '.join(args),)]
+ popen = subprocess.Popen(args1, stderr=subprocess.PIPE)
+ _, child_stderr = popen.communicate()
+ assert popen.wait() == 134 # aborted
+ assert 'out of memory:' in child_stderr
+ return '42'
+ #
+ for i in range(10):
+ ulimitv = random.randrange(50000, 100000)
+ print ulimitv
+ res = self.run("limited_memory_linux", -1, runner=myrunner)
+ assert res == 42
+
# ____________________________________________________________________
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit