Skip to content

Commit

Permalink
Stackless issue python#190: Do not close running (async) generators o…
Browse files Browse the repository at this point in the history
…r coroutines (python#195)

Silently ignore attempts to close a running generator, coroutine or asynchronous
generator. This avoids spurious error messages, if such an object is deallocated
as part of a paused, restorable tasklet.
(cherry picked from commit 905d0ef)
  • Loading branch information
Anselm Kruis authored and Anselm Kruis committed Jan 19, 2019
1 parent 427c5a0 commit f2fa3aa
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 1 deletion.
9 changes: 9 additions & 0 deletions Objects/genobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,15 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
PyFrameObject *f = gen->gi_frame;
PyObject *result;

#ifdef STACKLESS
if (gen->gi_running && exc && closing) {
/*
* Do not close a running generator.
* See Stackless issue 190.
*/
return NULL;
}
#endif
if (gen->gi_running) {
char *msg = "generator already executing";
if (PyCoro_CheckExact(gen)) {
Expand Down
5 changes: 5 additions & 0 deletions Stackless/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ What's New in Stackless 3.X.X?

*Release date: 20XX-XX-XX*

- https://github.com/stackless-dev/stackless/issues/190
Silently ignore attempts to close a running generator, coroutine or
asynchronous generator. This avoids spurious error messages, if such an
object is deallocated as part of a paused, restorable tasklet.

- https://github.com/stackless-dev/stackless/issues/206
Fix the error handling of the Python implementation of function-object
pickling.
Expand Down
71 changes: 70 additions & 1 deletion Stackless/unittests/test_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import types
import pickle
import copyreg
import sys

from support import test_main # @UnusedImport
from support import StacklessTestCase
from support import StacklessTestCase, captured_stderr


def f():
Expand Down Expand Up @@ -36,6 +37,74 @@ def testSimpleLeakage(self):
if len(leakage):
self.failUnless(len(leakage) == 0, "Leaked %s" % repr(leakage))

def run_GC_test(self, task, arg):
tasklet = stackless.tasklet(task)(arg)
tasklet.run()
if False: # To test the generator / coroutine / async gen
tasklet.run()
self.assertFalse(tasklet.alive)
return
self.assertTrue(tasklet.paused)
tasklet.tempval = None
with captured_stderr() as stringio:
# must not throw or output
if tasklet.restorable:
tasklet.bind(None)
# make sure, that t=None kills the last reference
self.assertEqual(sys.getrefcount(tasklet), 2)
tasklet = None
self.assertEqual(stringio.getvalue(), "")

def testGCRunningGenerator(self):
def gen():
try:
# print("gen nesting level: ", stackless.current.nesting_level)
stackless.schedule_remove()
yield 1
except: # @IgnorePep8
# print("exception in gen:", sys.exc_info())
raise

def task(generator):
l = [i for i in generator]
self.assertListEqual(l, [1])

self.run_GC_test(task,gen())

def testGCRunningCoroutine(self):
async def coro():
try:
# print("coro nesting level: ", stackless.current.nesting_level)
stackless.schedule_remove()
except: # @IgnorePep8
# print("exception in coro:", sys.exc_info())
raise

def task(c):
self.assertRaises(StopIteration, c.send, None)

self.run_GC_test(task, coro())

def testGCRunningAsyncGen(self):
async def asyncgen():
try:
# print("asyncgen nesting level: ", stackless.current.nesting_level)
stackless.schedule_remove()
except: # @IgnorePep8
# print("exception in asyncgen:", sys.exc_info())
raise
yield 100

def task(ag):
c = ag.__anext__()
with self.assertRaises(StopIteration) as cm:
c.send(None)
self.assertEqual(cm.exception.value, 100)
c = ag.__anext__()
self.assertRaises(StopAsyncIteration, c.send, None)

self.run_GC_test(task, asyncgen())


class TestGeneratorWrapper(StacklessTestCase):
def test_run_wrap_generator(self):
Expand Down

0 comments on commit f2fa3aa

Please sign in to comment.