Add timerslack concept for libos and enbale prctl PR_GET_TIMERSLACK option

This commit is contained in:
Hui, Chunyang 2020-09-03 06:53:22 +00:00 committed by Tate, Hongliang Tian
parent 1a11655169
commit 4031216f13
10 changed files with 101 additions and 15 deletions

@ -118,6 +118,7 @@ enclave {
void occlum_ocall_clock_gettime(clockid_t clockid, [out] struct timespec* ts);
void occlum_ocall_clock_getres(clockid_t clockid, [out] struct timespec* res);
void occlum_ocall_rdtsc([out] uint32_t* low, [out] uint32_t* high);
void occlum_ocall_get_timerslack([out] int *timer_slack);
int occlum_ocall_nanosleep(
[in] const struct timespec* req,

@ -1,3 +1,4 @@
use super::super::time::timer_slack::TIMERSLACK;
use super::*;
pub fn select(
@ -63,7 +64,10 @@ pub fn select(
if !timeout.is_null() {
let time_left = unsafe { *(timeout) };
time_left.validate()?;
assert!(time_left.as_duration() <= origin_timeout.as_duration());
assert!(
// Note: TIMERSLACK is a single value use maintained by the libOS and will not vary for different threads.
time_left.as_duration() <= origin_timeout.as_duration() + (*TIMERSLACK).to_duration()
);
}
debug!("returned pollfds are {:?}", pollfds);

@ -3,34 +3,31 @@
// Implement `PrctlNum` and `PrctlCmd`.
#[macro_export]
macro_rules! impl_prctl_nums_and_cmds {
($( $prctl_name: ident => ( $prctl_num: expr, $($prctl_type_tt: tt)* ) ),+,) => {
($( $prctl_name: ident => ( $prctl_num: expr, $($prctl_type_tt: tt),* ) ),+,) => {
$(const $prctl_name:i32 = $prctl_num;)*
impl_prctl_cmds! {
$(
$prctl_name => ( $($prctl_type_tt)*),
$prctl_name => ( $($prctl_type_tt),* ),
)*
}
}
}
macro_rules! impl_prctl_cmds {
($( $prctl_name: ident => ( $($prctl_type_tt: tt)* ) ),+,) => {
($( $prctl_name: ident => ( $($prctl_type_tt: tt),* ) ),+,) => {
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub enum PrctlCmd<'a> {
$(
$prctl_name( get_arg_type!($($prctl_type_tt)*) ),
$prctl_name($(get_arg_type!($prctl_type_tt)),* ),
)*
}
}
}
macro_rules! get_arg_type {
(()) => {
()
};
($($prctl_type_tt: tt)*) => {
$($prctl_type_tt)*
($prctl_type_tt: tt) => {
$prctl_type_tt
};
}

@ -3,6 +3,7 @@ use alloc::vec::Vec;
use std::ffi::CString;
use std::os::raw::c_char;
use super::super::time::timer_slack::TIMERSLACK;
use super::thread::ThreadName;
use crate::prelude::*;
use crate::util::mem_util::from_user::{check_array, clone_cstring_safely};
@ -16,8 +17,9 @@ impl_prctl_nums_and_cmds! {
// Format:
// prctl_name => (prctl_num, prctl_type_arg, ...
PR_SET_NAME => (15, ThreadName),
// Get thread name
PR_GET_NAME => (16, &'a mut [u8]),
PR_GET_NAME => (16, (&'a mut [u8])),
PR_SET_TIMERSLACK => (29, u64),
PR_GET_TIMERSLACK => (30, ()),
}
impl<'a> PrctlCmd<'a> {
@ -39,6 +41,8 @@ impl<'a> PrctlCmd<'a> {
};
PrctlCmd::PR_GET_NAME(buf_checked)
}
PR_SET_TIMERSLACK => PrctlCmd::PR_SET_TIMERSLACK(arg2),
PR_GET_TIMERSLACK => PrctlCmd::PR_GET_TIMERSLACK(()),
_ => {
debug!("prctl cmd num: {}", cmd);
return_errno!(EINVAL, "unsupported prctl command");
@ -59,7 +63,17 @@ pub fn do_prctl(cmd: PrctlCmd) -> Result<isize> {
let name = current.name();
c_buf.copy_from_slice(name.as_slice());
}
_ => warn!("Prctl command not supported"),
PrctlCmd::PR_SET_TIMERSLACK(nanoseconds) => {
return_errno!(
EINVAL,
"Setting timer slack for different libos process is not supported"
);
}
PrctlCmd::PR_GET_TIMERSLACK(()) => {
let nanoseconds = (*TIMERSLACK).to_u32();
return Ok(nanoseconds as isize);
}
_ => return_errno!(EINVAL, "Prctl command not supported"),
}
Ok(0)

@ -175,7 +175,7 @@ pub fn do_futex(
pub fn do_prctl(option: i32, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> Result<isize> {
let prctl_cmd = super::prctl::PrctlCmd::from_raw(option, arg2, arg3, arg4, arg5)?;
super::prctl::do_prctl(prctl_cmd).map(|_| 0)
super::prctl::do_prctl(prctl_cmd)
}
pub fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize> {

@ -1,3 +1,4 @@
use self::timer_slack::*;
use super::*;
use core::convert::TryFrom;
use process::pid_t;
@ -8,6 +9,7 @@ use std::{fmt, u64};
use syscall::SyscallNum;
mod profiler;
pub mod timer_slack;
pub mod up_time;
pub use profiler::ThreadProfiler;
@ -182,7 +184,7 @@ pub fn do_nanosleep(req: &timespec_t, rem: Option<&mut timespec_t>) -> Result<()
assert!(sgx_status == sgx_status_t::SGX_SUCCESS);
assert!(ret == 0 || libc::errno() == Errno::EINTR as i32);
if ret != 0 {
assert!(u_rem.as_duration() <= req.as_duration());
assert!(u_rem.as_duration() <= req.as_duration() + (*TIMERSLACK).to_duration());
if let Some(rem) = rem {
*rem = u_rem;
}

@ -0,0 +1,47 @@
use super::*;
use std::time::Duration;
pub struct TimerSlack {
nanoseconds: u32,
}
impl TimerSlack {
pub fn new(nanoseconds: u32) -> Result<Self> {
let timerslack = Self { nanoseconds };
timerslack.validate()?;
Ok(timerslack)
}
pub fn validate(&self) -> Result<()> {
// Timer slack bigger than 1ms is considered invalid here. The kernel default timer slack is 50us.
if self.nanoseconds < 1_000_000 {
Ok(())
} else {
return_errno!(EINVAL, "invalid value for TimerSlack");
}
}
pub fn to_u32(&self) -> u32 {
self.nanoseconds
}
pub fn to_duration(&self) -> Duration {
Duration::from_nanos(self.to_u32() as u64)
}
}
lazy_static! {
pub static ref TIMERSLACK: TimerSlack =
do_get_timerslack().unwrap_or(TimerSlack::new(50_000).unwrap()); // Use kernel default timer slack 50us.
}
fn do_get_timerslack() -> Result<TimerSlack> {
extern "C" {
fn occlum_ocall_get_timerslack(nanosecond: *mut i32) -> sgx_status_t;
}
let mut timer_slack: i32 = 0;
let sgx_status = unsafe { occlum_ocall_get_timerslack(&mut timer_slack as *mut i32) };
assert!(sgx_status == sgx_status_t::SGX_SUCCESS);
TimerSlack::new(timer_slack as u32)
}

@ -1,5 +1,6 @@
#include <pthread.h>
#include <sys/time.h>
#include <sys/prctl.h>
#include "ocalls.h"
void occlum_ocall_gettimeofday(struct timeval *tv) {
@ -35,3 +36,8 @@ void occlum_ocall_rdtsc(uint32_t *low, uint32_t *high) {
*low = (uint32_t)rax;
*high = (uint32_t)rdx;
}
void occlum_ocall_get_timerslack(int *timer_slack) {
int nanoseconds = prctl(PR_GET_TIMERSLACK, 0, 0, 0, 0);
*timer_slack = nanoseconds;
}

@ -7,6 +7,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <occlum_pal_api.h>
#include <sys/prctl.h>
int main(int argc, char *argv[]) {
// Parse arguments

@ -126,6 +126,19 @@ static int test_prctl_get_default_thread_name(void) {
return 0;
}
static int test_prctl_get_timerslack(void) {
int nanoseconds = prctl(PR_GET_TIMERSLACK, 0, 0, 0, 0);
if (nanoseconds < 0) {
THROW_ERROR("test prctl get timer slack failed");
};
printf("timer slack = %d ns\n", nanoseconds);
// Kernel default timer slack is 50us
if (nanoseconds != 50000) {
THROW_ERROR("timer slack is not 50us");
}
return 0;
}
// ============================================================================
// Test suite main
// ============================================================================
@ -133,6 +146,7 @@ static test_case_t test_cases[] = {
TEST_CASE(test_prctl_set_get_long_name), // over 16 bytes
TEST_CASE(test_prctl_set_get_normal_name),
TEST_CASE(test_prctl_get_default_thread_name),
TEST_CASE(test_prctl_get_timerslack),
};
int main() {