diff --git a/src/libos/src/misc/mod.rs b/src/libos/src/misc/mod.rs index 809e7467..b6567883 100644 --- a/src/libos/src/misc/mod.rs +++ b/src/libos/src/misc/mod.rs @@ -1,5 +1,7 @@ use super::*; mod uname; +mod rlimit; pub use self::uname::{utsname_t, do_uname}; +pub use self::rlimit::{rlimit_t, resource_t, ResourceLimits, ResourceLimitsRef, do_prlimit}; diff --git a/src/libos/src/misc/rlimit.rs b/src/libos/src/misc/rlimit.rs new file mode 100644 index 00000000..f55acd6c --- /dev/null +++ b/src/libos/src/misc/rlimit.rs @@ -0,0 +1,123 @@ +use super::*; +use process::{pid_t}; + +#[derive(Debug, Copy, Clone)] +pub struct ResourceLimits { + rlimits: [rlimit_t; RLIMIT_COUNT], +} +pub type ResourceLimitsRef = Arc>; + +impl ResourceLimits { + pub fn get(&self, resource: resource_t) -> &rlimit_t { + &self.rlimits[resource as usize] + } + + pub fn get_mut(&mut self, resource: resource_t) -> &mut rlimit_t { + &mut self.rlimits[resource as usize] + } +} + +impl Default for ResourceLimits { + fn default() -> ResourceLimits { + // TODO: set appropriate limits for resources + let mut rlimits = ResourceLimits { + rlimits: [ Default::default(); RLIMIT_COUNT ], + }; + rlimits + } +} + + +#[derive(Debug, Copy, Clone)] +#[allow(non_camel_case_types)] +pub struct rlimit_t { + cur: u64, + max: u64, +} + +impl Default for rlimit_t { + fn default() -> rlimit_t { + rlimit_t { + cur: u64::max_value(), + max: u64::max_value(), + } + } +} + + +#[derive(Debug, Copy, Clone)] +#[allow(non_camel_case_types)] +pub enum resource_t { + RLIMIT_CPU = 0, + RLIMIT_FSIZE = 1, + RLIMIT_DATA = 2, + RLIMIT_STACK = 3, + RLIMIT_CORE = 4, + RLIMIT_RSS = 5, + RLIMIT_NPROC = 6, + RLIMIT_NOFILE = 7, + RLIMIT_MEMLOCK = 8, + RLIMIT_AS = 9, + RLIMIT_LOCKS = 10, + RLIMIT_SIGPENDING = 11, + RLIMIT_MSGQUEUE = 12, + RLIMIT_NICE = 13, + RLIMIT_RTPRIO = 14, +} +const RLIMIT_COUNT: usize = 15; + +impl resource_t { + pub fn from_u32(bits: u32) -> Result { + match bits { + 0 => Ok(resource_t::RLIMIT_CPU), + 1 => Ok(resource_t::RLIMIT_FSIZE), + 2 => Ok(resource_t::RLIMIT_DATA), + 3 => Ok(resource_t::RLIMIT_STACK), + 4 => Ok(resource_t::RLIMIT_CORE), + 5 => Ok(resource_t::RLIMIT_RSS), + 6 => Ok(resource_t::RLIMIT_NPROC), + 7 => Ok(resource_t::RLIMIT_NOFILE), + 8 => Ok(resource_t::RLIMIT_MEMLOCK), + 9 => Ok(resource_t::RLIMIT_AS), + 10 => Ok(resource_t::RLIMIT_LOCKS), + 11 => Ok(resource_t::RLIMIT_SIGPENDING), + 12 => Ok(resource_t::RLIMIT_MSGQUEUE), + 13 => Ok(resource_t::RLIMIT_NICE), + 14 => Ok(resource_t::RLIMIT_RTPRIO), + _ => errno!(EINVAL, "invalid resource"), + } + } +} + + +pub fn do_prlimit( + pid: pid_t, + resource: resource_t, + new_limit: Option<&rlimit_t>, + old_limit: Option<&mut rlimit_t>, +) -> Result<(), Error> { + let process_ref = if pid == 0 { + process::get_current() + } + else { + process::get(pid)? + }; + let mut process = process_ref.lock().unwrap(); + let rlimits_ref = process.get_rlimits(); + let mut rlimits = rlimits_ref.lock().unwrap(); + if let Some(old_limit) = old_limit { + *old_limit = *rlimits.get(resource) + } + if let Some(new_limit) = new_limit { + *rlimits.get_mut(resource) = *new_limit; + } + Ok(()) +} + +pub fn do_getrlimit(resource: resource_t, old_limit: &mut rlimit_t) -> Result<(), Error> { + do_prlimit(0 as pid_t, resource, None, Some(old_limit)) +} + +pub fn do_setrlimit(resource: resource_t, new_limit: &rlimit_t) -> Result<(), Error> { + do_prlimit(0 as pid_t, resource, Some(new_limit), None) +} diff --git a/src/libos/src/process/mod.rs b/src/libos/src/process/mod.rs index 8ec293ec..86c6017e 100644 --- a/src/libos/src/process/mod.rs +++ b/src/libos/src/process/mod.rs @@ -1,8 +1,6 @@ pub use self::process::{Status, IDLE_PROCESS}; pub use self::task::{get_current, run_task}; -pub mod table { - pub use super::process_table::get; -} +pub use self::process_table::{get}; pub use self::exit::{do_exit, do_wait4, ChildProcessFilter}; pub use self::spawn::{do_spawn, FileAction}; pub use self::wait::{WaitQueue, Waiter}; @@ -30,6 +28,7 @@ pub struct Process { waiting_children: Option>, vm: ProcessVMRef, file_table: FileTableRef, + rlimits: ResourceLimitsRef, } pub type ProcessRef = Arc>; @@ -79,3 +78,4 @@ use self::task::Task; use super::*; use fs::{File, FileRef, FileTable}; use vm::{ProcessVM, VMRangeTrait}; +use misc::{ResourceLimitsRef}; diff --git a/src/libos/src/process/process.rs b/src/libos/src/process/process.rs index e932b081..74260c18 100644 --- a/src/libos/src/process/process.rs +++ b/src/libos/src/process/process.rs @@ -20,6 +20,7 @@ lazy_static! { waiting_children: Default::default(), vm: Default::default(), file_table: Default::default(), + rlimits: Default::default(), })) }; } @@ -30,6 +31,7 @@ impl Process { task: Task, vm_ref: ProcessVMRef, file_table_ref: FileTableRef, + rlimits_ref: ResourceLimitsRef, ) -> Result<(pid_t, ProcessRef), Error> { let new_pid = process_table::alloc_pid(); let new_process_ref = Arc::new(SgxMutex::new(Process { @@ -46,6 +48,7 @@ impl Process { waiting_children: None, vm: vm_ref, file_table: file_table_ref, + rlimits: rlimits_ref, })); Ok((new_pid, new_process_ref)) } @@ -97,6 +100,9 @@ impl Process { self.cwd += path; } } + pub fn get_rlimits(&self) -> &ResourceLimitsRef { + &self.rlimits + } } impl Drop for Process { diff --git a/src/libos/src/process/process_table.rs b/src/libos/src/process/process_table.rs index fdda8d3e..ed800df7 100644 --- a/src/libos/src/process/process_table.rs +++ b/src/libos/src/process/process_table.rs @@ -14,8 +14,10 @@ pub fn remove(pid: pid_t) { PROCESS_TABLE.lock().unwrap().remove(&pid); } -pub fn get(pid: pid_t) -> Option { - PROCESS_TABLE.lock().unwrap().get(&pid).map(|pr| pr.clone()) +pub fn get(pid: pid_t) -> Result { + PROCESS_TABLE.lock().unwrap().get(&pid) + .map(|pr| pr.clone()) + .ok_or_else(|| Error::new(Errno::ENOENT, "process not found")) } static NEXT_PID: AtomicU32 = AtomicU32::new(1); diff --git a/src/libos/src/process/spawn/mod.rs b/src/libos/src/process/spawn/mod.rs index c32a7e4c..3dd58ec1 100644 --- a/src/libos/src/process/spawn/mod.rs +++ b/src/libos/src/process/spawn/mod.rs @@ -6,6 +6,7 @@ use std::ffi::{CStr, CString}; use std::path::Path; use std::sgxfs::SgxFile; use vm::{ProcessVM, VMRangeTrait}; +use misc::{ResourceLimitsRef}; use super::*; use super::task::Task; @@ -72,7 +73,8 @@ pub fn do_spawn>( let files = init_files(parent_ref, file_actions)?; Arc::new(SgxMutex::new(files)) }; - Process::new(&cwd, task, vm_ref, files_ref)? + let rlimits_ref = Default::default(); + Process::new(&cwd, task, vm_ref, files_ref, rlimits_ref)? }; parent_adopts_new_child(&parent_ref, &new_process_ref); process_table::put(new_pid, new_process_ref.clone()); diff --git a/src/libos/src/process/thread.rs b/src/libos/src/process/thread.rs index 8d8d925a..e28187d9 100644 --- a/src/libos/src/process/thread.rs +++ b/src/libos/src/process/thread.rs @@ -51,8 +51,9 @@ pub fn do_clone( let task = new_thread_task(stack_addr, new_tls)?; let vm_ref = current.get_vm().clone(); let files_ref = current.get_files().clone(); + let rlimits_ref = current.get_rlimits().clone(); let cwd = ¤t.cwd; - Process::new(cwd, task, vm_ref, files_ref)? + Process::new(cwd, task, vm_ref, files_ref, rlimits_ref)? }; if let Some(ctid) = ctid { diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 76d41be8..1e642086 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -8,7 +8,7 @@ use std::ptr; use time::timeval_t; use util::mem_util::from_user::*; use vm::{VMAreaFlags, VMResizeOptions}; -use misc::{utsname_t}; +use misc::{utsname_t, resource_t, rlimit_t}; use super::*; @@ -134,6 +134,8 @@ pub extern "C" fn dispatch_syscall( SYS_UNAME => do_uname(arg0 as *mut utsname_t), + SYS_PRLIMIT64 => do_prlimit(arg0 as pid_t, arg1 as u32, arg2 as *const rlimit_t, arg3 as *mut rlimit_t), + _ => do_unknown(num, arg0, arg1, arg2, arg3, arg4, arg5), }; debug!("syscall return: {:?}", ret); @@ -705,3 +707,26 @@ fn do_uname(name: *mut utsname_t) -> Result { let name = unsafe { &mut *name }; misc::do_uname(name).map(|_| 0) } + +fn do_prlimit(pid: pid_t, resource: u32, new_limit: *const rlimit_t, old_limit: *mut rlimit_t) -> Result { + let resource = resource_t::from_u32(resource)?; + let new_limit = { + if new_limit != ptr::null() { + check_ptr(new_limit)?; + Some(unsafe { &*new_limit }) + } + else { + None + } + }; + let old_limit = { + if old_limit != ptr::null_mut() { + check_mut_ptr(old_limit)?; + Some(unsafe { &mut *old_limit }) + } + else { + None + } + }; + misc::do_prlimit(pid, resource, new_limit, old_limit).map(|_| 0) +} diff --git a/test/Makefile b/test/Makefile index 98152f6b..f300e9ff 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../) # Dependencies: need to be compiled but not to run by any Makefile target TEST_DEPS := dev_null # Tests: need to be compiled and run by test-% target -TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread uname +TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit # Benchmarks: need to be compiled and run by bench-% target BENCHES := spawn_and_exit_latency pipe_throughput diff --git a/test/rlimit/Makefile b/test/rlimit/Makefile new file mode 100644 index 00000000..9e1b6dec --- /dev/null +++ b/test/rlimit/Makefile @@ -0,0 +1,5 @@ +include ../test_common.mk + +EXTRA_C_FLAGS := +EXTRA_LINK_FLAGS := +BIN_ARGS := diff --git a/test/rlimit/main.c b/test/rlimit/main.c new file mode 100644 index 00000000..5e1943e5 --- /dev/null +++ b/test/rlimit/main.c @@ -0,0 +1,15 @@ +#include +#include + +int main(int argc, const char* argv[]) { + struct rlimit rlim; + if (getrlimit(RLIMIT_AS, &rlim) < 0) { + printf("ERROR: getrlimit failed\n"); + return -1; + } + if (setrlimit(RLIMIT_AS, &rlim) < 0) { + printf("ERROR: getrlimit failed\n"); + return -1; + } + return 0; +}