1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- import gc
- import sys
- import unittest
- import weakref
- import greenlet
- class GCTests(unittest.TestCase):
- def test_dead_circular_ref(self):
- o = weakref.ref(greenlet.greenlet(greenlet.getcurrent).switch())
- gc.collect()
- self.assertTrue(o() is None)
- self.assertFalse(gc.garbage, gc.garbage)
- if greenlet.GREENLET_USE_GC:
- # These only work with greenlet gc support
- def test_circular_greenlet(self):
- class circular_greenlet(greenlet.greenlet):
- pass
- o = circular_greenlet()
- o.self = o
- o = weakref.ref(o)
- gc.collect()
- self.assertTrue(o() is None)
- self.assertFalse(gc.garbage, gc.garbage)
- def test_inactive_ref(self):
- class inactive_greenlet(greenlet.greenlet):
- def __init__(self):
- greenlet.greenlet.__init__(self, run=self.run)
- def run(self):
- pass
- o = inactive_greenlet()
- o = weakref.ref(o)
- gc.collect()
- self.assertTrue(o() is None)
- self.assertFalse(gc.garbage, gc.garbage)
- def test_finalizer_crash(self):
- # This test is designed to crash when active greenlets
- # are made garbage collectable, until the underlying
- # problem is resolved. How does it work:
- # - order of object creation is important
- # - array is created first, so it is moved to unreachable first
- # - we create a cycle between a greenlet and this array
- # - we create an object that participates in gc, is only
- # referenced by a greenlet, and would corrupt gc lists
- # on destruction, the easiest is to use an object with
- # a finalizer
- # - because array is the first object in unreachable it is
- # cleared first, which causes all references to greenlet
- # to disappear and causes greenlet to be destroyed, but since
- # it is still live it causes a switch during gc, which causes
- # an object with finalizer to be destroyed, which causes stack
- # corruption and then a crash
- class object_with_finalizer(object):
- def __del__(self):
- pass
- array = []
- parent = greenlet.getcurrent()
- def greenlet_body():
- greenlet.getcurrent().object = object_with_finalizer()
- try:
- parent.switch()
- finally:
- del greenlet.getcurrent().object
- g = greenlet.greenlet(greenlet_body)
- g.array = array
- array.append(g)
- g.switch()
- del array
- del g
- greenlet.getcurrent()
- gc.collect()
|