Skip to content

Commit cf48318

Browse files
Properly kill all the whole process group and don't block on normal exit indefinitely if children hold pipe
1 parent 8f4af66 commit cf48318

2 files changed

Lines changed: 20 additions & 6 deletions

File tree

plain2code.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
from tui.plain2code_tui import Plain2CodeTUI
5353

5454
DEFAULT_TEMPLATE_DIRS = importlib.resources.files("standard_template_library")
55-
RENDER_THREAD_SHUTDOWN_TIMEOUT = 0.3
55+
RENDER_THREAD_SHUTDOWN_TIMEOUT = 0.7
5656

5757

5858
def get_render_range(render_range, plain_source):

render_machine/render_utils.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515

1616
SCRIPT_EXECUTION_TIMEOUT = 120
1717
TIMEOUT_ERROR_EXIT_CODE = 124
18+
POLL_INTERVAL_SECONDS = 0.2
19+
SIGTERM_GRACE_PERIOD_SECONDS = 0.2
20+
STDOUT_READ_TIMEOUT_SECONDS = 5
1821

1922

2023
def revert_changes_for_frid(render_context):
@@ -56,9 +59,15 @@ def _kill_process(proc: subprocess.Popen) -> None:
5659
else:
5760
proc.terminate()
5861
try:
59-
proc.wait(timeout=5)
62+
proc.wait(timeout=SIGTERM_GRACE_PERIOD_SECONDS)
6063
except subprocess.TimeoutExpired:
61-
proc.kill()
64+
if sys.platform != "win32":
65+
try:
66+
os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
67+
except OSError:
68+
proc.kill()
69+
else:
70+
proc.kill()
6271

6372

6473
def execute_script( # noqa: C901
@@ -100,14 +109,19 @@ def execute_script( # noqa: C901
100109
exc.stdout = partial_stdout
101110
raise exc
102111
if stop_event is not None:
103-
stop_event.wait(timeout=0.2)
112+
stop_event.wait(timeout=POLL_INTERVAL_SECONDS)
104113
if stop_event.is_set():
105114
_kill_process(proc)
106115
raise RenderCancelledError()
107116
else:
108-
time.sleep(0.2)
117+
time.sleep(POLL_INTERVAL_SECONDS)
109118

110-
stdout = proc.stdout.read()
119+
# Use communicate() with a timeout because child processes may hold the pipe open after the main process exits.
120+
try:
121+
stdout, _ = proc.communicate(timeout=STDOUT_READ_TIMEOUT_SECONDS)
122+
except subprocess.TimeoutExpired:
123+
proc.stdout.close()
124+
stdout = ""
111125
elapsed_time = time.time() - start_time
112126

113127
# Log the info about the script execution

0 commit comments

Comments
 (0)