@@ -42,9 +42,22 @@ def all_tasks(loop=None):
42
42
"""Return a set of all tasks for the loop."""
43
43
if loop is None :
44
44
loop = events .get_running_loop ()
45
- # NB: set(_all_tasks) is required to protect
46
- # from https://bugs.python.org/issue34970 bug
47
- return {t for t in list (_all_tasks )
45
+ # Looping over a WeakSet (_all_tasks) isn't safe as it can be updated from another
46
+ # thread while we do so. Therefore we cast it to list prior to filtering. The list
47
+ # cast itself requires iteration, so we repeat it several times ignoring
48
+ # RuntimeErrors (which are not very likely to occur). See issues 34970 and 36607 for
49
+ # details.
50
+ i = 0
51
+ while True :
52
+ try :
53
+ tasks = list (_all_tasks )
54
+ except RuntimeError :
55
+ i += 1
56
+ if i >= 1000 :
57
+ raise
58
+ else :
59
+ break
60
+ return {t for t in tasks
48
61
if futures ._get_loop (t ) is loop and not t .done ()}
49
62
50
63
@@ -54,9 +67,22 @@ def _all_tasks_compat(loop=None):
54
67
# method.
55
68
if loop is None :
56
69
loop = events .get_event_loop ()
57
- # NB: set(_all_tasks) is required to protect
58
- # from https://bugs.python.org/issue34970 bug
59
- return {t for t in list (_all_tasks ) if futures ._get_loop (t ) is loop }
70
+ # Looping over a WeakSet (_all_tasks) isn't safe as it can be updated from another
71
+ # thread while we do so. Therefore we cast it to list prior to filtering. The list
72
+ # cast itself requires iteration, so we repeat it several times ignoring
73
+ # RuntimeErrors (which are not very likely to occur). See issues 34970 and 36607 for
74
+ # details.
75
+ i = 0
76
+ while True :
77
+ try :
78
+ tasks = list (_all_tasks )
79
+ except RuntimeError :
80
+ i += 1
81
+ if i >= 1000 :
82
+ raise
83
+ else :
84
+ break
85
+ return {t for t in tasks if futures ._get_loop (t ) is loop }
60
86
61
87
62
88
def _set_task_name (task , name ):
0 commit comments