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