Update TODO

This commit is contained in:
MeiK 2020-05-21 15:05:28 +08:00
parent 353236a154
commit d3ed13ea13
6 changed files with 100 additions and 31 deletions

View File

@ -1 +1,6 @@
# river # river
## TODO
- 资源限制
- 资源占用过多的错误

View File

@ -21,7 +21,7 @@ pub enum Error {
TemplateRenderError(RenderError), TemplateRenderError(RenderError),
LanguageConfigError(String), LanguageConfigError(String),
CreateTempDirError(io::Error), CreateTempDirError(io::Error),
CloseTempDirError(io::Error), // CloseTempDirError(io::Error),
CopyFileError(io::Error), CopyFileError(io::Error),
OsStringToStringError(OsString), OsStringToStringError(OsString),
ForkError(Option<i32>), ForkError(Option<i32>),

View File

@ -36,6 +36,7 @@ fn main() {
match process::run(&judge_config) { match process::run(&judge_config) {
Ok(_) => {} Ok(_) => {}
Err(err) => { Err(err) => {
// TODO: SE
eprintln!("{}", err); eprintln!("{}", err);
return; return;
} }

View File

@ -134,11 +134,18 @@ pub fn run(judge_config: &JudgeConfig) -> Result<()> {
}; };
} }
// TODO: 处理 CE 与 RE编译期间程序运行出错为 CE运行期间出错为 RE // TODO: 处理 CE 与 RE编译期间程序运行出错为 CE运行期间出错为 RE
let _ = compile(judge_config, to_dir)?; let compile_status = compile(judge_config, to_dir)?;
if !compile_status.exited {
// TODO: CE
}
for test_case in &judge_config.tests { for test_case in &judge_config.tests {
let exit_status = run_one(judge_config, test_case, to_dir)?; let exit_status = run_one(judge_config, test_case, to_dir)?;
let output_file_path = to_dir.join(&test_case.output_file); let output_file_path = to_dir.join(&test_case.output_file);
let answer_file_path = from_dir.join(&test_case.answer_file); let answer_file_path = from_dir.join(&test_case.answer_file);
if !exit_status.exited {
// TODO: RE
}
let res = TestCaseResult::standard(&output_file_path, &answer_file_path, exit_status); let res = TestCaseResult::standard(&output_file_path, &answer_file_path, exit_status);
println!("{:?}", res); println!("{:?}", res);
match fs::remove_file(output_file_path) { match fs::remove_file(output_file_path) {
@ -151,10 +158,11 @@ pub fn run(judge_config: &JudgeConfig) -> Result<()> {
} }
}; };
} }
match pwd.close() { println!("{:?}", pwd);
Ok(_) => {} // match pwd.close() {
Err(err) => return Err(Error::CloseTempDirError(err)), // Ok(_) => {}
}; // Err(err) => return Err(Error::CloseTempDirError(err)),
// };
Ok(()) Ok(())
} }
@ -200,9 +208,26 @@ pub fn wait(pid: i32) -> Result<ExitStatus> {
Ok(elapsed) => elapsed.as_millis(), Ok(elapsed) => elapsed.as_millis(),
Err(err) => return Err(Error::SystemTimeError(err)), Err(err) => return Err(Error::SystemTimeError(err)),
}; };
let signal = unsafe {
if libc::WIFSIGNALED(status) {
libc::WTERMSIG(status)
} else if libc::WIFSTOPPED(status) {
libc::WSTOPSIG(status)
} else {
0
}
};
let exited = unsafe { libc::WIFEXITED(status) };
if exited {
status = unsafe { libc::WEXITSTATUS(status) };
}
let coredump = unsafe { libc::WCOREDUMP(status) };
Ok(ExitStatus { Ok(ExitStatus {
rusage, rusage,
status, status,
signal,
exited,
coredump,
time_used, time_used,
real_time_used, real_time_used,
memory_used, memory_used,
@ -267,15 +292,14 @@ pub fn run_one(
panic!("How dare you!"); panic!("How dare you!");
} else if pid > 0 { } else if pid > 0 {
// 父进程 // 父进程
let exit_status = wait(pid)?; return Ok(wait(pid)?);
return Ok(exit_status);
} else { } else {
// 异常 // 异常
return Err(Error::ForkError(io::Error::last_os_error().raw_os_error())); return Err(Error::ForkError(io::Error::last_os_error().raw_os_error()));
} }
} }
pub fn compile(judge_config: &JudgeConfig, workdir: &Path) -> Result<()> { pub fn compile(judge_config: &JudgeConfig, workdir: &Path) -> Result<ExitStatus> {
let pid; let pid;
unsafe { unsafe {
pid = libc::fork(); pid = libc::fork();
@ -292,9 +316,8 @@ pub fn compile(judge_config: &JudgeConfig, workdir: &Path) -> Result<()> {
} }
panic!("How dare you!"); panic!("How dare you!");
} else if pid > 0 { } else if pid > 0 {
let _ = wait(pid)?; return Ok(wait(pid)?);
} else { } else {
return Err(Error::ForkError(io::Error::last_os_error().raw_os_error())); return Err(Error::ForkError(io::Error::last_os_error().raw_os_error()));
} }
Ok(())
} }

View File

@ -6,15 +6,12 @@ use std::fs::File;
use std::io::{self, BufRead, BufReader}; use std::io::{self, BufRead, BufReader};
use std::path::Path; use std::path::Path;
#[derive(Debug, Copy, Clone)]
pub struct ResourceUsed {
pub time_used: i64,
pub memory_used: i64,
}
pub struct ExitStatus { pub struct ExitStatus {
pub rusage: libc::rusage, pub rusage: libc::rusage,
pub status: i32, pub status: i32,
pub signal: i32,
pub exited: bool,
pub coredump: bool,
pub time_used: i64, pub time_used: i64,
pub real_time_used: u128, pub real_time_used: u128,
pub memory_used: i64, pub memory_used: i64,
@ -22,11 +19,11 @@ pub struct ExitStatus {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum TestCaseResult { pub enum TestCaseResult {
Accepted(ResourceUsed), Accepted,
CompileError(ResourceUsed, String), CompileError(String),
WrongAnswer(ResourceUsed), WrongAnswer,
RuntimeError(ResourceUsed, String), RuntimeError(String),
SystemError(ResourceUsed, String), SystemError(String),
} }
impl fmt::Display for TestCaseResult { impl fmt::Display for TestCaseResult {
@ -45,10 +42,9 @@ impl TestCaseResult {
println!("time used:\t{}", exit_status.time_used); println!("time used:\t{}", exit_status.time_used);
println!("real time used:\t{}", exit_status.real_time_used); println!("real time used:\t{}", exit_status.real_time_used);
println!("memory used:\t{}", exit_status.rusage.ru_maxrss); println!("memory used:\t{}", exit_status.rusage.ru_maxrss);
let used = ResourceUsed { println!("status:\t{}", exit_status.status);
time_used: exit_status.time_used, println!("signal:\t{}", exit_status.signal);
memory_used: exit_status.rusage.ru_maxrss, println!("exited:\t{}", exit_status.exited);
};
let output_filename = match output_file.as_ref().to_str() { let output_filename = match output_file.as_ref().to_str() {
Some(val) => val, Some(val) => val,
@ -108,13 +104,13 @@ impl TestCaseResult {
break; break;
} }
if output_buffer.trim_end() != answer_buffer.trim_end() { if output_buffer.trim_end() != answer_buffer.trim_end() {
return Ok(TestCaseResult::WrongAnswer(used)); return Ok(TestCaseResult::WrongAnswer);
} }
} }
// 末尾的空白字符不影响结果 // 末尾的空白字符不影响结果
while output_bytes != 0 { while output_bytes != 0 {
if output_buffer.trim() != "" { if output_buffer.trim() != "" {
return Ok(TestCaseResult::WrongAnswer(used)); return Ok(TestCaseResult::WrongAnswer);
} }
output_bytes = match output_reader.read_line(&mut output_buffer) { output_bytes = match output_reader.read_line(&mut output_buffer) {
Ok(val) => val, Ok(val) => val,
@ -128,7 +124,7 @@ impl TestCaseResult {
} }
while answer_bytes != 0 { while answer_bytes != 0 {
if answer_buffer.trim() != "" { if answer_buffer.trim() != "" {
return Ok(TestCaseResult::WrongAnswer(used)); return Ok(TestCaseResult::WrongAnswer);
} }
answer_bytes = match answer_reader.read_line(&mut answer_buffer) { answer_bytes = match answer_reader.read_line(&mut answer_buffer) {
Ok(val) => val, Ok(val) => val,
@ -141,6 +137,6 @@ impl TestCaseResult {
}; };
} }
Ok(TestCaseResult::Accepted(used)) Ok(TestCaseResult::Accepted)
} }
} }

44
tests/response.json Normal file
View File

@ -0,0 +1,44 @@
{
"compile": {
"time": 120,
"memory": 4096,
"status": 0,
"signal": 0,
"exited": true,
"output": "main.c: In function main: \nmain.c:5:5: warning: ignoring return value of scanf, declared with attribute warn_unused_result [-Wunused-result] \n scanf(\"%d %d\", &a, &b);"
},
"tests": [
{
"time": 0,
"memory": 1576,
"status": 0,
"signal": 0,
"exited": true,
"result": "Accepted"
},
{
"time": 0,
"memory": 1576,
"status": 0,
"signal": 0,
"exited": true,
"result": "WrongAnswer"
},
{
"time": 0,
"memory": 1576,
"status": 0,
"signal": 0,
"exited": true,
"result": "Accepted"
},
{
"time": 0,
"memory": 1576,
"status": 139,
"signal": 11,
"exited": false,
"result": "RuntimeError"
}
]
}