Skip to content

Commit

Permalink
docs(Judger): 📝 update document for crate::sandbox
Browse files Browse the repository at this point in the history
  • Loading branch information
Eason0729 committed May 7, 2024
1 parent 11827b7 commit 0a2c15b
Show file tree
Hide file tree
Showing 14 changed files with 235 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ jobs:
run: mkdir -p backend/config && cargo test -p backend
- name: Run Frontend Unit Test
run: cargo test -p frontend
- name: Run Judger Unit Test
run: cargo test -p judger
- name: Lint
run: |
cargo fmt --all -- --check
Expand Down
5 changes: 2 additions & 3 deletions judger/plugins/rlua-54/spec.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ name = "rlua-54" # must be same as dictionary name
uid = "1c41598f-e253-4f81-9ef5-d50bf1e4e74f" # be sure it's unique

[compile]
lockdown = true
command = ["/rlua-54","compile"]
kernel_mem = 67108864
user_mem = 268435456
Expand All @@ -16,6 +15,6 @@ total_time = 10000000
[judge]
command = ["/rlua-54","execute"]
kernel_mem = 67108864
multiplier_memory = 6 # user_mem
memory_multiplier = 6 # user_mem
rt_time = 1000000
multiplier_cpu = 3 # cpu_time
cpu_multiplier = 3 # cpu_time
154 changes: 154 additions & 0 deletions judger/src/language/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
use std::{ffi::OsString, time::Duration};

use serde::Deserialize;
use tokio::io::{AsyncRead, AsyncReadExt};
use uuid::Uuid;

use crate::sandbox::{Cpu, Memory};

pub struct Config {
pub compile_limit: (Cpu, Memory, u64, Duration),
pub judge_limit: (Cpu, Memory, u64, Duration),
pub compile_command: Vec<OsString>,
pub judge_command: Vec<OsString>,
}

impl Config {
async fn from_reader(mut reader: impl AsyncRead + Unpin) -> Self {
let mut buf = String::new();
reader.read_to_string(&mut buf).await.unwrap();
let mut raw: Raw = toml::from_str(&buf).unwrap();
raw.compile.fill();
raw.judge.fill();

Self {
compile_limit: (
Cpu {
kernel: todo!(),
user: todo!(),
total: todo!(),
},
Memory {
kernel: todo!(),
user: todo!(),
total: todo!(),
},
raw.compile.output_limit.unwrap(),
Duration::from_millis(raw.compile.walltime.unwrap()),
),
judge_limit: todo!(),
compile_command: todo!(),
judge_command: todo!(),
}
}
}

#[derive(Deserialize)]
struct Raw {
info: String,
extension: String,
name: String,
id: Uuid,
compile: RawCompile,
judge: RawJudge,
}

#[derive(Deserialize)]
struct RawCompile {
command: Vec<OsString>,
kernel_mem: Option<u64>,
user_mem: Option<u64>,
rt_time: Option<u64>,
cpu_time: Option<u64>,
total_time: Option<u64>,
output_limit: Option<u64>,
walltime: Option<u64>,
}

impl RawCompile {
fn fill(&mut self) {
let template = Self::default();
macro_rules! try_fill {
($f:ident) => {
if self.$f.is_none(){
self.$f=template.$f;
}
};
($f:ident,$($e:ident),+) => {
try_fill!($f);
try_fill!($($e),+);
}
}
try_fill!(
kernel_mem,
user_mem,
rt_time,
cpu_time,
total_time,
output_limit,
walltime
);
}
}

impl Default for RawCompile {
fn default() -> Self {
Self {
command: Vec::new(),
kernel_mem: Some(67108864),
user_mem: Some(268435456),
rt_time: Some(1000000),
cpu_time: Some(1000000),
total_time: Some(10000000),
output_limit: Some(4096),
walltime: Some(360000000),
}
}
}

#[derive(Deserialize)]
struct RawJudge {
command: Vec<OsString>,
kernel_mem: Option<u64>,
rt_time: Option<u64>,
memory_multiplier: Option<f64>,
cpu_multiplier: Option<f64>,
walltime: Option<u64>,
}

impl RawJudge {
fn fill(&mut self) {
let template = Self::default();
macro_rules! try_fill {
($f:ident) => {
if self.$f.is_none(){
self.$f=template.$f;
}
};
($f:ident,$($e:ident),+) => {
try_fill!($f);
try_fill!($($e),+);
}
}
try_fill!(
kernel_mem,
rt_time,
memory_multiplier,
cpu_multiplier,
walltime
);
}
}

impl Default for RawJudge {
fn default() -> Self {
Self {
command: Vec::new(),
kernel_mem: Some(67108864),
rt_time: Some(1000000),
memory_multiplier: Some(1.0),
cpu_multiplier: Some(1.0),
walltime: Some(360000000),
}
}
}
1 change: 1 addition & 0 deletions judger/src/language/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod config;
23 changes: 20 additions & 3 deletions judger/src/sandbox/mod.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
// mod limiter;
mod monitor;
mod process;

use std::{ffi::OsStr, path::Path, time::Duration};

pub use self::monitor::{Cpu, Memory};

/// Context of the sandbox
///
/// define resource limit and filesystem is out of the scope of `filesystem`
pub trait Context: Limit {
type FS: Filesystem;
fn create_fs(&mut self) -> Self::FS;
fn get_args(&mut self) -> impl Iterator<Item = &OsStr>;
}

pub trait Limit {
fn get_cpu(&mut self) -> Cpu;
fn get_memory(&mut self) -> Memory;
fn get_args(&mut self) -> impl Iterator<Item = &OsStr>;
fn get_output_limit(&mut self) -> u64;
fn get_output(&mut self) -> u64;
fn get_walltime(&mut self) -> Duration {
Duration::from_secs(60 * 30)
}
Expand All @@ -25,3 +27,18 @@ pub trait Filesystem {
fn mount(&mut self) -> impl AsRef<Path> + Send;
fn get_size(&mut self) -> u64;
}

impl Limit for (Cpu, Memory, u64, Duration) {
fn get_cpu(&mut self) -> Cpu {
self.0.clone()
}
fn get_memory(&mut self) -> Memory {
self.1.clone()
}
fn get_output(&mut self) -> u64 {
self.2
}
fn get_walltime(&mut self) -> Duration {
self.3
}
}
4 changes: 4 additions & 0 deletions judger/src/sandbox/monitor/hier.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::config::Accounting;
use cgroups_rs::*;

/// type of monitor for cpu
pub enum MonitorKind {
/// use `cpu.stat` from cpu subsystem
Cpu,
/// use cpu accounting subsystem
CpuAcct,
}

Expand All @@ -19,6 +22,7 @@ lazy_static::lazy_static! {
}

impl MonitorKind {
/// get the hierarchy(cgroup v1/v2) of monitor
pub fn heir(&self) -> Box<dyn Hierarchy> {
match self {
MonitorKind::Cpu => hierarchies::auto(),
Expand Down
1 change: 1 addition & 0 deletions judger/src/sandbox/monitor/mem_cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use cgroups_rs::{cgroup_builder::CgroupBuilder, Cgroup};
use std::sync::{atomic::Ordering, Arc};
use tokio::time::*;

/// maximum allow time deviation for cpu monitor
const MONITOR_ACCURACY: Duration = Duration::from_millis(80);

const CG_PATH_COUNTER: AtomicUsize = AtomicUsize::new(0);
Expand Down
20 changes: 19 additions & 1 deletion judger/src/sandbox/monitor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,26 @@ lazy_static::lazy_static! {

pub trait Monitor {
type Resource;
async fn wait_exhaust(&mut self) -> MonitorKind;
/// wait for exhuast of resource
///
/// This function is cancel safe.
async fn wait_exhaust(&mut self) -> MonitorKind {
log::warn!("unimplemented wait_exhaust!");
loop {
if let Some(reason) = self.poll_exhaust() {
return reason;
}
tokio::time::sleep(Duration::from_millis(12)).await;
}
}
/// poll for exhuast of resource
///
/// Implementor should do bith [`wait_exhaust`] and [`poll_exhaust`]
/// for better performance.
fn poll_exhaust(&mut self) -> Option<MonitorKind>;
/// get the resource usage
///
/// Please note that [`poll_exhaust`] might not be called before this function
async fn stat(self) -> Self::Resource;
}

Expand Down
4 changes: 4 additions & 0 deletions judger/src/sandbox/monitor/stat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ use super::output::Output;

pub type MemAndCpu = (Memory, Cpu);

/// statistics of resource usage
pub struct Stat {
pub memory: Memory,
pub cpu: Cpu,
pub output: Output,
pub walltime: Duration,
}

/// memory usage(in bytes)
#[derive(Clone)]
pub struct Memory {
pub kernel: u64,
pub user: u64,
Expand All @@ -25,6 +28,7 @@ impl Memory {
}
}

/// cpu usage(in nanoseconds)
#[derive(Clone)]
pub struct Cpu {
pub kernel: u64,
Expand Down
1 change: 0 additions & 1 deletion judger/src/sandbox/monitor/walltime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ impl super::Monitor for Monitor {
}
Some(MonitorKind::Walltime)
}

async fn stat(self) -> Self::Resource {
match self.start {
Some(start) => Instant::now().duration_since(start),
Expand Down
1 change: 1 addition & 0 deletions judger/src/sandbox/process/corpse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::process::ExitStatus;

use super::monitor::{MonitorKind, Stat};

/// A corpse of a process
pub struct Corpse {
/// exit code of signal
pub(super) code: Option<ExitStatus>,
Expand Down
15 changes: 15 additions & 0 deletions judger/src/sandbox/process/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
//! A module that provides a way to setup environment for a process and run.
//!
//! Using this module should be SAFE(can't launching a process without
//! explicit resource limitation)
//!
//! ```norun
//! use process::*;
//!
//! // implement process context yourself
//! let ctx=Context::new();
//!
//! let process=Process::new(ctx).unwrap();
//! let corpse=process.wait(b"data for stdin").await.unwrap();
//! ```
mod corpse;
mod nsjail;
mod process;
Expand Down
Loading

0 comments on commit 0a2c15b

Please sign in to comment.