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

Reply via email to