Skip to content

Commit

Permalink
Merge pull request #759 from online-judge-tools/fix/kill-zombies-again
Browse files Browse the repository at this point in the history
Kill processes when Ctrl-C is pressed
  • Loading branch information
kmyk authored May 4, 2020
2 parents 99963a5 + 17d0870 commit 010d00d
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 2 deletions.
7 changes: 6 additions & 1 deletion onlinejudge_command/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,13 @@ def exec_command(command_str: str, *, stdin: Optional[IO[Any]] = None, input: Op
try:
answer, _ = proc.communicate(input=input, timeout=timeout)
except subprocess.TimeoutExpired:
pass
finally:
if preexec_fn is not None:
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
try:
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
except ProcessLookupError:
pass
else:
proc.terminate()

Expand Down
33 changes: 32 additions & 1 deletion tests/command_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import pathlib
import random
import shutil
import signal
import sys
import threading
import unittest

import tests.utils
Expand Down Expand Up @@ -1011,7 +1013,7 @@ def test_call_output_uses_both_lf_and_crlf(self):
)

@unittest.skipIf(os.name == 'nt', "procfs is required")
def test_call_test_check_no_zombie(self):
def test_call_test_check_no_zombie_with_tle(self):
marker = 'zombie-%08x' % random.randrange(2**32)
data = self.snippet_call_test(
args=['-c', tests.utils.python_c("import time; time.sleep(100) # {}".format(marker)), '--tle', '1'],
Expand Down Expand Up @@ -1048,6 +1050,35 @@ def test_call_test_check_no_zombie(self):
with open(str(cmdline), 'rb') as fh:
self.assertNotIn(marker.encode(), fh.read())

@unittest.skipIf(os.name == 'nt', "procfs is required")
def test_call_test_check_no_zombie_with_keyboard_interrupt(self):
marker_for_callee = 'zombie-%08x' % random.randrange(2**32)
marker_for_caller = 'zombie-%08x' % random.randrange(2**32)
files = [
{
'path': 'test/{}-1.in'.format(marker_for_caller),
'data': 'foo\n'
},
]

def send_keyboard_interrupt():
for cmdline in pathlib.Path('/proc').glob('*/cmdline'):
with open(str(cmdline), 'rb') as fh:
if marker_for_caller.encode() in fh.read():
pid = int(cmdline.parts[2])
print('sending Ctrl-C to', pid)
os.kill(pid, signal.SIGINT)

timer = threading.Timer(1.0, send_keyboard_interrupt)
timer.start()
result = tests.utils.run_in_sandbox(args=['-v', 'test', '-c', tests.utils.python_c("import time; time.sleep(10) # {}".format(marker_for_callee)), 'test/{}-1.in'.format(marker_for_caller)], files=files)
self.assertNotEqual(result['proc'].returncode, 0)

# check there are no processes whose command-line arguments contains the marker word
for cmdline in pathlib.Path('/proc').glob('*/cmdline'):
with open(str(cmdline), 'rb') as fh:
self.assertNotIn(marker_for_callee.encode(), fh.read())


@unittest.skipIf(os.name == 'nt', "memory checking is disabled and output is different with Linux")
class TestTestLog(unittest.TestCase):
Expand Down

0 comments on commit 010d00d

Please sign in to comment.