[pypy-svn] r53596 - in pypy/dist/pypy: rlib rpython rpython/lltypesystem rpython/memory rpython/memory/gc rpython/memory/gctransform rpython/memory/test translator/c translator/c/src translator/c/test

arigo at codespeak.net arigo at codespeak.net
Tue Apr 8 22:48:28 CEST 2008


Author: arigo
Date: Tue Apr  8 22:48:25 2008
New Revision: 53596

Modified:
   pypy/dist/pypy/rlib/rgc.py
   pypy/dist/pypy/rpython/llinterp.py
   pypy/dist/pypy/rpython/lltypesystem/llheap.py
   pypy/dist/pypy/rpython/lltypesystem/lloperation.py
   pypy/dist/pypy/rpython/memory/gc/base.py
   pypy/dist/pypy/rpython/memory/gc/semispace.py
   pypy/dist/pypy/rpython/memory/gctransform/framework.py
   pypy/dist/pypy/rpython/memory/gcwrapper.py
   pypy/dist/pypy/rpython/memory/test/snippet.py
   pypy/dist/pypy/translator/c/gc.py
   pypy/dist/pypy/translator/c/src/mem.h
   pypy/dist/pypy/translator/c/test/test_boehm.py
Log:
Add and implement rlib.rgc.{disable,enable}_finalizers().


Modified: pypy/dist/pypy/rlib/rgc.py
==============================================================================
--- pypy/dist/pypy/rlib/rgc.py	(original)
+++ pypy/dist/pypy/rlib/rgc.py	Tue Apr  8 22:48:25 2008
@@ -11,6 +11,15 @@
     """
     pass
 
+def disable_finalizers():
+    """Prevent __del__ methods from running.
+    Calls to disable_finalizers/enable_finalizers can be nested.
+    """
+    gc.disable()     # rough approximation on top of CPython
+
+def enable_finalizers():
+    gc.enable()     # rough approximation on top of CPython
+
 # ____________________________________________________________
 # Framework GC features
 
@@ -162,3 +171,14 @@
         [v_nbytes] = hop.inputargs(lltype.Signed)
         return hop.genop('gc_set_max_heap_size', [v_nbytes],
                          resulttype=lltype.Void)
+
+class CollectEntry(ExtRegistryEntry):
+    _about_ = (disable_finalizers, enable_finalizers)
+
+    def compute_result_annotation(self):
+        from pypy.annotation import model as annmodel
+        return annmodel.s_None
+
+    def specialize_call(self, hop):
+        opname = 'gc__' + self.instance.__name__
+        return hop.genop(opname, [], resulttype=hop.r_result)

Modified: pypy/dist/pypy/rpython/llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/llinterp.py	(original)
+++ pypy/dist/pypy/rpython/llinterp.py	Tue Apr  8 22:48:25 2008
@@ -753,6 +753,12 @@
     def op_gc__collect(self):
         self.heap.collect()
 
+    def op_gc__disable_finalizers(self):
+        self.heap.disable_finalizers()
+
+    def op_gc__enable_finalizers(self):
+        self.heap.enable_finalizers()
+
     def op_gc_free(self, addr):
         # what can you do?
         pass
@@ -836,7 +842,7 @@
 
     def op_raw_malloc(self, size):
         assert lltype.typeOf(size) == lltype.Signed
-        return self.heap.raw_malloc(size)
+        return llmemory.raw_malloc(size)
 
     op_boehm_malloc = op_boehm_malloc_atomic = op_raw_malloc
 
@@ -848,20 +854,20 @@
 
     def op_raw_malloc_usage(self, size):
         assert lltype.typeOf(size) == lltype.Signed
-        return self.heap.raw_malloc_usage(size)
+        return llmemory.raw_malloc_usage(size)
 
     def op_raw_free(self, addr):
         checkadr(addr) 
-        self.heap.raw_free(addr)
+        llmemory.raw_free(addr)
 
     def op_raw_memclear(self, addr, size):
         checkadr(addr)
-        self.heap.raw_memclear(addr, size)
+        llmemory.raw_memclear(addr, size)
 
     def op_raw_memcopy(self, fromaddr, toaddr, size):
         checkadr(fromaddr)
         checkadr(toaddr)
-        self.heap.raw_memcopy(fromaddr, toaddr, size)
+        llmemory.raw_memcopy(fromaddr, toaddr, size)
 
     def op_raw_load(self, addr, typ, offset):
         checkadr(addr)

Modified: pypy/dist/pypy/rpython/lltypesystem/llheap.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/llheap.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/llheap.py	Tue Apr  8 22:48:25 2008
@@ -1,14 +1,11 @@
 # only for the LLInterpreter.  Don't use directly.
 
 from pypy.rpython.lltypesystem.lltype import pyobjectptr, malloc, free, typeOf
-from pypy.rpython.lltypesystem.llmemory import raw_malloc, raw_free
-from pypy.rpython.lltypesystem.llmemory import raw_memclear, raw_memcopy
-from pypy.rpython.lltypesystem.llmemory import raw_malloc_usage, \
-    weakref_create, weakref_deref
+from pypy.rpython.lltypesystem.llmemory import weakref_create, weakref_deref
 
 setfield = setattr
 from operator import setitem as setarrayitem
-from gc import collect
+from pypy.rlib.rgc import collect, disable_finalizers, enable_finalizers
 
 def setinterior(toplevelcontainer, inneraddr, INNERTYPE, newvalue):
     assert typeOf(newvalue) == INNERTYPE

Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lloperation.py	Tue Apr  8 22:48:25 2008
@@ -387,6 +387,8 @@
     # __________ GC operations __________
 
     'gc__collect':          LLOp(canunwindgc=True),
+    'gc__disable_finalizers': LLOp(),
+    'gc__enable_finalizers':  LLOp(canunwindgc=True),
     'gc_free':              LLOp(),
     'gc_fetch_exception':   LLOp(),
     'gc_restore_exception': LLOp(),

Modified: pypy/dist/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc/base.py	Tue Apr  8 22:48:25 2008
@@ -114,6 +114,12 @@
     def x_clone(self, clonedata):
         raise RuntimeError("no support for x_clone in the GC")
 
+    def disable_finalizers(self):
+        pass     # xxx this should really be implemented by all subclasses
+
+    def enable_finalizers(self):
+        pass     # xxx this should really be implemented by all subclasses
+
     def trace(self, obj, callback, arg):
         """Enumerate the locations inside the given obj that can contain
         GC pointers.  For each such location, callback(pointer, arg) is

Modified: pypy/dist/pypy/rpython/memory/gc/semispace.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc/semispace.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc/semispace.py	Tue Apr  8 22:48:25 2008
@@ -524,17 +524,18 @@
         self.run_finalizers = new_run_finalizer
 
     def execute_finalizers(self):
-        if self.finalizer_lock_count > 0:
-            return    # the outer invocation of execute_finalizers() will do it
-        self.finalizer_lock_count = 1
+        self.finalizer_lock_count += 1
         try:
             while self.run_finalizers.non_empty():
                 #print "finalizer"
+                if self.finalizer_lock_count > 1:
+                    # the outer invocation of execute_finalizers() will do it
+                    break
                 obj = self.run_finalizers.popleft()
                 finalizer = self.getfinalizer(self.get_type_id(obj))
                 finalizer(obj)
         finally:
-            self.finalizer_lock_count = 0
+            self.finalizer_lock_count -= 1
 
     STATISTICS_NUMBERS = 0
 

Modified: pypy/dist/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform/framework.py	Tue Apr  8 22:48:25 2008
@@ -217,6 +217,10 @@
             + [annmodel.SomeBool(), annmodel.SomeBool()], s_gcref)
         self.collect_ptr = getfn(GCClass.collect.im_func,
             [s_gc], annmodel.s_None)
+        self.disable_finalizers_ptr = getfn(GCClass.disable_finalizers.im_func,
+            [s_gc], annmodel.s_None)
+        self.enable_finalizers_ptr = getfn(GCClass.enable_finalizers.im_func,
+            [s_gc], annmodel.s_None)
 
         # in some GCs we can inline the common case of
         # malloc_fixedsize(typeid, size, True, False, False)
@@ -526,6 +530,21 @@
                   resultvar=op.result)
         self.pop_roots(hop, livevars)
 
+    def gct_gc__disable_finalizers(self, hop):
+        # cannot collect()
+        op = hop.spaceop
+        hop.genop("direct_call", [self.disable_finalizers_ptr,
+                                  self.c_const_gc],
+                  resultvar=op.result)
+
+    def gct_gc__enable_finalizers(self, hop):
+        # can collect() because it typically calls pending finalizers
+        op = hop.spaceop
+        livevars = self.push_roots(hop)
+        hop.genop("direct_call", [self.enable_finalizers_ptr, self.c_const_gc],
+                  resultvar=op.result)
+        self.pop_roots(hop, livevars)
+
     def gct_gc_x_swap_pool(self, hop):
         op = hop.spaceop
         [v_malloced] = op.args

Modified: pypy/dist/pypy/rpython/memory/gcwrapper.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gcwrapper.py	(original)
+++ pypy/dist/pypy/rpython/memory/gcwrapper.py	Tue Apr  8 22:48:25 2008
@@ -81,6 +81,12 @@
     def collect(self):
         self.gc.collect()
 
+    def disable_finalizers(self):
+        self.gc.disable_finalizers()
+
+    def enable_finalizers(self):
+        self.gc.enable_finalizers()
+
     def weakref_create_getlazy(self, objgetter):
         # we have to be lazy in reading the llinterp variable containing
         # the 'obj' pointer, because the gc.malloc() call below could

Modified: pypy/dist/pypy/rpython/memory/test/snippet.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/snippet.py	(original)
+++ pypy/dist/pypy/rpython/memory/test/snippet.py	Tue Apr  8 22:48:25 2008
@@ -1,9 +1,15 @@
+import os
+from pypy.tool.udir import udir
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.lltypesystem.lloperation import llop
 
 class SemiSpaceGCTests:
     large_tests_ok = False
 
+    def run_ok(self, f):
+        res = self.run(f)
+        assert res == 'ok'
+
     def test_finalizer_order(self):
         import random
         from pypy.tool.algo import graphlib
@@ -119,3 +125,53 @@
             print summary
             print msg
             py.test.fail(msg)
+
+    def test_disable_finalizers(self):
+        from pypy.rlib import rgc
+        if self.large_tests_ok:
+            MULTIPLY = 50
+        else:
+            MULTIPLY = 1
+
+        tmpfilepath = udir.join('test_disable_finalizers')
+
+        class State:
+            pass
+        state = State()
+        state.tmpfilename = str(tmpfilepath)
+        state.fd = -1
+
+        class X(object):
+            def __init__(self, x):
+                self.x = str(x)
+            def __del__(self):
+                if state.fd >= 0:
+                    os.write(state.fd, self.x)
+
+        def do_stuff():
+            lst = [X(n) for n in range(7*MULTIPLY)]
+            return len(lst)
+
+        def f():
+            fd = os.open(state.tmpfilename,
+                         os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
+                         0644)
+            state.fd = fd
+            for i in range(10*MULTIPLY):
+                do_stuff()
+                rgc.disable_finalizers()
+                os.write(fd, '-')
+                do_stuff()
+                os.write(fd, '+')
+                rgc.enable_finalizers()
+            state.fd = -1
+            os.close(fd)
+            return 'ok'
+
+        self.run_ok(f)
+        buf = tmpfilepath.read()
+        assert buf.count('-') == buf.count('+')
+        assert buf.count('-') + buf.count('+') < len(buf)
+        for i in range(len(buf)):
+            if buf[i] == '-':
+                assert buf[i+1] == '+'

Modified: pypy/dist/pypy/translator/c/gc.py
==============================================================================
--- pypy/dist/pypy/translator/c/gc.py	(original)
+++ pypy/dist/pypy/translator/c/gc.py	Tue Apr  8 22:48:25 2008
@@ -134,6 +134,12 @@
     def OP_GC__COLLECT(self, funcgen, op):
         return ''
 
+    def OP_GC__DISABLE_FINALIZERS(self, funcgen, op):
+        return ''
+
+    def OP_GC__ENABLE_FINALIZERS(self, funcgen, op):
+        return ''
+
 
 class RefcountingRuntimeTypeInfo_OpaqueNode(ContainerNode):
     nodekind = 'refcnt rtti'

Modified: pypy/dist/pypy/translator/c/src/mem.h
==============================================================================
--- pypy/dist/pypy/translator/c/src/mem.h	(original)
+++ pypy/dist/pypy/translator/c/src/mem.h	Tue Apr  8 22:48:25 2008
@@ -131,20 +131,29 @@
 	else								   \
 		GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj)
 
+extern int boehm_gc_finalizer_lock;
 void boehm_gc_startup_code(void);
+void boehm_gc_finalizer_notifier(void);
+
+#define OP_GC__DISABLE_FINALIZERS(r)  boehm_gc_finalizer_lock++
+#define OP_GC__ENABLE_FINALIZERS(r)   (boehm_gc_finalizer_lock--,	\
+				       boehm_gc_finalizer_notifier())
 
 #ifndef PYPY_NOT_MAIN_FILE
-static void boehm_gc_finalizer_notifier(void)
+int boehm_gc_finalizer_lock = 0;
+void boehm_gc_finalizer_notifier(void)
 {
-	static int recursing = 0;
-	if (recursing)
-		return;  /* GC_invoke_finalizers() will be done by the
-			    boehm_gc_finalizer_notifier() that is
-			    currently in the C stack, when we return there */
-	recursing = 1;
-	while (GC_should_invoke_finalizers())
+	boehm_gc_finalizer_lock++;
+	while (GC_should_invoke_finalizers()) {
+		if (boehm_gc_finalizer_lock > 1) {
+			/* GC_invoke_finalizers() will be done by the
+			   boehm_gc_finalizer_notifier() that is
+			   currently in the C stack, when we return there */
+			break;
+		}
 		GC_invoke_finalizers();
-	recursing = 0;
+	}
+	boehm_gc_finalizer_lock--;
 }
 void boehm_gc_startup_code(void)
 {

Modified: pypy/dist/pypy/translator/c/test/test_boehm.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_boehm.py	(original)
+++ pypy/dist/pypy/translator/c/test/test_boehm.py	Tue Apr  8 22:48:25 2008
@@ -1,6 +1,7 @@
 import py
 from pypy.translator.translator import TranslationContext
 from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.memory.test import snippet
 from pypy.translator.tool.cbuild import check_boehm_presence
 from pypy.translator.c.genc import CExtModuleBuilder
 from pypy import conftest
@@ -365,3 +366,16 @@
         c_fn = self.getcompiled(fn, [int])
         res = c_fn(10000)
         assert res == 0
+
+    # reusing some tests from pypy.rpython.memory.test.snippet
+    large_tests_ok = True
+
+    def run_ok(self, f):
+        def wrapper():
+            return int(f() == 'ok')
+        c_fn = self.getcompiled(wrapper, [])
+        res = c_fn()
+        assert res == 1
+
+    test_disable_finalizers = (
+        snippet.SemiSpaceGCTests.test_disable_finalizers.im_func)



More information about the Pypy-commit mailing list