summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2017-08-20 23:33:06 +0200
committerStefan Behnel <stefan_ml@behnel.de>2017-08-20 23:33:06 +0200
commite0c94ef2d98b2c5193d152fa2603de782dcb9d58 (patch)
treecdc1bffc45d0a1248bdcbbe4408aa86b8ba5ba0b
parent69f3183a3357086a4c443c77c7e49ba99d29fd3c (diff)
downloadcython-e0c94ef2d98b2c5193d152fa2603de782dcb9d58.tar.gz
Keep direct closure of generators and coroutines intact during cleanup by disabling their tp_clear() as they still need their closure for handling the final GeneratorExit call.
-rw-r--r--Cython/Compiler/ParseTreeTransforms.py3
-rw-r--r--tests/run/generator_frame_cycle.py7
2 files changed, 10 insertions, 0 deletions
diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py
index aee77f81d..4edaf0923 100644
--- a/Cython/Compiler/ParseTreeTransforms.py
+++ b/Cython/Compiler/ParseTreeTransforms.py
@@ -2660,6 +2660,9 @@ class CreateClosureClasses(CythonTransform):
class_scope = entry.type.scope
class_scope.is_internal = True
class_scope.is_closure_class_scope = True
+ if node.is_async_def or node.is_generator:
+ # Generators need their closure intact during cleanup as they resume to handle GeneratorExit
+ class_scope.directives['no_gc_clear'] = True
if Options.closure_freelist_size:
class_scope.directives['freelist'] = Options.closure_freelist_size
diff --git a/tests/run/generator_frame_cycle.py b/tests/run/generator_frame_cycle.py
index d912ff9cc..3789d4c8d 100644
--- a/tests/run/generator_frame_cycle.py
+++ b/tests/run/generator_frame_cycle.py
@@ -1,6 +1,7 @@
# mode: run
# tag: generator
+import cython
import sys
@@ -24,6 +25,9 @@ def test_generator_frame_cycle():
eval('g.throw(ValueError)', {'g': g})
del g
+ if cython.compiled:
+ # FIXME: this should not be necessary, but I can't see how to do it...
+ import gc; gc.collect()
return tuple(testit)
@@ -53,4 +57,7 @@ def test_generator_frame_cycle_with_outer_exc():
del g
assert sys.exc_info()[1] is exc, sys.exc_info()
+ if cython.compiled:
+ # FIXME: this should not be necessary, but I can't see how to do it...
+ import gc; gc.collect()
return tuple(testit)