GreenletExit not thrown when a greenlet is garbage-collected
Created originally on Bitbucket by antocuni (Antonio Cuni)
import greenlet import gc class A(object): def __del__(self): print 'A.__del__' def g1(): try: print 'g1: begin' a = A() print 'g1: switching' MAIN.switch() except greenlet.GreenletExit: print 'g1: GreenletExit' finally: print 'g1: finally' def main(): global MAIN MAIN = greenlet.getcurrent() greenlet.greenlet(g1).switch() gc.collect() main()
These are the results on CPython and PyPy;
A.__del__ is used just to show that the greenlet is actually garbage collected.
$ python green.py g1: begin g1: switching g1: GreenletExit g1: finally A.__del__ $ pypy green.py g1: begin g1: switching A.__del__
The following patch seems to be enough to fix the problem; however, since it’s a good practice to be very careful when dealing with greenlets and continuelets, I’d like some feeback before committing it:
diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py --- a/lib_pypy/greenlet.py +++ b/lib_pypy/greenlet.py @@ -47,6 +47,9 @@ if parent is not None: self.parent = parent + def __del__(self): + self.throw() + def switch(self, *args, **kwds): "Switch execution to this greenlet, optionally passing the values " "given as argument(s). Returns the value passed when switching back."