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