[pypy-svn] r50824 - in pypy/dist/pypy: interpreter module/__builtin__ module/_file module/_socket module/_weakref

arigo at codespeak.net arigo at codespeak.net
Mon Jan 21 13:10:13 CET 2008


Author: arigo
Date: Mon Jan 21 13:10:12 2008
New Revision: 50824

Modified:
   pypy/dist/pypy/interpreter/baseobjspace.py
   pypy/dist/pypy/interpreter/typedef.py
   pypy/dist/pypy/module/__builtin__/interp_classobj.py
   pypy/dist/pypy/module/_file/interp_file.py
   pypy/dist/pypy/module/_socket/interp_socket.py
   pypy/dist/pypy/module/_weakref/interp__weakref.py
Log:
Add logic for built-in objects to make sure that all the weakrefs to
them are cleared before the rest of their __del__ methods run.

This showed up in pypy-c-boehm runs of
lib-python/modified-2.4.1/test/test_file.py,
where a weakref to a file could sometimes still
be alive after the file was closed by its __del__.


Modified: pypy/dist/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/dist/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/dist/pypy/interpreter/baseobjspace.py	Mon Jan 21 13:10:12 2008
@@ -117,6 +117,23 @@
         raise OperationError(space.w_TypeError, space.wrap(
             "cannot create weak reference to '%s' object" % typename))
 
+    def clear_all_weakrefs(self):
+        """Call this at the beginning of interp-level __del__() methods
+        in subclasses.  It ensures that weakrefs (if any) are cleared
+        before the object is further destroyed.
+        """
+        lifeline = self.getweakref()
+        if lifeline is not None:
+            # Clear all weakrefs to this object before we proceed with
+            # the destruction of the object.  We detach the lifeline
+            # first: if the code following before_del() calls the
+            # app-level, e.g. a user-defined __del__(), and this code
+            # tries to use weakrefs again, it won't reuse the broken
+            # (already-cleared) weakrefs from this lifeline.
+            self.setweakref(lifeline.space, None)
+            lifeline.clear_all_weakrefs()
+
+
 class Wrappable(W_Root):
     """A subclass of Wrappable is an internal, interpreter-level class
     that can nevertheless be exposed at application-level by space.wrap()."""

Modified: pypy/dist/pypy/interpreter/typedef.py
==============================================================================
--- pypy/dist/pypy/interpreter/typedef.py	(original)
+++ pypy/dist/pypy/interpreter/typedef.py	Mon Jan 21 13:10:12 2008
@@ -149,15 +149,7 @@
         parent_destructor = getattr(cls, '__del__', None)
         class Proto(object):
             def __del__(self):
-                lifeline = self.getweakref()
-                if lifeline is not None:
-                    # Clear all weakrefs to this object before we call
-                    # the app-level __del__.  We detach the lifeline
-                    # first: if the app-level __del__ tries to use
-                    # weakrefs again, they won't reuse the broken
-                    # (already-cleared) ones from this lifeline.
-                    self.setweakref(self.space, None)
-                    lifeline.clear_all_weakrefs()
+                self.clear_all_weakrefs()
                 try:
                     self.space.userdel(self)
                 except OperationError, e:
@@ -546,6 +538,12 @@
 weakref_descr.name = '__weakref__'
 
 def make_weakref_descr(cls):
+    """Make instances of the Wrappable subclass 'cls' weakrefable.
+    This returns the '__weakref__' desctriptor to use for the TypeDef.
+    Note that if the class also defines a custom '__del__', the
+    __del__ should call self.clear_all_weakrefs() before it clears
+    the resources used by the object.
+    """
     # force the interface into the given cls
     def getweakref(self):
         return self._lifeline_

Modified: pypy/dist/pypy/module/__builtin__/interp_classobj.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/interp_classobj.py	(original)
+++ pypy/dist/pypy/module/__builtin__/interp_classobj.py	Mon Jan 21 13:10:12 2008
@@ -694,19 +694,8 @@
 )
 
 class W_InstanceObjectWithDel(W_InstanceObject):
-    # XXX this is code duplication from pypy.interpreter.typedef
-    # find a way to prevent this.
     def __del__(self):
-        
-        lifeline = self.getweakref()
-        if lifeline is not None:
-            # Clear all weakrefs to this object before we call
-            # the app-level __del__.  We detach the lifeline
-            # first: if the app-level __del__ tries to use
-            # weakrefs again, they won't reuse the broken
-            # (already-cleared) ones from this lifeline.
-            self.setweakref(self.space, None)
-            lifeline.clear_all_weakrefs()
+        self.clear_all_weakrefs()
         try:
             self.descr_del()
         except OperationError, e:

Modified: pypy/dist/pypy/module/_file/interp_file.py
==============================================================================
--- pypy/dist/pypy/module/_file/interp_file.py	(original)
+++ pypy/dist/pypy/module/_file/interp_file.py	Mon Jan 21 13:10:12 2008
@@ -33,6 +33,7 @@
     def __del__(self):
         # assume that the file and stream objects are only visible in the
         # thread that runs __del__, so no race condition should be possible
+        self.clear_all_weakrefs()
         self.direct_close()
 
     def fdopenstream(self, stream, fd, mode, name):

Modified: pypy/dist/pypy/module/_socket/interp_socket.py
==============================================================================
--- pypy/dist/pypy/module/_socket/interp_socket.py	(original)
+++ pypy/dist/pypy/module/_socket/interp_socket.py	Mon Jan 21 13:10:12 2008
@@ -22,6 +22,10 @@
     return space.str_w(w_obj)
 
 class W_RSocket(Wrappable, RSocket):
+    def __del__(self):
+        self.clear_all_weakrefs()
+        self.close()
+
     def accept_w(self, space):
         """accept() -> (socket object, address info)
 

Modified: pypy/dist/pypy/module/_weakref/interp__weakref.py
==============================================================================
--- pypy/dist/pypy/module/_weakref/interp__weakref.py	(original)
+++ pypy/dist/pypy/module/_weakref/interp__weakref.py	Mon Jan 21 13:10:12 2008
@@ -8,7 +8,8 @@
 
 
 class WeakrefLifeline(object):
-    def __init__(self):
+    def __init__(self, space):
+        self.space = space       # this is here for W_Root.clear_all_weakrefs()
         self.refs_weak = []
         self.cached_weakref_index = -1
         self.cached_proxy_index = -1
@@ -145,7 +146,7 @@
 def descr__new__weakref(space, w_subtype, w_obj, w_callable=None):
     lifeline = w_obj.getweakref()
     if lifeline is None:
-        lifeline = WeakrefLifeline()
+        lifeline = WeakrefLifeline(space)
         w_obj.setweakref(space, lifeline)
     return lifeline.get_or_make_weakref(space, w_subtype, w_obj, w_callable)
 
@@ -218,7 +219,7 @@
 is about to be finalized."""
     lifeline = w_obj.getweakref()
     if lifeline is None:
-        lifeline = WeakrefLifeline()
+        lifeline = WeakrefLifeline(space)
         w_obj.setweakref(space, lifeline) 
     return lifeline.get_or_make_proxy(space, w_obj, w_callable)
 



More information about the Pypy-commit mailing list