Skip to content

Commit 20da5a0

Browse files
committed
improve freeze detection by removing global processing time assumption
1 parent 9de63b4 commit 20da5a0

File tree

1 file changed

+31
-20
lines changed

1 file changed

+31
-20
lines changed

tests/test_process_spawning.py

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import ctypes.util
33
import logging
44
from concurrent.futures import ThreadPoolExecutor
5+
from threading import Thread
56
from unittest import TestCase
67

78
import uvloop
@@ -44,12 +45,32 @@ async def spawn_external_process(loop, event):
4445
executor = ThreadPoolExecutor()
4546
try:
4647
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)
4849
finally:
4950
event.set()
5051
executor.shutdown(wait=False)
5152
return True
5253

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+
5374
def spawn_process():
5475
"""Spawn external process via `popen` system call."""
5576

@@ -71,25 +92,15 @@ def spawn_process():
7192
ctypes.c_size_t, ctypes.c_void_p)
7293
fread.restype = ctypes.c_size_t
7394

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))
93104

94105
return True
95106

0 commit comments

Comments
 (0)