codekingpro/portable-devtools
114k
1import gc
2
3import weakref
4
5import greenlet
6
7
8from . import TestCase
9from .leakcheck import fails_leakcheck
10# These only work with greenlet gc support
11# which is no longer optional.
12assert greenlet.GREENLET_USE_GC
13
14class TestGC(TestCase):
15 def test_dead_circular_ref(self):
16 o = weakref.ref(greenlet.greenlet(greenlet.getcurrent).switch())
17 gc.collect()
18 if o() is not None:
19 import sys
20 print("O IS NOT NONE.", sys.getrefcount(o()))
21 self.assertIsNone(o())
22 self.assertFalse(gc.garbage, gc.garbage)
23
24 def test_circular_greenlet(self):
25 class circular_greenlet(greenlet.greenlet):
26 self = None
27 o = circular_greenlet()
28 o.self = o
29 o = weakref.ref(o)
30 gc.collect()
31 self.assertIsNone(o())
32 self.assertFalse(gc.garbage, gc.garbage)
33
34 def test_inactive_ref(self):
35 class inactive_greenlet(greenlet.greenlet):
36 def __init__(self):
37 greenlet.greenlet.__init__(self, run=self.run)
38
39 def run(self):
40 pass
41 o = inactive_greenlet()
42 o = weakref.ref(o)
43 gc.collect()
44 self.assertIsNone(o())
45 self.assertFalse(gc.garbage, gc.garbage)
46
47 @fails_leakcheck
48 def test_finalizer_crash(self):
49 # This test is designed to crash when active greenlets
50 # are made garbage collectable, until the underlying
51 # problem is resolved. How does it work:
52 # - order of object creation is important
53 # - array is created first, so it is moved to unreachable first
54 # - we create a cycle between a greenlet and this array
55 # - we create an object that participates in gc, is only
56 # referenced by a greenlet, and would corrupt gc lists
57 # on destruction, the easiest is to use an object with
58 # a finalizer
59 # - because array is the first object in unreachable it is
60 # cleared first, which causes all references to greenlet
61 # to disappear and causes greenlet to be destroyed, but since
62 # it is still live it causes a switch during gc, which causes
63 # an object with finalizer to be destroyed, which causes stack
64 # corruption and then a crash
65
66 class object_with_finalizer(object):
67 def __del__(self):
68 pass
69 array = []
70 parent = greenlet.getcurrent()
71 def greenlet_body():
72 greenlet.getcurrent().object = object_with_finalizer()
73 try:
74 parent.switch()
75 except greenlet.GreenletExit:
76 print("Got greenlet exit!")
77 finally:
78 del greenlet.getcurrent().object
79 g = greenlet.greenlet(greenlet_body)
80 g.array = array
81 array.append(g)
82 g.switch()
83 del array
84 del g
85 greenlet.getcurrent()
86 gc.collect()
87 