常规更新

This commit is contained in:
MeiK 2020-09-01 19:39:52 +08:00
parent 45af94494a
commit 14d67da8f3
3 changed files with 131 additions and 31 deletions

View File

@ -1,7 +1,7 @@
use crate::river::judge_response::{JudgeResult, JudgeStatus};
use crate::river::JudgeResponse;
use libc::strerror;
use std::ffi::CStr;
use std::ffi::{CStr, NulError, OsString};
use std::fmt;
use std::io;
use std::result;
@ -12,6 +12,8 @@ pub enum Error {
LanguageNotFound(i32),
FileWriteError(io::Error),
ChannelRecvError,
StringToCStringError(NulError),
OsStringToStringError(OsString),
}
pub type Result<T> = result::Result<T, Error>;

View File

@ -6,21 +6,30 @@ use crate::river::{JudgeRequest, JudgeResponse};
use std::path::Path;
use tokio::fs;
impl JudgeResponse {
fn new() -> JudgeResponse {
JudgeResponse {
time_used: 0,
memory_used: 0,
result: JudgeResult::Accepted as i32,
errno: 0,
exit_code: 0,
stdout: "".into(),
stderr: "".into(),
errmsg: "".into(),
status: JudgeStatus::Running as i32,
}
}
}
pub async fn judger(request: &JudgeRequest) -> Result<JudgeResponse> {
return Ok(JudgeResponse {
time_used: request.time_limit,
memory_used: 2,
result: JudgeResult::Accepted as i32,
errno: 0,
exit_code: 0,
stdout: "stdout".into(),
stderr: "stderr".into(),
errmsg: "".into(),
status: JudgeStatus::Ended as i32,
});
let mut resp = JudgeResponse::new();
resp.time_used = request.time_limit;
return Ok(resp);
}
pub async fn compile(request: &JudgeRequest, path: &Path) -> Result<JudgeResponse> {
let mut resp = JudgeResponse::new();
// 写入代码
let filename = match Language::from_i32(request.language) {
Some(Language::C) => "main.c",
@ -36,21 +45,29 @@ pub async fn compile(request: &JudgeRequest, path: &Path) -> Result<JudgeRespons
return Err(Error::FileWriteError(e));
};
let process = Process::new();
let status = process.await?;
println!("{}", status.exit_code);
let mut process = Process::new();
let cmd = match Language::from_i32(request.language) {
Some(Language::C) => "gcc main.c",
Some(Language::Cpp) => "g++ main.cpp",
Some(Language::Python) => "/usr/bin/python3 -m compileall main.py",
Some(Language::Rust) => "rustc main.rs",
// 无需编译的语言直接返回
Some(Language::Node) => return Ok(resp),
Some(Language::TypeScript) => "tsc",
Some(Language::Go) => "main.go",
None => return Err(Error::LanguageNotFound(request.language)),
};
process.cmd = cmd.to_string();
process.workdir = path.to_path_buf();
process.time_limit = request.time_limit;
process.memory_limit = request.memory_limit;
return Ok(JudgeResponse {
time_used: request.time_limit,
memory_used: 2,
result: JudgeResult::Accepted as i32,
errno: 0,
exit_code: 0,
stdout: "stdout".into(),
stderr: "stderr".into(),
errmsg: "".into(),
status: JudgeStatus::Ended as i32,
});
let status = process.await?;
if status.exit_code != 0 {
resp.result = JudgeResult::CompileError as i32;
resp.status = JudgeStatus::Ended as i32;
}
return Ok(resp);
}
pub fn pending() -> JudgeResponse {

View File

@ -1,7 +1,12 @@
use super::error::{Error, Result};
use libc;
use std::env;
use std::ffi::CString;
use std::future::Future;
use std::mem;
use std::path::PathBuf;
use std::pin::Pin;
use std::ptr;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll};
@ -11,6 +16,7 @@ use std::time::SystemTime;
#[derive(Clone)]
pub struct Process {
pub pid: i32,
pub workdir: PathBuf,
pub time_limit: i32,
pub memory_limit: i32,
pub stdin_fd: i32,
@ -32,6 +38,7 @@ impl Process {
stdout_fd: -1,
stderr_fd: -1,
cmd: "".to_string(),
workdir: PathBuf::from(""),
tx: Arc::new(Mutex::new(tx)),
rx: Arc::new(Mutex::new(rx)),
}
@ -91,14 +98,88 @@ impl Future for Process {
}
}
fn run(_process: Process) {
unsafe {
// TODO
println!("run");
libc::exit(1);
pub struct ExecArgs {
pub pathname: *const libc::c_char,
pub argv: *const *const libc::c_char,
pub envp: *const *const libc::c_char,
}
impl ExecArgs {
fn build(cmd: &String) -> Result<ExecArgs> {
let cmds: Vec<&str> = cmd.split_whitespace().collect();
let pathname = cmds[0].clone();
let pathname_str = match CString::new(pathname) {
Ok(value) => value,
Err(err) => return Err(Error::StringToCStringError(err)),
};
let pathname = pathname_str.as_ptr();
let mut argv_vec: Vec<*const libc::c_char> = vec![];
for item in cmds.iter() {
let cstr = match CString::new(item.clone()) {
Ok(value) => value,
Err(err) => return Err(Error::StringToCStringError(err)),
};
let cptr = cstr.as_ptr();
// 需要使用 mem::forget 来标记
// 否则在此次循环结束后cstr 就会被回收,后续 exec 函数无法通过指针获取到字符串内容
mem::forget(cstr);
argv_vec.push(cptr);
}
// argv 与 envp 的参数需要使用 NULL 来标记结束
argv_vec.push(ptr::null());
let argv: *const *const libc::c_char = argv_vec.as_ptr() as *const *const libc::c_char;
// env 环境变量传递当前进程环境变量
let mut envp_vec: Vec<*const libc::c_char> = vec![];
for (key, value) in env::vars_os() {
let mut key = match key.to_str() {
Some(val) => val.to_string(),
None => return Err(Error::OsStringToStringError(key)),
};
let value = match value.to_str() {
Some(val) => val.to_string(),
None => return Err(Error::OsStringToStringError(value)),
};
key.push_str("=");
key.push_str(&value);
let cstr = match CString::new(key) {
Ok(value) => value,
Err(err) => return Err(Error::StringToCStringError(err)),
};
let cptr = cstr.as_ptr();
// 需要使用 mem::forget 来标记
// 否则在此次循环结束后cstr 就会被回收,后续 exec 函数无法通过指针获取到字符串内容
mem::forget(cstr);
envp_vec.push(cptr);
}
envp_vec.push(ptr::null());
let envp = envp_vec.as_ptr() as *const *const libc::c_char;
mem::forget(pathname_str);
mem::forget(argv_vec);
mem::forget(envp_vec);
Ok(ExecArgs {
pathname,
argv,
envp,
})
}
}
fn run(process: Process) {
// 子进程里崩溃也无法返回,崩溃就直接崩溃了
let exec_args = ExecArgs::build(&process.cmd).unwrap();
// 修改工作目录
env::set_current_dir(process.workdir).unwrap();
println!("{}", process.cmd);
unsafe {
// TODO: 资源限制等
libc::execve(exec_args.pathname, exec_args.argv, exec_args.envp);
}
panic!("How dare you!");
}
fn wait(pid: i32) -> ProcessStatus {
let start = SystemTime::now();
let mut status = 0;