mirror of
https://github.com/MeiK2333/river.git
synced 2025-11-04 14:49:40 +08:00
Update
This commit is contained in:
parent
8ba1eb2d90
commit
c35eb6ae29
@ -68,7 +68,7 @@ message JudgeResponse {
|
|||||||
}
|
}
|
||||||
// int32 errno = 4;
|
// int32 errno = 4;
|
||||||
// int32 exit_code = 5;
|
// int32 exit_code = 5;
|
||||||
// string stdout = 6;
|
string stdout = 6;
|
||||||
// string stderr = 7;
|
string stderr = 7;
|
||||||
string errmsg = 8;
|
string errmsg = 8;
|
||||||
}
|
}
|
||||||
|
|||||||
3
src/config.rs
Normal file
3
src/config.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub static STDIN_FILENAME: &str = "stdin.txt";
|
||||||
|
pub static STDOUT_FILENAME: &str = "stdout.txt";
|
||||||
|
pub static STDERR_FILENAME: &str = "stderr.txt";
|
||||||
@ -14,6 +14,7 @@ pub enum Error {
|
|||||||
CreateTempDirError(io::Error),
|
CreateTempDirError(io::Error),
|
||||||
LanguageNotFound(i32),
|
LanguageNotFound(i32),
|
||||||
FileWriteError(io::Error),
|
FileWriteError(io::Error),
|
||||||
|
FileReadError(io::Error),
|
||||||
ChannelRecvError,
|
ChannelRecvError,
|
||||||
StringToCStringError(NulError),
|
StringToCStringError(NulError),
|
||||||
OsStringToStringError(OsString),
|
OsStringToStringError(OsString),
|
||||||
@ -57,6 +58,8 @@ pub fn system_error(err: Error) -> JudgeResponse {
|
|||||||
time_used: 0,
|
time_used: 0,
|
||||||
memory_used: 0,
|
memory_used: 0,
|
||||||
state: Some(State::Result(JudgeResult::SystemError as i32)),
|
state: Some(State::Result(JudgeResult::SystemError as i32)),
|
||||||
|
stdout: "".into(),
|
||||||
|
stderr: "".into(),
|
||||||
errmsg: format!("{}", err).into(),
|
errmsg: format!("{}", err).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use super::config::{STDERR_FILENAME, STDOUT_FILENAME};
|
||||||
use super::error::{Error, Result};
|
use super::error::{Error, Result};
|
||||||
use super::process::Process;
|
use super::process::Process;
|
||||||
use super::runner::RunnerStatus;
|
use super::runner::RunnerStatus;
|
||||||
@ -14,6 +15,8 @@ impl JudgeResponse {
|
|||||||
time_used: 0,
|
time_used: 0,
|
||||||
memory_used: 0,
|
memory_used: 0,
|
||||||
errmsg: "".into(),
|
errmsg: "".into(),
|
||||||
|
stdout: "".into(),
|
||||||
|
stderr: "".into(),
|
||||||
state: Some(State::Status(JudgeStatus::Running as i32)),
|
state: Some(State::Status(JudgeStatus::Running as i32)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,27 +43,17 @@ pub async fn judger(
|
|||||||
Some(Language::Go) => "./a.out",
|
Some(Language::Go) => "./a.out",
|
||||||
None => return Err(Error::LanguageNotFound(request.language)),
|
None => return Err(Error::LanguageNotFound(request.language)),
|
||||||
};
|
};
|
||||||
let mut process = Process::new(
|
let process = Process::new(
|
||||||
cmd.to_string(),
|
cmd.to_string(),
|
||||||
path.to_path_buf(),
|
path.to_path_buf(),
|
||||||
|
&data.in_data,
|
||||||
data.time_limit,
|
data.time_limit,
|
||||||
data.memory_limit,
|
data.memory_limit,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// 设置输入数据
|
|
||||||
process.set_stdin(&data.in_data)?;
|
|
||||||
|
|
||||||
// 开始执行并等待返回结果
|
// 开始执行并等待返回结果
|
||||||
let runner = process.runner.clone();
|
let runner = process.runner.clone();
|
||||||
let status = runner.await?;
|
let status = runner.await?;
|
||||||
// TODO: 对比答案
|
|
||||||
// 此处是为了消除 warning 的临时代码
|
|
||||||
let reader = process.stdout_reader()?;
|
|
||||||
let mut buf: [u8; 1024] = [0; 1024];
|
|
||||||
reader.readline(&mut buf)?;
|
|
||||||
let reader = process.stderr_reader()?;
|
|
||||||
let mut buf: [u8; 1024] = [0; 1024];
|
|
||||||
reader.readline(&mut buf)?;
|
|
||||||
|
|
||||||
// TODO: 根据返回值等判断 tle、mle、re 等状态
|
// TODO: 根据返回值等判断 tle、mle、re 等状态
|
||||||
// TODO: 对比答案,检查结果
|
// TODO: 对比答案,检查结果
|
||||||
@ -92,33 +85,45 @@ pub async fn compile(
|
|||||||
return Err(Error::FileWriteError(e));
|
return Err(Error::FileWriteError(e));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: 使用配置文件
|
||||||
let cmd = match Language::from_i32(request.language) {
|
let cmd = match Language::from_i32(request.language) {
|
||||||
Some(Language::C) => "/usr/bin/gcc main.c -o a.out -Wall -O2 -std=c99 --static",
|
Some(Language::C) => "/usr/bin/gcc main.c -o a.out -Wall -O2 -std=c99 --static",
|
||||||
Some(Language::Cpp) => "/usr/bin/g++ main.cpp -O2 -Wall --static -o a.out --std=gnu++17",
|
Some(Language::Cpp) => "/usr/bin/g++ main.cpp -O2 -Wall --static -o a.out --std=gnu++17",
|
||||||
Some(Language::Python) => "/usr/bin/python3 -m compileall main.py",
|
Some(Language::Python) => "/usr/bin/python3 -m compileall main.py",
|
||||||
Some(Language::Rust) => "/usr/bin/rustc main.rs -o a.out -C opt-level=2",
|
Some(Language::Rust) => "/usr/bin/rustc main.rs -o a.out -C opt-level=2",
|
||||||
// 无需编译的语言直接返回
|
|
||||||
// TODO: eslint......
|
// TODO: eslint......
|
||||||
Some(Language::Node) => return Ok(resp),
|
Some(Language::Node) => "/bin/echo hello",
|
||||||
Some(Language::TypeScript) => "/usr/bin/tsc",
|
Some(Language::TypeScript) => "/usr/bin/tsc",
|
||||||
Some(Language::Go) => "/usr/bin/go build -ldflags \"-s -w\" main.go",
|
Some(Language::Go) => "/usr/bin/go build -ldflags \"-s -w\" main.go",
|
||||||
None => return Err(Error::LanguageNotFound(request.language)),
|
None => return Err(Error::LanguageNotFound(request.language)),
|
||||||
};
|
};
|
||||||
// 编译的资源限制为固定的
|
debug!("build command: {}", cmd);
|
||||||
let process = Process::new(cmd.to_string(), path.to_path_buf(), 10000, 64 * 1024)?;
|
let v = vec![];
|
||||||
|
let process = Process::new(
|
||||||
|
cmd.to_string(),
|
||||||
|
path.to_path_buf(),
|
||||||
|
&v,
|
||||||
|
// 编译的资源限制为固定的
|
||||||
|
10000,
|
||||||
|
64 * 1024,
|
||||||
|
)?;
|
||||||
|
|
||||||
let runner = process.runner.clone();
|
let runner = process.runner.clone();
|
||||||
let status = runner.await?;
|
let status = runner.await?;
|
||||||
resp.set_process_status(&status);
|
resp.set_process_status(&status);
|
||||||
if status.exit_code != 0 {
|
if status.exit_code != 0 {
|
||||||
debug!("compile exit code: {}", status.exit_code);
|
debug!("compile exit code: {}", status.exit_code);
|
||||||
let reader = process.stdout_reader()?;
|
// 从 stdout 和 stderr 中获取错误信息
|
||||||
let stdout = reader.read()?;
|
let stdout = match fs::read_to_string(path.join(STDOUT_FILENAME)).await {
|
||||||
debug!("stdout {}", stdout);
|
Ok(val) => val,
|
||||||
let reader = process.stderr_reader()?;
|
Err(e) => return Err(Error::FileReadError(e)),
|
||||||
let stderr = reader.read()?;
|
};
|
||||||
debug!("stderr {}", stderr);
|
let stderr = match fs::read_to_string(path.join(STDERR_FILENAME)).await {
|
||||||
resp.errmsg = stderr;
|
Ok(val) => val,
|
||||||
|
Err(e) => return Err(Error::FileReadError(e)),
|
||||||
|
};
|
||||||
|
resp.stdout = stdout;
|
||||||
|
resp.stderr = stderr;
|
||||||
resp.state = Some(State::Result(JudgeResult::CompileError as i32));
|
resp.state = Some(State::Result(JudgeResult::CompileError as i32));
|
||||||
} else {
|
} else {
|
||||||
resp.state = Some(State::Result(JudgeResult::Accepted as i32));
|
resp.state = Some(State::Result(JudgeResult::Accepted as i32));
|
||||||
|
|||||||
@ -13,11 +13,11 @@ use tempfile::tempdir_in;
|
|||||||
use tonic::transport::Server;
|
use tonic::transport::Server;
|
||||||
use tonic::{Request, Response, Status};
|
use tonic::{Request, Response, Status};
|
||||||
|
|
||||||
|
mod config;
|
||||||
mod error;
|
mod error;
|
||||||
mod exec_args;
|
mod exec_args;
|
||||||
mod judger;
|
mod judger;
|
||||||
mod process;
|
mod process;
|
||||||
mod reader;
|
|
||||||
mod runner;
|
mod runner;
|
||||||
|
|
||||||
pub mod river {
|
pub mod river {
|
||||||
|
|||||||
147
src/process.rs
147
src/process.rs
@ -1,10 +1,8 @@
|
|||||||
|
use super::config::STDIN_FILENAME;
|
||||||
use super::error::{Error, Result};
|
use super::error::{Error, Result};
|
||||||
use super::reader::Reader;
|
|
||||||
use super::runner::Runner;
|
use super::runner::Runner;
|
||||||
use libc;
|
use libc;
|
||||||
use std::ffi::c_void;
|
use std::fs;
|
||||||
use std::ffi::CString;
|
|
||||||
use std::os::raw::c_char;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
@ -17,57 +15,27 @@ pub struct Process {
|
|||||||
pub runner: Runner,
|
pub runner: Runner,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_buf_str(path_buf: &PathBuf) -> Result<String> {
|
|
||||||
let file = match path_buf.file_stem() {
|
|
||||||
Some(stem) => match stem.to_str() {
|
|
||||||
Some(val) => val.to_string(),
|
|
||||||
None => return Err(Error::PathBufToStringError(path_buf.clone())),
|
|
||||||
},
|
|
||||||
None => return Err(Error::PathBufToStringError(path_buf.clone())),
|
|
||||||
};
|
|
||||||
Ok(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Process {
|
impl Process {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
cmd: String,
|
cmd: String,
|
||||||
workdir: PathBuf,
|
workdir: PathBuf,
|
||||||
|
in_data: &Vec<u8>,
|
||||||
time_limit: i32,
|
time_limit: i32,
|
||||||
memory_limit: i32,
|
memory_limit: i32,
|
||||||
) -> Result<Process> {
|
) -> Result<Process> {
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
let memfile = path_buf_str(&workdir)?;
|
debug!("writing input file");
|
||||||
let outfile = match CString::new(format!("{}{}", "stdout", memfile)) {
|
// TODO: 此处同步写入文件,后续可以修改为异步写入,防止阻塞整体流程
|
||||||
Ok(val) => val,
|
if let Err(e) = fs::write(workdir.join(STDIN_FILENAME), &in_data) {
|
||||||
Err(e) => return Err(Error::StringToCStringError(e)),
|
return Err(Error::FileWriteError(e));
|
||||||
};
|
|
||||||
let errfile = match CString::new(format!("{}{}", "stderr", memfile)) {
|
|
||||||
Ok(val) => val,
|
|
||||||
Err(e) => return Err(Error::StringToCStringError(e)),
|
|
||||||
};
|
|
||||||
let stdout_fd = unsafe {
|
|
||||||
libc::shm_open(
|
|
||||||
outfile.as_ptr(),
|
|
||||||
libc::O_RDWR | libc::O_CREAT,
|
|
||||||
libc::S_IRUSR | libc::S_IWUSR,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let stderr_fd = unsafe {
|
|
||||||
libc::shm_open(
|
|
||||||
errfile.as_ptr(),
|
|
||||||
libc::O_RDWR | libc::O_CREAT,
|
|
||||||
libc::S_IRUSR | libc::S_IWUSR,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Process {
|
Ok(Process {
|
||||||
runner: Runner {
|
runner: Runner {
|
||||||
pid: -1,
|
pid: -1,
|
||||||
time_limit: time_limit,
|
time_limit: time_limit,
|
||||||
memory_limit: memory_limit,
|
memory_limit: memory_limit,
|
||||||
stdin_fd: None,
|
|
||||||
stdout_fd: stdout_fd,
|
|
||||||
stderr_fd: stderr_fd,
|
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
workdir: workdir,
|
workdir: workdir,
|
||||||
tx: Arc::new(Mutex::new(tx)),
|
tx: Arc::new(Mutex::new(tx)),
|
||||||
@ -75,60 +43,6 @@ impl Process {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 为进程设置 stdin 的数据
|
|
||||||
pub fn set_stdin(&mut self, in_data: &Vec<u8>) -> Result<()> {
|
|
||||||
if in_data.len() == 0 {
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
let memfile = path_buf_str(&self.runner.workdir)?;
|
|
||||||
let memfile = format!("{}{}", "stdin", memfile);
|
|
||||||
// 打开内存文件
|
|
||||||
let fd = unsafe {
|
|
||||||
libc::shm_open(
|
|
||||||
CString::new(memfile).unwrap().as_ptr(),
|
|
||||||
libc::O_RDWR | libc::O_CREAT,
|
|
||||||
libc::S_IRUSR | libc::S_IWUSR,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
if fd <= 0 {
|
|
||||||
return Err(Error::SyscallError("shm_open".to_string()));
|
|
||||||
}
|
|
||||||
self.runner.stdin_fd = Some(fd);
|
|
||||||
// 扩充内存到数据文件大小
|
|
||||||
if unsafe { libc::ftruncate(fd, in_data.len() as i64) } < 0 {
|
|
||||||
return Err(Error::SyscallError("ftruncate".to_string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 复制数据到创建的内存中
|
|
||||||
unsafe {
|
|
||||||
let ptr = libc::mmap(
|
|
||||||
std::ptr::null_mut() as *mut c_void,
|
|
||||||
in_data.len(),
|
|
||||||
libc::PROT_WRITE,
|
|
||||||
libc::MAP_SHARED,
|
|
||||||
fd,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
if ptr == libc::MAP_FAILED {
|
|
||||||
return Err(Error::SyscallError("mmap".to_string()));
|
|
||||||
}
|
|
||||||
libc::strcpy(ptr as *mut c_char, in_data.as_ptr() as *const i8);
|
|
||||||
// 复制完要记得 munmap,否则会造成无法回收的内存泄露
|
|
||||||
if libc::munmap(ptr, in_data.len()) < 0 {
|
|
||||||
return Err(Error::SyscallError("munmap".to_string()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stdout_reader(&self) -> Result<Reader> {
|
|
||||||
Reader::new(self.runner.stdout_fd)
|
|
||||||
}
|
|
||||||
pub fn stderr_reader(&self) -> Result<Reader> {
|
|
||||||
Reader::new(self.runner.stderr_fd)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Process {
|
impl Drop for Process {
|
||||||
@ -147,37 +61,11 @@ impl Drop for Process {
|
|||||||
libc::waitpid(self.runner.pid, &mut status, 0);
|
libc::waitpid(self.runner.pid, &mut status, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 如果设置了 stdin 数据,则需要释放对应的内存
|
|
||||||
if let Some(_) = self.runner.stdin_fd {
|
|
||||||
// 如果 stdin_fd 有值,则说明 pathbuf 的转换一定没问题,否则上面也不会转换成功
|
|
||||||
let memfile = self
|
|
||||||
.runner
|
|
||||||
.workdir
|
|
||||||
.clone()
|
|
||||||
.into_os_string()
|
|
||||||
.into_string()
|
|
||||||
.unwrap();
|
|
||||||
unsafe {
|
|
||||||
libc::shm_unlink(CString::new(memfile).unwrap().as_ptr());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 清理 stdout 和 stderr 的空间
|
|
||||||
let memfile = path_buf_str(&self.runner.workdir).unwrap();
|
|
||||||
let outfile = CString::new(format!("{}{}", "stdout", memfile)).unwrap();
|
|
||||||
let errfile = CString::new(format!("{}{}", "stderr", memfile)).unwrap();
|
|
||||||
unsafe {
|
|
||||||
libc::shm_unlink(CString::new(outfile).unwrap().as_ptr());
|
|
||||||
libc::shm_unlink(CString::new(errfile).unwrap().as_ptr());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::process::Process;
|
|
||||||
use std::fs;
|
|
||||||
use tempfile::tempdir_in;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hello() {
|
fn hello() {
|
||||||
let s = String::from("hello");
|
let s = String::from("hello");
|
||||||
@ -186,22 +74,5 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn run() {
|
async fn run() {}
|
||||||
let cmd = String::from("/bin/echo hello");
|
|
||||||
let pwd = tempdir_in("./runner").unwrap().into_path();
|
|
||||||
let path = pwd.to_str().unwrap();
|
|
||||||
let process = Process::new(cmd, pwd.clone(), 1000, 65535).unwrap();
|
|
||||||
let runner = process.runner.clone();
|
|
||||||
let status = runner.await.unwrap();
|
|
||||||
fs::remove_dir_all(path).unwrap();
|
|
||||||
assert_eq!(status.exit_code, 0);
|
|
||||||
|
|
||||||
let mut buf: [u8; 1024] = [0; 1024];
|
|
||||||
let reader = process.stdout_reader().unwrap();
|
|
||||||
reader.readline(&mut buf).unwrap();
|
|
||||||
let s = String::from("hello\n");
|
|
||||||
let bytes = s.into_bytes();
|
|
||||||
assert_eq!(&buf[0..6], &bytes[..]);
|
|
||||||
assert_eq!(buf[6], 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,55 +0,0 @@
|
|||||||
use super::error::{Error, Result};
|
|
||||||
use libc;
|
|
||||||
use std::ffi::CString;
|
|
||||||
use std::os::raw::c_char;
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
pub struct Reader {
|
|
||||||
fd: i32,
|
|
||||||
stream: *mut libc::FILE,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Reader {
|
|
||||||
pub fn new(fd: i32) -> Result<Reader> {
|
|
||||||
let mode = match CString::new("r") {
|
|
||||||
Ok(val) => val,
|
|
||||||
Err(e) => return Err(Error::StringToCStringError(e)),
|
|
||||||
};
|
|
||||||
let stream = unsafe { libc::fdopen(fd, mode.as_ptr()) };
|
|
||||||
Ok(Reader { fd, stream: stream })
|
|
||||||
}
|
|
||||||
pub fn readline(&self, buf: &mut [u8]) -> Result<()> {
|
|
||||||
let res = unsafe {
|
|
||||||
libc::fgets(
|
|
||||||
buf.as_mut_ptr() as *mut c_char,
|
|
||||||
buf.len() as i32,
|
|
||||||
self.stream,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
if res.is_null() {
|
|
||||||
return Err(Error::SyscallError("fgets".to_string()));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
pub fn read(&self) -> Result<String> {
|
|
||||||
let mut result: String = "".to_owned();
|
|
||||||
let mut buf: [u8; 1024] = [0; 1024];
|
|
||||||
while unsafe { libc::read(self.fd, buf.as_mut_ptr() as *mut libc::c_void, 1024) } != 0 {
|
|
||||||
let s = match str::from_utf8(&buf) {
|
|
||||||
Ok(val) => (val),
|
|
||||||
Err(_) => return Err(Error::SyscallError("read".to_string())),
|
|
||||||
};
|
|
||||||
debug!("{}", s);
|
|
||||||
result.push_str(s);
|
|
||||||
}
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Reader {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
libc::fclose(self.stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +1,8 @@
|
|||||||
|
use super::config::{STDERR_FILENAME, STDIN_FILENAME, STDOUT_FILENAME};
|
||||||
use super::error::{errno_str, Error, Result};
|
use super::error::{errno_str, Error, Result};
|
||||||
use super::exec_args::ExecArgs;
|
use super::exec_args::ExecArgs;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::ffi::CString;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -18,9 +20,6 @@ pub struct Runner {
|
|||||||
pub workdir: PathBuf,
|
pub workdir: PathBuf,
|
||||||
pub time_limit: i32,
|
pub time_limit: i32,
|
||||||
pub memory_limit: i32,
|
pub memory_limit: i32,
|
||||||
pub stdin_fd: Option<i32>,
|
|
||||||
pub stdout_fd: i32,
|
|
||||||
pub stderr_fd: i32,
|
|
||||||
pub cmd: String,
|
pub cmd: String,
|
||||||
pub tx: Arc<Mutex<mpsc::Sender<RunnerStatus>>>,
|
pub tx: Arc<Mutex<mpsc::Sender<RunnerStatus>>>,
|
||||||
pub rx: Arc<Mutex<mpsc::Receiver<RunnerStatus>>>,
|
pub rx: Arc<Mutex<mpsc::Receiver<RunnerStatus>>>,
|
||||||
@ -109,6 +108,24 @@ impl Future for Runner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn dup(filename: &str, to: libc::c_int, flag: libc::c_int, mode: libc::c_int) {
|
||||||
|
let filename_str = CString::new(filename).unwrap();
|
||||||
|
let filename = filename_str.as_ptr();
|
||||||
|
let fd = libc::open(filename, flag, mode);
|
||||||
|
if fd < 0 {
|
||||||
|
let err = io::Error::last_os_error().raw_os_error();
|
||||||
|
eprintln!("open failure!");
|
||||||
|
eprintln!("{:?}", io::Error::last_os_error().raw_os_error());
|
||||||
|
panic!(errno_str(err));
|
||||||
|
}
|
||||||
|
if libc::dup2(fd, to) < 0 {
|
||||||
|
let err = io::Error::last_os_error().raw_os_error();
|
||||||
|
eprintln!("dup2 failure!");
|
||||||
|
eprintln!("{:?}", io::Error::last_os_error().raw_os_error());
|
||||||
|
panic!(errno_str(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Runner {
|
impl Runner {
|
||||||
pub fn run(&self) {
|
pub fn run(&self) {
|
||||||
// 子进程里崩溃也无法返回,崩溃就直接崩溃了
|
// 子进程里崩溃也无法返回,崩溃就直接崩溃了
|
||||||
@ -132,11 +149,19 @@ impl Runner {
|
|||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
// 重定向文件描述符
|
// 重定向文件描述符
|
||||||
if let Some(fd) = self.stdin_fd {
|
dup(STDIN_FILENAME, libc::STDIN_FILENO, libc::O_RDONLY, 0o644);
|
||||||
dup(fd, libc::STDIN_FILENO);
|
dup(
|
||||||
}
|
STDOUT_FILENAME,
|
||||||
dup(self.stdout_fd, libc::STDOUT_FILENO);
|
libc::STDOUT_FILENO,
|
||||||
dup(self.stderr_fd, libc::STDERR_FILENO);
|
libc::O_CREAT | libc::O_RDWR,
|
||||||
|
0o644,
|
||||||
|
);
|
||||||
|
dup(
|
||||||
|
STDERR_FILENAME,
|
||||||
|
libc::STDERR_FILENO,
|
||||||
|
libc::O_CREAT | libc::O_RDWR,
|
||||||
|
0o644,
|
||||||
|
);
|
||||||
// 墙上时钟限制
|
// 墙上时钟限制
|
||||||
if setitimer(ITIMER_REAL, &rt, ptr::null_mut()) == -1 {
|
if setitimer(ITIMER_REAL, &rt, ptr::null_mut()) == -1 {
|
||||||
eprintln!("setitimer failure!");
|
eprintln!("setitimer failure!");
|
||||||
@ -170,15 +195,6 @@ impl Runner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn dup(from: libc::c_int, to: libc::c_int) {
|
|
||||||
if libc::dup2(from, to) < 0 {
|
|
||||||
let err = io::Error::last_os_error().raw_os_error();
|
|
||||||
eprintln!("dup2 failure!");
|
|
||||||
eprintln!("{:?}", io::Error::last_os_error().raw_os_error());
|
|
||||||
panic!(errno_str(err));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Runner {
|
impl Runner {
|
||||||
pub fn wait(&self) -> RunnerStatus {
|
pub fn wait(&self) -> RunnerStatus {
|
||||||
let pid = self.pid;
|
let pid = self.pid;
|
||||||
@ -214,15 +230,6 @@ impl Runner {
|
|||||||
eprintln!("{:?}", io::Error::last_os_error().raw_os_error());
|
eprintln!("{:?}", io::Error::last_os_error().raw_os_error());
|
||||||
panic!("How dare you!");
|
panic!("How dare you!");
|
||||||
}
|
}
|
||||||
// 重置输出偏移量
|
|
||||||
if libc::lseek(self.stdout_fd, 0, libc::SEEK_SET) < 0 {
|
|
||||||
eprintln!("{:?}", io::Error::last_os_error().raw_os_error());
|
|
||||||
panic!("How dare you!");
|
|
||||||
}
|
|
||||||
if libc::lseek(self.stderr_fd, 0, libc::SEEK_SET) < 0 {
|
|
||||||
eprintln!("{:?}", io::Error::last_os_error().raw_os_error());
|
|
||||||
panic!("How dare you!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut exit_code = 0;
|
let mut exit_code = 0;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user