Skip to content

Commit 6f4de81

Browse files
itamarofacebook-github-bot
authored andcommitted
Backport gh-107803: Double linked list implementation for asyncio tasks
Summary: upstream issue: python/cpython#107803 backported commits: - python/cpython@4717aaa - python/cpython@8223544 Differential Revision: D59280319 fbshipit-source-id: 9fb14b7f5b6662ff5093ed27c56841b8de8c5a2c
1 parent e4cb62e commit 6f4de81

9 files changed

+382
-99
lines changed

Include/internal/pycore_global_objects_fini_generated.h

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_global_strings.h

+1
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,7 @@ struct _Py_global_strings {
387387
STRUCT_FOR_ID(displayhook)
388388
STRUCT_FOR_ID(dklen)
389389
STRUCT_FOR_ID(doc)
390+
STRUCT_FOR_ID(done)
390391
STRUCT_FOR_ID(dont_inherit)
391392
STRUCT_FOR_ID(dst)
392393
STRUCT_FOR_ID(dst_dir_fd)

Include/internal/pycore_object.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n)
126126
}
127127
#define _Py_RefcntAdd(op, n) _Py_RefcntAdd(_PyObject_CAST(op), n)
128128

129-
extern void _Py_SetImmortal(PyObject *op);
130-
extern void _Py_SetImmortalUntracked(PyObject *op);
129+
PyAPI_FUNC(void) _Py_SetImmortal(PyObject *op);
130+
PyAPI_FUNC(void) _Py_SetImmortalUntracked(PyObject *op);
131131

132132
// Makes an immortal object mortal again with the specified refcnt. Should only
133133
// be used during runtime finalization.

Include/internal/pycore_runtime_init_generated.h

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_unicodeobject_generated.h

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/asyncio/tasks.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -1097,14 +1097,14 @@ def _unregister_eager_task(task):
10971097
_py_enter_task = _enter_task
10981098
_py_leave_task = _leave_task
10991099
_py_swap_current_task = _swap_current_task
1100-
1100+
_py_all_tasks = all_tasks
11011101

11021102
try:
11031103
from _asyncio import (_register_task, _register_eager_task,
11041104
_unregister_task, _unregister_eager_task,
11051105
_enter_task, _leave_task, _swap_current_task,
11061106
_scheduled_tasks, _eager_tasks, _current_tasks,
1107-
current_task)
1107+
current_task, all_tasks)
11081108
except ImportError:
11091109
pass
11101110
else:
@@ -1116,3 +1116,4 @@ def _unregister_eager_task(task):
11161116
_c_enter_task = _enter_task
11171117
_c_leave_task = _leave_task
11181118
_c_swap_current_task = _swap_current_task
1119+
_c_all_tasks = all_tasks

Lib/test/test_asyncio/test_tasks.py

+23-11
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class BaseTaskTests:
8686

8787
Task = None
8888
Future = None
89+
all_tasks = None
8990

9091
def new_task(self, loop, coro, name='TestTask', context=None):
9192
return self.__class__.Task(coro, loop=loop, name=name, context=context)
@@ -2267,7 +2268,7 @@ async def kill_me(loop):
22672268
coro = kill_me(self.loop)
22682269
task = asyncio.ensure_future(coro, loop=self.loop)
22692270

2270-
self.assertEqual(asyncio.all_tasks(loop=self.loop), {task})
2271+
self.assertEqual(self.all_tasks(loop=self.loop), {task})
22712272

22722273
asyncio.set_event_loop(None)
22732274

@@ -2282,7 +2283,7 @@ async def kill_me(loop):
22822283
# no more reference to kill_me() task: the task is destroyed by the GC
22832284
support.gc_collect()
22842285

2285-
self.assertEqual(asyncio.all_tasks(loop=self.loop), set())
2286+
self.assertEqual(self.all_tasks(loop=self.loop), set())
22862287

22872288
mock_handler.assert_called_with(self.loop, {
22882289
'message': 'Task was destroyed but it is pending!',
@@ -2431,7 +2432,7 @@ async def coro():
24312432
message = m_log.error.call_args[0][0]
24322433
self.assertIn('Task was destroyed but it is pending', message)
24332434

2434-
self.assertEqual(asyncio.all_tasks(self.loop), set())
2435+
self.assertEqual(self.all_tasks(self.loop), set())
24352436

24362437
def test_create_task_with_noncoroutine(self):
24372438
with self.assertRaisesRegex(TypeError,
@@ -2731,6 +2732,7 @@ async def func():
27312732
# Add patched Task & Future back to the test case
27322733
cls.Task = Task
27332734
cls.Future = Future
2735+
cls.all_tasks = tasks.all_tasks
27342736

27352737
# Add an extra unit-test
27362738
cls.test_subclasses_ctask_cfuture = test_subclasses_ctask_cfuture
@@ -2804,6 +2806,7 @@ class CTask_CFuture_Tests(BaseTaskTests, SetMethodsTest,
28042806

28052807
Task = getattr(tasks, '_CTask', None)
28062808
Future = getattr(futures, '_CFuture', None)
2809+
all_tasks = getattr(tasks, '_c_all_tasks', None)
28072810

28082811
@support.refcount_test
28092812
def test_refleaks_in_task___init__(self):
@@ -2835,6 +2838,7 @@ class CTask_CFuture_SubclassTests(BaseTaskTests, test_utils.TestCase):
28352838

28362839
Task = getattr(tasks, '_CTask', None)
28372840
Future = getattr(futures, '_CFuture', None)
2841+
all_tasks = getattr(tasks, '_c_all_tasks', None)
28382842

28392843

28402844
@unittest.skipUnless(hasattr(tasks, '_CTask'),
@@ -2844,6 +2848,7 @@ class CTaskSubclass_PyFuture_Tests(BaseTaskTests, test_utils.TestCase):
28442848

28452849
Task = getattr(tasks, '_CTask', None)
28462850
Future = futures._PyFuture
2851+
all_tasks = getattr(tasks, '_c_all_tasks', None)
28472852

28482853

28492854
@unittest.skipUnless(hasattr(futures, '_CFuture'),
@@ -2853,6 +2858,7 @@ class PyTask_CFutureSubclass_Tests(BaseTaskTests, test_utils.TestCase):
28532858

28542859
Future = getattr(futures, '_CFuture', None)
28552860
Task = tasks._PyTask
2861+
all_tasks = tasks._py_all_tasks
28562862

28572863

28582864
@unittest.skipUnless(hasattr(tasks, '_CTask'),
@@ -2861,6 +2867,7 @@ class CTask_PyFuture_Tests(BaseTaskTests, test_utils.TestCase):
28612867

28622868
Task = getattr(tasks, '_CTask', None)
28632869
Future = futures._PyFuture
2870+
all_tasks = getattr(tasks, '_c_all_tasks', None)
28642871

28652872

28662873
@unittest.skipUnless(hasattr(futures, '_CFuture'),
@@ -2869,13 +2876,15 @@ class PyTask_CFuture_Tests(BaseTaskTests, test_utils.TestCase):
28692876

28702877
Task = tasks._PyTask
28712878
Future = getattr(futures, '_CFuture', None)
2879+
all_tasks = staticmethod(tasks._py_all_tasks)
28722880

28732881

28742882
class PyTask_PyFuture_Tests(BaseTaskTests, SetMethodsTest,
28752883
test_utils.TestCase):
28762884

28772885
Task = tasks._PyTask
28782886
Future = futures._PyFuture
2887+
all_tasks = staticmethod(tasks._py_all_tasks)
28792888

28802889

28812890
@add_subclass_tests
@@ -2915,6 +2924,7 @@ class BaseTaskIntrospectionTests:
29152924
_unregister_task = None
29162925
_enter_task = None
29172926
_leave_task = None
2927+
all_tasks = None
29182928

29192929
def test__register_task_1(self):
29202930
class TaskLike:
@@ -2928,9 +2938,9 @@ def done(self):
29282938
task = TaskLike()
29292939
loop = mock.Mock()
29302940

2931-
self.assertEqual(asyncio.all_tasks(loop), set())
2941+
self.assertEqual(self.all_tasks(loop), set())
29322942
self._register_task(task)
2933-
self.assertEqual(asyncio.all_tasks(loop), {task})
2943+
self.assertEqual(self.all_tasks(loop), {task})
29342944
self._unregister_task(task)
29352945

29362946
def test__register_task_2(self):
@@ -2944,9 +2954,9 @@ def done(self):
29442954
task = TaskLike()
29452955
loop = mock.Mock()
29462956

2947-
self.assertEqual(asyncio.all_tasks(loop), set())
2957+
self.assertEqual(self.all_tasks(loop), set())
29482958
self._register_task(task)
2949-
self.assertEqual(asyncio.all_tasks(loop), {task})
2959+
self.assertEqual(self.all_tasks(loop), {task})
29502960
self._unregister_task(task)
29512961

29522962
def test__register_task_3(self):
@@ -2960,9 +2970,9 @@ def done(self):
29602970
task = TaskLike()
29612971
loop = mock.Mock()
29622972

2963-
self.assertEqual(asyncio.all_tasks(loop), set())
2973+
self.assertEqual(self.all_tasks(loop), set())
29642974
self._register_task(task)
2965-
self.assertEqual(asyncio.all_tasks(loop), set())
2975+
self.assertEqual(self.all_tasks(loop), set())
29662976
self._unregister_task(task)
29672977

29682978
def test__enter_task(self):
@@ -3013,20 +3023,21 @@ def test__unregister_task(self):
30133023
task.get_loop = lambda: loop
30143024
self._register_task(task)
30153025
self._unregister_task(task)
3016-
self.assertEqual(asyncio.all_tasks(loop), set())
3026+
self.assertEqual(self.all_tasks(loop), set())
30173027

30183028
def test__unregister_task_not_registered(self):
30193029
task = mock.Mock()
30203030
loop = mock.Mock()
30213031
self._unregister_task(task)
3022-
self.assertEqual(asyncio.all_tasks(loop), set())
3032+
self.assertEqual(self.all_tasks(loop), set())
30233033

30243034

30253035
class PyIntrospectionTests(test_utils.TestCase, BaseTaskIntrospectionTests):
30263036
_register_task = staticmethod(tasks._py_register_task)
30273037
_unregister_task = staticmethod(tasks._py_unregister_task)
30283038
_enter_task = staticmethod(tasks._py_enter_task)
30293039
_leave_task = staticmethod(tasks._py_leave_task)
3040+
all_tasks = staticmethod(tasks._py_all_tasks)
30303041

30313042

30323043
@unittest.skipUnless(hasattr(tasks, '_c_register_task'),
@@ -3037,6 +3048,7 @@ class CIntrospectionTests(test_utils.TestCase, BaseTaskIntrospectionTests):
30373048
_unregister_task = staticmethod(tasks._c_unregister_task)
30383049
_enter_task = staticmethod(tasks._c_enter_task)
30393050
_leave_task = staticmethod(tasks._c_leave_task)
3051+
all_tasks = staticmethod(tasks._c_all_tasks)
30403052
else:
30413053
_register_task = _unregister_task = _enter_task = _leave_task = None
30423054

0 commit comments

Comments
 (0)