2
2
import ctypes .util
3
3
import logging
4
4
from concurrent .futures import ThreadPoolExecutor
5
+ from threading import Thread
5
6
from unittest import TestCase
6
7
7
8
import uvloop
@@ -44,12 +45,32 @@ async def spawn_external_process(loop, event):
44
45
executor = ThreadPoolExecutor ()
45
46
try :
46
47
call = loop .run_in_executor (executor , spawn_process )
47
- await asyncio .wait_for (call , loop = loop , timeout = 160 )
48
+ await asyncio .wait_for (call , loop = loop , timeout = 3600 )
48
49
finally :
49
50
event .set ()
50
51
executor .shutdown (wait = False )
51
52
return True
52
53
54
+ BUFFER_LENGTH = 1025
55
+ BufferType = ctypes .c_char * (BUFFER_LENGTH - 1 )
56
+
57
+ def run_echo (popen , fread , pclose ):
58
+ fd = popen ('echo test' .encode ('ASCII' ), 'r' .encode ('ASCII' ))
59
+ try :
60
+ while True :
61
+ buffer = BufferType ()
62
+ data = ctypes .c_void_p (ctypes .addressof (buffer ))
63
+
64
+ # -> this call will freeze whole loop in case of bug
65
+ read = fread (data , 1 , BUFFER_LENGTH , fd )
66
+ if not read :
67
+ break
68
+ except Exception :
69
+ logging .getLogger ().exception ('read error' )
70
+ raise
71
+ finally :
72
+ pclose (fd )
73
+
53
74
def spawn_process ():
54
75
"""Spawn external process via `popen` system call."""
55
76
@@ -71,25 +92,15 @@ def spawn_process():
71
92
ctypes .c_size_t , ctypes .c_void_p )
72
93
fread .restype = ctypes .c_size_t
73
94
74
- BUFFER_LENGTH = 1025
75
- BufferType = ctypes .c_char * (BUFFER_LENGTH - 1 )
76
-
77
- for _ in range (10000 ):
78
- fd = popen ('echo test' .encode ('ASCII' ), 'r' .encode ('ASCII' ))
79
- try :
80
- while True :
81
- buffer = BufferType ()
82
- data = ctypes .c_void_p (ctypes .addressof (buffer ))
83
-
84
- # -> this call will freeze whole loop in case of bug
85
- read = fread (data , 1 , BUFFER_LENGTH , fd )
86
- if not read :
87
- break
88
- except Exception :
89
- logging .getLogger ().exception ('read error' )
90
- raise
91
- finally :
92
- pclose (fd )
95
+ for iteration in range (10000 ):
96
+ t = Thread (target = run_echo ,
97
+ args = (popen , fread , pclose ),
98
+ daemon = True )
99
+ t .start ()
100
+ t .join (timeout = 20.0 )
101
+ if t .is_alive ():
102
+ raise Exception ('process freeze detected at {}'
103
+ .format (iteration ))
93
104
94
105
return True
95
106
0 commit comments