[3.6] bpo-34769: Thread safety for _asyncgen_finalizer_hook(). (GH-97… · python/cpython@a14dda5 (original) (raw)
`@@ -915,6 +915,74 @@ def test_run_forever_pre_stopped(self):
`
915
915
`self.loop.run_forever()
`
916
916
`self.loop._selector.select.assert_called_once_with(0)
`
917
917
``
``
918
`+
async def leave_unfinalized_asyncgen(self):
`
``
919
`+
Create an async generator, iterate it partially, and leave it
`
``
920
`+
to be garbage collected.
`
``
921
`+
Used in async generator finalization tests.
`
``
922
`+
Depends on implementation details of garbage collector. Changes
`
``
923
`+
in gc may break this function.
`
``
924
`+
status = {'started': False,
`
``
925
`+
'stopped': False,
`
``
926
`+
'finalized': False}
`
``
927
+
``
928
`+
async def agen():
`
``
929
`+
status['started'] = True
`
``
930
`+
try:
`
``
931
`+
for item in ['ZERO', 'ONE', 'TWO', 'THREE', 'FOUR']:
`
``
932
`+
yield item
`
``
933
`+
finally:
`
``
934
`+
status['finalized'] = True
`
``
935
+
``
936
`+
ag = agen()
`
``
937
`+
ai = ag.aiter()
`
``
938
+
``
939
`+
async def iter_one():
`
``
940
`+
try:
`
``
941
`+
item = await ai.anext()
`
``
942
`+
except StopAsyncIteration:
`
``
943
`+
return
`
``
944
`+
if item == 'THREE':
`
``
945
`+
status['stopped'] = True
`
``
946
`+
return
`
``
947
`+
self.loop.create_task(iter_one())
`
``
948
+
``
949
`+
self.loop.create_task(iter_one())
`
``
950
`+
return status
`
``
951
+
``
952
`+
def test_asyncgen_finalization_by_gc(self):
`
``
953
`+
Async generators should be finalized when garbage collected.
`
``
954
`+
self.loop._process_events = mock.Mock()
`
``
955
`+
self.loop._write_to_self = mock.Mock()
`
``
956
`+
with support.disable_gc():
`
``
957
`+
status = self.loop.run_until_complete(self.leave_unfinalized_asyncgen())
`
``
958
`+
while not status['stopped']:
`
``
959
`+
test_utils.run_briefly(self.loop)
`
``
960
`+
self.assertTrue(status['started'])
`
``
961
`+
self.assertTrue(status['stopped'])
`
``
962
`+
self.assertFalse(status['finalized'])
`
``
963
`+
support.gc_collect()
`
``
964
`+
test_utils.run_briefly(self.loop)
`
``
965
`+
self.assertTrue(status['finalized'])
`
``
966
+
``
967
`+
def test_asyncgen_finalization_by_gc_in_other_thread(self):
`
``
968
`+
Python issue 34769: If garbage collector runs in another
`
``
969
`+
thread, async generators will not finalize in debug
`
``
970
`+
mode.
`
``
971
`+
self.loop._process_events = mock.Mock()
`
``
972
`+
self.loop._write_to_self = mock.Mock()
`
``
973
`+
self.loop.set_debug(True)
`
``
974
`+
with support.disable_gc():
`
``
975
`+
status = self.loop.run_until_complete(self.leave_unfinalized_asyncgen())
`
``
976
`+
while not status['stopped']:
`
``
977
`+
test_utils.run_briefly(self.loop)
`
``
978
`+
self.assertTrue(status['started'])
`
``
979
`+
self.assertTrue(status['stopped'])
`
``
980
`+
self.assertFalse(status['finalized'])
`
``
981
`+
self.loop.run_until_complete(
`
``
982
`+
self.loop.run_in_executor(None, support.gc_collect))
`
``
983
`+
test_utils.run_briefly(self.loop)
`
``
984
`+
self.assertTrue(status['finalized'])
`
``
985
+
918
986
``
919
987
`class MyProto(asyncio.Protocol):
`
920
988
`done = None
`