This commit is contained in:
MeiK 2020-08-30 22:02:13 +08:00
parent 7931f6b2bc
commit 55d090af9d
3 changed files with 89 additions and 22 deletions

View File

@ -1,5 +1,7 @@
use crate::river::judge_response::{JudgeResult, JudgeStatus};
use crate::river::JudgeResponse;
use libc::strerror;
use std::ffi::CStr;
use std::fmt;
use std::io;
use std::result;
@ -9,13 +11,29 @@ pub enum Error {
CreateTempDirError(io::Error),
LanguageNotFound(i32),
FileWriteError(io::Error),
ForkError(Option<i32>),
}
pub type Result<T> = result::Result<T, Error>;
pub fn errno_str(errno: Option<i32>) -> String {
match errno {
Some(no) => {
let stre = unsafe { strerror(no) };
let c_str: &CStr = unsafe { CStr::from_ptr(stre) };
c_str.to_str().unwrap().to_string()
}
_ => "Unknown Error!".to_string(),
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::ForkError(errno) => {
let reason = errno_str(errno);
write!(f, "ForkError: {}", reason)
}
_ => write!(f, "{:?}", self),
}
}

View File

@ -31,7 +31,6 @@ pub async fn compile(request: &JudgeRequest, path: &Path) -> Result<JudgeRespons
Some(Language::Go) => "main.go",
None => return Err(Error::LanguageNotFound(request.language)),
};
if let Err(e) = fs::write(path.join(filename), request.code.clone()).await {
return Err(Error::FileWriteError(e));
};

View File

@ -1,41 +1,91 @@
use super::error::{Error, Result};
use libc;
use std::future::Future;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::thread;
use std::time::Duration;
#[derive(Clone)]
pub struct Process {
pub pid: i32,
pub time_limit: i32,
pub read_time_limit: i32,
pub memory_limit: i32,
pub stdin_fd: i32,
pub stdout_fd: i32,
pub stderr_fd: i32,
pub cmd: str,
pub cmd: String,
}
impl Process {
pub fn new() -> Process {
Process {
pid: -1,
time_limit: -1,
memory_limit: -1,
stdin_fd: -1,
stdout_fd: -1,
stderr_fd: -1,
cmd: "".to_string(),
}
}
pub fn set_pid(&mut self, pid: i32) {
self.pid = pid;
}
}
impl Future for Process {
type Output = &'static str;
type Output = Result<ProcessStatus>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<&'static str> {
let mut status = 0;
unsafe {
// TODO: fork、修改用户、组、设置限制exec 等等
// TODO: seccomp 等保证安全
let _pid = libc::waitpid(self.pid, &mut status, libc::WNOHANG);
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<ProcessStatus>> {
// pid == -1 时为第一次触发,此时开始运行
// 直到进程执行完毕, wake 通知进入下次检查
if self.pid == -1 {
let pid;
unsafe {
pid = libc::fork();
}
if pid == 0 {
// 子进程
// TODO: fork、修改用户、组、设置限制exec 等等
// TODO: seccomp 等保证安全
let process = Pin::into_inner(self).clone();
run(process);
} else if pid > 0 {
// 父进程
self.as_mut().set_pid(pid);
let waker = cx.waker().clone();
let pid = self.pid;
thread::spawn(move || {
// 等待子进程结束
wait(pid);
// 触发唤醒异步
waker.wake();
});
} else {
// 出错
return Poll::Ready(Err(Error::ForkError(
io::Error::last_os_error().raw_os_error(),
)));
}
return Poll::Pending;
} else {
// 子进程结束后被唤醒
// 收集运行信息,返回数据,结束异步
wait(self.pid);
// TODO: Poll::Ready
return Poll::Pending;
}
if status != 0 {
return Poll::Ready("");
}
let waker = cx.waker().clone();
thread::spawn(move || {
thread::sleep(Duration::from_millis(3000));
waker.wake();
});
Poll::Pending
}
}
fn run(process: Process) {}
fn wait(pid: i32) {}
pub struct ProcessStatus {
pub rusage: libc::rusage,
pub exit_code: i32,
pub status: i32,
}