修复setitimer无法限制子进程时间的BUG, 增加测试17

This commit is contained in:
spxcds 2016-05-02 13:55:18 +08:00
parent 7fa58f5d72
commit df0cc40750
7 changed files with 59 additions and 3 deletions

View File

@ -31,7 +31,7 @@ void run(struct config *config, struct result *result) {
int status;
struct rusage resource_usage;
struct timeval start, end;
struct rlimit memory_limit;
struct rlimit memory_limit, cpu_time_rlimit;
int signal;
int i;
FILE* log_fp;
@ -166,7 +166,7 @@ void run(struct config *config, struct result *result) {
if (config->max_memory != MEMORY_UNLIMITED) {
memory_limit.rlim_cur = memory_limit.rlim_max = (rlim_t) (config->max_memory) * 2;
if (setrlimit(RLIMIT_AS, &memory_limit) == -1) {
LOG_FATAL(log_fp, "setrlimit failed, errno: %d", errno);
LOG_FATAL(log_fp, "setrlimit memory failed, errno: %d", errno);
ERROR(log_fp, SETRLIMIT_FAILED);
}
}
@ -181,6 +181,14 @@ void run(struct config *config, struct result *result) {
LOG_FATAL(log_fp, "set real time timer failed");
ERROR(log_fp, SETITIMER_FAILED);
}
// child process can not inherit timeout rules from parent process defined by setitimer, so we use setrlimit to
// control child process max running time
cpu_time_rlimit.rlim_cur = cpu_time_rlimit.rlim_max = (config->max_cpu_time + 1000) / 1000;
if (setrlimit(RLIMIT_CPU, &cpu_time_rlimit) == -1) {
LOG_FATAL(log_fp, "setrlimit cpu time failed, errno: %d", errno);
ERROR(log_fp, SETRLIMIT_FAILED);
}
}
// read stdin from in file

29
tests/17/Main.c Normal file
View File

@ -0,0 +1,29 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{
int status;
int pid;
if ((pid = fork()) < 0) {
perror("fork error");
return 0;
}
if (pid == 0) {
while (1) {};
}
else {
struct rusage resource_usage;
if (wait4(pid, &status, 0, &resource_usage) == -1) {
perror("wait4 error!");
}
}
return 0;
}

1
tests/17/config Normal file
View File

@ -0,0 +1 @@
{"language": "c", "max_cpu_time": 2000, "max_memory": 200000000, "use_sandbox": false}

0
tests/17/in Normal file
View File

0
tests/17/out Normal file
View File

1
tests/17/result Normal file
View File

@ -0,0 +1 @@
{"flag": 0, "signal": 0}

View File

@ -31,7 +31,7 @@ class JudgerTest(TestCase):
continue
print "\n\nRunning test: ", i
test_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), str(i))
exe_path = os.path.join("/tmp/judger_test", str(i))
exe_path = os.path.join(self.tmp_path, str(i))
config = json.loads(open(os.path.join(test_dir, "config")).read())
self.assertEqual(self.compile_src(os.path.join(test_dir, "Main.c"), config.pop("language"), exe_path), 0)
@ -51,6 +51,7 @@ class JudgerTest(TestCase):
self._judger_in_file_args_check()
self._judger_args_args_check()
self._judger_env_args_check()
self._judger_child_process_cpu_time_check()
self._judger_user_args_check()
def _judger_cpu_time_args_check(self):
@ -129,6 +130,22 @@ class JudgerTest(TestCase):
out_file="/dev/null", max_cpu_time=2000, max_memory=200000000,
env=["aaa=123"], use_sandbox=True, use_nobody=True)
# child process can not inherit timeout rules from parent process defined by setitimer, so we use setrlimit to
# control child process max running time
def _judger_child_process_cpu_time_check(self):
try:
max_cpu_time = 2000
result = judger.run(path=os.path.join(self.tmp_path, "17"), in_file="/dev/null",
out_file="/dev/null", max_cpu_time=max_cpu_time, max_memory=200000000,
env=["aaa=123"], use_sandbox=False, use_nobody=True)
expected_cpu_time = (max_cpu_time + 1000) / 1000 * 1000
if result["cpu_time"] > expected_cpu_time * 1.1:
self.fail("cpu time exceeded")
if result["real_time"] >= max_cpu_time * 3:
self.fail("real time exceeded")
except Exception as e:
self.fail(e.message)
if __name__ == "__main__":
main()