diff options
author | Prabhu Ramachandran | 2017-04-27 17:28:44 +0530 |
---|---|---|
committer | GitHub | 2017-04-27 17:28:44 +0530 |
commit | a67f8597da19527669b596fab08083a18c7e1fcc (patch) | |
tree | 26484d05a23223df13aabb42fe674ce759e09187 | |
parent | ea9e60c47b763515b324aa507da06a1e91c488c6 (diff) | |
parent | 4a8f9a117f6a784fe722b8b381368c41be86024a (diff) | |
download | online_test-a67f8597da19527669b596fab08083a18c7e1fcc.tar.gz online_test-a67f8597da19527669b596fab08083a18c7e1fcc.tar.bz2 online_test-a67f8597da19527669b596fab08083a18c7e1fcc.zip |
Merge pull request #274 from maheshgudi/kill_stray_processes
Kill stray processes
-rw-r--r-- | requirements/requirements-common.txt | 1 | ||||
-rw-r--r-- | yaksh/base_evaluator.py | 5 | ||||
-rw-r--r-- | yaksh/bash_stdio_evaluator.py | 3 | ||||
-rw-r--r-- | yaksh/cpp_stdio_evaluator.py | 3 | ||||
-rw-r--r-- | yaksh/evaluator_tests/test_bash_evaluation.py | 10 | ||||
-rw-r--r-- | yaksh/evaluator_tests/test_c_cpp_evaluation.py | 13 | ||||
-rw-r--r-- | yaksh/evaluator_tests/test_java_evaluation.py | 16 | ||||
-rw-r--r-- | yaksh/evaluator_tests/test_scilab_evaluation.py | 9 | ||||
-rw-r--r-- | yaksh/hook_evaluator.py | 6 | ||||
-rw-r--r-- | yaksh/java_stdio_evaluator.py | 3 | ||||
-rw-r--r-- | yaksh/stdio_evaluator.py | 13 |
11 files changed, 72 insertions, 10 deletions
diff --git a/requirements/requirements-common.txt b/requirements/requirements-common.txt index e04c5bd..53a44a4 100644 --- a/requirements/requirements-common.txt +++ b/requirements/requirements-common.txt @@ -5,3 +5,4 @@ python-social-auth==0.2.19 tornado selenium==2.53.6 coverage +psutil diff --git a/yaksh/base_evaluator.py b/yaksh/base_evaluator.py index 071008f..e702f68 100644 --- a/yaksh/base_evaluator.py +++ b/yaksh/base_evaluator.py @@ -7,6 +7,7 @@ from os.path import join, isfile from os.path import isdir, dirname, abspath, join, isfile, exists import subprocess import stat +import signal # Local imports @@ -30,11 +31,11 @@ class BaseEvaluator(object): stdout and stderr. """ try: - proc = subprocess.Popen(cmd_args, *args, **kw) + proc = subprocess.Popen(cmd_args,preexec_fn=os.setpgrp, *args, **kw) stdout, stderr = proc.communicate() except TimeoutException: # Runaway code, so kill it. - proc.kill() + os.killpg(os.getpgid(proc.pid), signal.SIGKILL) # Re-raise exception. raise return proc, stdout.decode('utf-8'), stderr.decode('utf-8') diff --git a/yaksh/bash_stdio_evaluator.py b/yaksh/bash_stdio_evaluator.py index 334620d..1ce729a 100644 --- a/yaksh/bash_stdio_evaluator.py +++ b/yaksh/bash_stdio_evaluator.py @@ -49,7 +49,8 @@ class BashStdIOEvaluator(StdIOEvaluator): shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE + stderr=subprocess.PIPE, + preexec_fn=os.setpgrp ) success, err = self.evaluate_stdio(self.user_answer, proc, self.expected_input, diff --git a/yaksh/cpp_stdio_evaluator.py b/yaksh/cpp_stdio_evaluator.py index b302fa4..d211bb7 100644 --- a/yaksh/cpp_stdio_evaluator.py +++ b/yaksh/cpp_stdio_evaluator.py @@ -82,7 +82,8 @@ class CppStdIOEvaluator(StdIOEvaluator): shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE + stderr=subprocess.PIPE, + preexec_fn=os.setpgrp ) success, err = self.evaluate_stdio(self.user_answer, proc, self.expected_input, diff --git a/yaksh/evaluator_tests/test_bash_evaluation.py b/yaksh/evaluator_tests/test_bash_evaluation.py index 482d45e..8bb8c81 100644 --- a/yaksh/evaluator_tests/test_bash_evaluation.py +++ b/yaksh/evaluator_tests/test_bash_evaluation.py @@ -3,6 +3,8 @@ import unittest import os import shutil import tempfile +from psutil import Process, pid_exists +# Local Imports from yaksh.grader import Grader from yaksh.bash_code_evaluator import BashCodeEvaluator from yaksh.bash_stdio_evaluator import BashStdIOEvaluator @@ -103,6 +105,10 @@ class BashAssertionEvaluationTestCases(EvaluatorBaseTest): # Then self.assertFalse(result.get("success")) self.assert_correct_output(self.timeout_msg, result.get("error")) + parent_proc = Process(os.getpid()).children() + if parent_proc: + children_procs = Process(parent_proc[0].pid) + self.assertFalse(any(children_procs.children(recursive=True))) def test_file_based_assert(self): # Given @@ -528,6 +534,10 @@ class BashHookEvaluationTestCases(EvaluatorBaseTest): # Then self.assertFalse(result.get('success')) self.assert_correct_output(self.timeout_msg, result.get('error')) + parent_proc = Process(os.getpid()).children() + if parent_proc: + children_procs = Process(parent_proc[0].pid) + self.assertFalse(any(children_procs.children(recursive=True))) if __name__ == '__main__': diff --git a/yaksh/evaluator_tests/test_c_cpp_evaluation.py b/yaksh/evaluator_tests/test_c_cpp_evaluation.py index 304f1cb..b15f766 100644 --- a/yaksh/evaluator_tests/test_c_cpp_evaluation.py +++ b/yaksh/evaluator_tests/test_c_cpp_evaluation.py @@ -4,6 +4,7 @@ import os import shutil import tempfile from textwrap import dedent +from psutil import Process # Local import from yaksh.grader import Grader @@ -151,6 +152,10 @@ class CAssertionEvaluationTestCases(EvaluatorBaseTest): # Then self.assertFalse(result.get("success")) self.assert_correct_output(self.timeout_msg, result.get("error")) + parent_proc = Process(os.getpid()).children() + if parent_proc: + children_procs = Process(parent_proc[0].pid) + self.assertFalse(any(children_procs.children(recursive=True))) def test_file_based_assert(self): # Given @@ -401,6 +406,10 @@ class CppStdIOEvaluationTestCases(EvaluatorBaseTest): # Then self.assertFalse(result.get("success")) self.assert_correct_output(self.timeout_msg, result.get("error")) + parent_proc = Process(os.getpid()).children() + if parent_proc: + children_procs = Process(parent_proc[0].pid) + self.assertFalse(any(children_procs.children(recursive=True))) def test_only_stdout(self): # Given @@ -967,6 +976,10 @@ class CppHookEvaluationTestCases(EvaluatorBaseTest): # Then self.assertFalse(result.get('success')) self.assert_correct_output(self.timeout_msg, result.get('error')) + parent_proc = Process(os.getpid()).children() + if parent_proc: + children_procs = Process(parent_proc[0].pid) + self.assertFalse(any(children_procs.children(recursive=True))) if __name__ == '__main__': diff --git a/yaksh/evaluator_tests/test_java_evaluation.py b/yaksh/evaluator_tests/test_java_evaluation.py index 3d127af..ea558ed 100644 --- a/yaksh/evaluator_tests/test_java_evaluation.py +++ b/yaksh/evaluator_tests/test_java_evaluation.py @@ -4,6 +4,9 @@ import os import shutil import tempfile from textwrap import dedent +from psutil import Process, pid_exists +import time + # Local Import from yaksh import grader as gd @@ -158,6 +161,10 @@ class JavaAssertionEvaluationTestCases(EvaluatorBaseTest): # Then self.assertFalse(result.get("success")) self.assert_correct_output(self.timeout_msg, result.get("error")) + parent_proc = Process(os.getpid()).children() + if parent_proc: + children_procs = Process(parent_proc[0].pid) + self.assertFalse(any(children_procs.children(recursive=True))) def test_file_based_assert(self): # Given @@ -398,6 +405,10 @@ class JavaStdIOEvaluationTestCases(EvaluatorBaseTest): # Then self.assertFalse(result.get("success")) self.assert_correct_output(self.timeout_msg, result.get("error")) + parent_proc = Process(os.getpid()).children() + if parent_proc: + children_procs = Process(parent_proc[0].pid) + self.assertFalse(any(children_procs.children(recursive=True))) def test_only_stdout(self): # Given @@ -832,8 +843,13 @@ class JavaHookEvaluationTestCases(EvaluatorBaseTest): result = grader.evaluate(kwargs) # Then + self.assertFalse(result.get('success')) self.assert_correct_output(self.timeout_msg, result.get('error')) + parent_proc = Process(os.getpid()).children() + if parent_proc: + children_procs = Process(parent_proc[0].pid) + self.assertFalse(any(children_procs.children(recursive=True))) if __name__ == '__main__': diff --git a/yaksh/evaluator_tests/test_scilab_evaluation.py b/yaksh/evaluator_tests/test_scilab_evaluation.py index 5a452a3..c3a1c83 100644 --- a/yaksh/evaluator_tests/test_scilab_evaluation.py +++ b/yaksh/evaluator_tests/test_scilab_evaluation.py @@ -3,13 +3,15 @@ import unittest import os import shutil import tempfile +from psutil import Process from textwrap import dedent + +#Local Import from yaksh import grader as gd from yaksh.grader import Grader from yaksh.scilab_code_evaluator import ScilabCodeEvaluator from yaksh.evaluator_tests.test_python_evaluation import EvaluatorBaseTest - class ScilabEvaluationTestCases(EvaluatorBaseTest): def setUp(self): tmp_in_dir_path = tempfile.mkdtemp() @@ -136,6 +138,11 @@ class ScilabEvaluationTestCases(EvaluatorBaseTest): self.assertFalse(result.get("success")) self.assert_correct_output(self.timeout_msg, result.get("error")) + parent_proc = Process(os.getpid()).children() + if parent_proc: + children_procs = Process(parent_proc[0].pid) + self.assertFalse(any(children_procs.children(recursive=True))) + if __name__ == '__main__': unittest.main() diff --git a/yaksh/hook_evaluator.py b/yaksh/hook_evaluator.py index 0819ec9..f5364d6 100644 --- a/yaksh/hook_evaluator.py +++ b/yaksh/hook_evaluator.py @@ -2,6 +2,8 @@ import sys import traceback import os +import signal +import psutil # Local imports from .file_utils import copy_files, delete_files @@ -65,10 +67,12 @@ class HookEvaluator(BaseEvaluator): check = hook_scope["check_answer"] success, err, mark_fraction = check(self.user_answer) except TimeoutException: + processes = psutil.Process(os.getpid()).children(recursive=True) + for process in processes: + process.kill() raise except Exception: msg = traceback.format_exc(limit=0) err = "Error in Hook code: {0}".format(msg) del tb return success, err, mark_fraction -
\ No newline at end of file diff --git a/yaksh/java_stdio_evaluator.py b/yaksh/java_stdio_evaluator.py index 48f265d..4e9238f 100644 --- a/yaksh/java_stdio_evaluator.py +++ b/yaksh/java_stdio_evaluator.py @@ -67,7 +67,8 @@ class JavaStdIOEvaluator(StdIOEvaluator): shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE + stderr=subprocess.PIPE, + preexec_fn=os.setpgrp ) success, err = self.evaluate_stdio(self.user_answer, proc, self.expected_input, diff --git a/yaksh/stdio_evaluator.py b/yaksh/stdio_evaluator.py index fa78a68..554d4c5 100644 --- a/yaksh/stdio_evaluator.py +++ b/yaksh/stdio_evaluator.py @@ -1,7 +1,10 @@ from __future__ import unicode_literals +import os +import signal # Local imports from .base_evaluator import BaseEvaluator +from .grader import TimeoutException class StdIOEvaluator(BaseEvaluator): @@ -9,9 +12,13 @@ class StdIOEvaluator(BaseEvaluator): success = False ip = expected_input.replace(",", " ") encoded_input = '{0}\n'.format(ip).encode('utf-8') - user_output_bytes, output_err_bytes = proc.communicate(encoded_input) - user_output = user_output_bytes.decode('utf-8') - output_err = output_err_bytes.decode('utf-8') + try: + user_output_bytes, output_err_bytes = proc.communicate(encoded_input) + user_output = user_output_bytes.decode('utf-8') + output_err = output_err_bytes.decode('utf-8') + except TimeoutException: + os.killpg(os.getpgid(proc.pid), signal.SIGTERM) + raise expected_output = expected_output.replace("\r", "") if not expected_input: error_msg = "Expected Output is\n{0} ".\ |