[pypy-svn] r27605 - in pypy/dist/pypy/rpython/memory: . test

cfbolz at codespeak.net cfbolz at codespeak.net
Mon May 22 17:29:07 CEST 2006


Author: cfbolz
Date: Mon May 22 17:29:06 2006
New Revision: 27605

Modified:
   pypy/dist/pypy/rpython/memory/gc.py
   pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py
Log:
try to make recursive calls to collect not crash. does not work with stackless,
so just prevent those calls :-(. some tests.


Modified: pypy/dist/pypy/rpython/memory/gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc.py	Mon May 22 17:29:06 2006
@@ -153,6 +153,7 @@
         #   was already freed.  The objects in 'malloced_objects' are not
         #   found via 'poolnodes'.
         self.poolnodes = lltype.nullptr(self.POOLNODE)
+        self.collect_in_progress = False
 
     def malloc(self, typeid, length=0):
         size = self.fixed_size(typeid)
@@ -217,9 +218,14 @@
         #    call __del__, move the object to the list of object-without-del
         import time
         from pypy.rpython.lltypesystem.lloperation import llop
+        # XXX the following two lines should not be there, but without them
+        # there is a strange crash in decodestate when using stackless :-(
+        if self.collect_in_progress:
+            return
         if DEBUG_PRINT:
             llop.debug_print(lltype.Void, 'collecting...')
         start_time = time.time()
+        self.collect_in_progress = True
         roots = self.get_roots()
         size_gc_header = self.gcheaderbuilder.size_gc_header
 ##        llop.debug_view(lltype.Void, self.malloced_objects, self.poolnodes,
@@ -323,6 +329,7 @@
         self.malloced_objects = firstpoolnode.linkedlist
         self.poolnodes = firstpoolnode.nextnode
         lltype.free(firstpoolnode, flavor='raw')
+        #llop.debug_view(lltype.Void, self.malloced_objects, self.malloced_objects_with_finalizer, size_gc_header)
 
         if curr_heap_size > self.bytes_malloced_threshold:
             self.bytes_malloced_threshold = curr_heap_size
@@ -348,23 +355,49 @@
 ##                        size_gc_header)
         assert self.heap_usage + old_malloced == curr_heap_size + freed_size
 
-        # call finalizers if needed
         self.heap_usage = curr_heap_size
         hdr = self.malloced_objects_with_finalizer
         self.malloced_objects_with_finalizer = lltype.nullptr(self.HDR)
+        last = lltype.nullptr(self.HDR)
         while hdr:
             next = hdr.next
             if hdr.typeid & 1:
-                hdr.next = self.malloced_objects_with_finalizer
-                self.malloced_objects_with_finalizer = hdr
+                hdr.next = lltype.nullptr(self.HDR)
+                if not self.malloced_objects_with_finalizer:
+                    self.malloced_objects_with_finalizer = hdr
+                else:
+                    last.next = hdr
                 hdr.typeid = hdr.typeid & (~1)
+                last = hdr
             else:
                 obj = llmemory.cast_ptr_to_adr(hdr) + size_gc_header
                 finalizer = self.getfinalizer(hdr.typeid >> 1)
-                finalizer(obj)
+                # make malloced_objects_with_finalizer consistent
+                # for the sake of a possible collection caused by finalizer
+                if not self.malloced_objects_with_finalizer:
+                    self.malloced_objects_with_finalizer = next
+                else:
+                    last.next = next
                 hdr.next = self.malloced_objects
                 self.malloced_objects = hdr
+                #llop.debug_view(lltype.Void, self.malloced_objects, self.malloced_objects_with_finalizer, size_gc_header)
+                finalizer(obj)
+                if not self.collect_in_progress: # another collection was caused?
+                    return
+                if not last:
+                    if self.malloced_objects_with_finalizer == next:
+                        self.malloced_objects_with_finalizer = lltype.nullptr(self.HDR)
+                    else:
+                        # now it gets annoying: finalizer caused a malloc of something
+                        # with a finalizer
+                        last = self.malloced_objects_with_finalizer
+                        while last.next != next:
+                            last = last.next
+                            last.next = lltype.nullptr(self.HDR)
+                else:
+                    last.next = lltype.nullptr(self.HDR)
             hdr = next
+        self.collect_in_progress = False
 
     STATISTICS_NUMBERS = 2
 

Modified: pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py	(original)
+++ pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py	Mon May 22 17:29:06 2006
@@ -347,6 +347,73 @@
         res = run([5, 42]) #XXX pure lazyness here too
         assert res == 12
 
+    def test_finalizer_resurrects(self):
+        class B(object):
+            pass
+        b = B()
+        b.nextid = 0
+        b.num_deleted = 0
+        class A(object):
+            def __init__(self):
+                self.id = b.nextid
+                b.nextid += 1
+            def __del__(self):
+                b.num_deleted += 1
+                b.a = self
+        def f(x, y):
+            a = A()
+            i = 0
+            while i < x:
+                i += 1
+                a = A()
+            llop.gc__collect(lltype.Void)
+            llop.gc__collect(lltype.Void)
+            aid = b.a.id
+            b.a = None
+            # check that __del__ is not called again
+            llop.gc__collect(lltype.Void)
+            llop.gc__collect(lltype.Void)
+            return b.num_deleted * 10 + aid + 100 * (b.a is None)
+        run = self.runner(f, nbargs=2)
+        res = run([5, 42]) #XXX pure lazyness here too
+        assert 160 <= res <= 165
+
+    def test_collect_during_collect(self):
+        class B(object):
+            pass
+        b = B()
+        b.nextid = 1
+        b.num_deleted = 0
+        class A(object):
+            def __init__(self):
+                self.id = b.nextid
+                b.nextid += 1
+            def __del__(self):
+                b.num_deleted += 1
+                C()
+                C()
+                llop.gc__collect(lltype.Void)
+        class C(A):
+            def __del__(self):
+                b.num_deleted += 1
+        def f(x, y):
+            persistent_a1 = A()
+            persistent_a2 = A()
+            i = 0
+            while i < x:
+                i += 1
+                a = A()
+            persistent_a3 = A()
+            persistent_a4 = A()
+            llop.gc__collect(lltype.Void)
+            llop.gc__collect(lltype.Void)
+            b.bla = persistent_a1.id + persistent_a2.id + persistent_a3.id + persistent_a4.id
+            return b.num_deleted
+        run = self.runner(f, nbargs=2)
+        # runs collect recursively 4 times
+        res = run([4, 42]) #XXX pure lazyness here too
+        assert res == 12
+
     def test_cloning(self):
         B = lltype.GcStruct('B', ('x', lltype.Signed))
         A = lltype.GcStruct('A', ('b', lltype.Ptr(B)),



More information about the Pypy-commit mailing list