Skip to content

Commit

Permalink
Use a simpler and more straightforward method to terminate the proces…
Browse files Browse the repository at this point in the history
…s tree
  • Loading branch information
weilycoder committed Dec 9, 2024
1 parent f314965 commit a459de9
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 58 deletions.
31 changes: 13 additions & 18 deletions cyaron/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
from __future__ import absolute_import
import os
import re
import signal
import subprocess
import tempfile
import psutil
from typing import Union, overload, Optional, List
from typing import Union, overload, Optional, List, cast
from io import IOBase
from . import log
from .utils import list_like, make_unicode
Expand Down Expand Up @@ -91,6 +91,7 @@ def __init__( # type: ignore
# if the dir "./io" not found it will be created
"""
self.__closed = False
self.input_file = cast(IOBase, None)
self.output_file = None
if file_prefix is not None:
# legacy mode
Expand Down Expand Up @@ -230,20 +231,13 @@ def __clear(self, file: IOBase, pos: int = 0):
file.seek(pos)

@staticmethod
def _kill_process_and_children(pid: int):
try:
parent = psutil.Process(pid)
while True:
children = parent.children()
if not children:
break
for child in children:
IO._kill_process_and_children(child.pid)
parent.kill()
except psutil.NoSuchProcess:
pass
except psutil.AccessDenied:
pass
def _kill_process_and_children(proc: subprocess.Popen):
if os.name == "posix":
os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
elif os.name == "nt":
os.system(f"TASKKILL /F /T /PID {proc.pid} > nul")
else:
proc.kill() # Not currently supported

def input_write(self, *args, **kwargs):
"""
Expand Down Expand Up @@ -304,13 +298,14 @@ def output_gen(self,
stdin=self.input_file.fileno(),
stdout=subprocess.PIPE,
universal_newlines=replace_EOL,
preexec_fn=os.setsid if os.name == "posix" else None,
)

try:
output, _ = proc.communicate(timeout=time_limit)
except subprocess.TimeoutExpired:
# proc.kill() # didn't work because `shell=True`.
self._kill_process_and_children(proc.pid)
# proc.kill() # didn't work because `shell=True`.
self._kill_process_and_children(proc)
raise
else:
if replace_EOL:
Expand Down
13 changes: 6 additions & 7 deletions cyaron/tests/io_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,12 @@ def test_output_gen(self):

def test_output_gen_time_limit_exceeded(self):
with captured_output():
TIMEOUT = 0.02
WAIT_TIME = 0.4 # If the wait time is too short, an error may occur
with open("long_time.py", "w", encoding="utf-8") as f:
f.write("import time, os\n"
"fn = input()\n"
"time.sleep(0.1)\n"
f"time.sleep({WAIT_TIME})\n"
"os.remove(fn)\n")

with IO("test_gen.in", "test_gen.out") as test:
Expand All @@ -89,8 +91,8 @@ def test_output_gen_time_limit_exceeded(self):
with self.assertRaises(subprocess.TimeoutExpired):
test.input_writeln(abs_input_filename)
test.output_gen(f'"{sys.executable}" long_time.py',
time_limit=0.05)
time.sleep(0.1)
time_limit=TIMEOUT)
time.sleep(WAIT_TIME)
try:
os.remove(input_filename)
except FileNotFoundError:
Expand Down Expand Up @@ -133,10 +135,7 @@ def test_make_dirs(self):

mkdir_false = False
try:
with IO(
"./automkdir_false/data.in",
"./automkdir_false/data.out",
):
with IO("./automkdir_false/data.in", "./automkdir_false/data.out"):
pass
except FileNotFoundError:
mkdir_false = True
Expand Down
32 changes: 1 addition & 31 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ readme = "README.md"
python = ">=3.6"
xeger = "^0.4.0"
colorful = "^0.5.6"
psutil = "^6.1.0"


[build-system]
Expand Down
1 change: 0 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ isolated_build = true
deps =
xeger
colorful
psutil
commands = python unit_test.py
allowlist_externals = poetry

0 comments on commit a459de9

Please sign in to comment.