Add setpriority and getpriority syscall
This commit is contained in:
parent
e3a0233c46
commit
96166dadc2
@ -48,6 +48,7 @@ pub fn do_clone(
|
||||
}
|
||||
};
|
||||
let files = current.files().clone();
|
||||
let nice = current.nice().clone();
|
||||
let rlimits = current.rlimits().clone();
|
||||
let fs = current.fs().clone();
|
||||
let name = current.name().clone();
|
||||
@ -60,6 +61,7 @@ pub fn do_clone(
|
||||
.fs(fs)
|
||||
.files(files)
|
||||
.name(name)
|
||||
.nice(nice)
|
||||
.rlimits(rlimits)
|
||||
.sig_mask(sig_mask);
|
||||
if let Some(ctid) = ctid {
|
||||
|
@ -257,6 +257,7 @@ fn new_process_common(
|
||||
};
|
||||
let fs_ref = Arc::new(RwLock::new(current_ref.fs().read().unwrap().clone()));
|
||||
let sched_ref = Arc::new(SgxMutex::new(current_ref.sched().lock().unwrap().clone()));
|
||||
let nice_ref = Arc::new(RwLock::new(current_ref.nice().read().unwrap().clone()));
|
||||
let rlimit_ref = Arc::new(SgxMutex::new(current_ref.rlimits().lock().unwrap().clone()));
|
||||
let sig_mask = if spawn_attributes.is_some() && spawn_attributes.unwrap().sig_mask.is_some()
|
||||
{
|
||||
@ -311,6 +312,7 @@ fn new_process_common(
|
||||
.parent(parent)
|
||||
.task(task)
|
||||
.sched(sched_ref)
|
||||
.nice(nice_ref)
|
||||
.rlimits(rlimit_ref)
|
||||
.fs(fs_ref)
|
||||
.pgrp(pgrp_ref)
|
||||
|
@ -12,7 +12,7 @@
|
||||
use crate::fs::{FileRef, FileTable, FsView};
|
||||
use crate::misc::ResourceLimits;
|
||||
use crate::prelude::*;
|
||||
use crate::sched::SchedAgent;
|
||||
use crate::sched::{NiceValue, SchedAgent};
|
||||
use crate::signal::{SigDispositions, SigQueues};
|
||||
use crate::vm::ProcessVM;
|
||||
|
||||
@ -80,3 +80,4 @@ pub type FsViewRef = Arc<RwLock<FsView>>;
|
||||
pub type SchedAgentRef = Arc<SgxMutex<SchedAgent>>;
|
||||
pub type ResourceLimitsRef = Arc<SgxMutex<ResourceLimits>>;
|
||||
pub type ProcessGrpRef = Arc<ProcessGrp>;
|
||||
pub type NiceValueRef = Arc<RwLock<NiceValue>>;
|
||||
|
@ -2,8 +2,8 @@ use super::super::table;
|
||||
use super::super::task::Task;
|
||||
use super::super::thread::{ThreadBuilder, ThreadId, ThreadName};
|
||||
use super::super::{
|
||||
FileTableRef, ForcedExitStatus, FsViewRef, ProcessGrpRef, ProcessRef, ProcessVMRef,
|
||||
ResourceLimitsRef, SchedAgentRef,
|
||||
FileTableRef, ForcedExitStatus, FsViewRef, NiceValueRef, ProcessGrpRef, ProcessRef,
|
||||
ProcessVMRef, ResourceLimitsRef, SchedAgentRef,
|
||||
};
|
||||
use super::{Process, ProcessInner};
|
||||
use crate::fs::FileMode;
|
||||
@ -100,6 +100,10 @@ impl ProcessBuilder {
|
||||
self.thread_builder(|tb| tb.sig_mask(sig_mask))
|
||||
}
|
||||
|
||||
pub fn nice(mut self, nice: NiceValueRef) -> Self {
|
||||
self.thread_builder(|tb| tb.nice(nice))
|
||||
}
|
||||
|
||||
pub fn rlimits(mut self, rlimits: ResourceLimitsRef) -> Self {
|
||||
self.thread_builder(|tb| tb.rlimits(rlimits))
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::ptr::NonNull;
|
||||
|
||||
use super::{
|
||||
FileTableRef, FsViewRef, ProcessRef, ProcessVM, ProcessVMRef, ResourceLimitsRef,
|
||||
FileTableRef, FsViewRef, NiceValueRef, ProcessRef, ProcessVM, ProcessVMRef, ResourceLimitsRef,
|
||||
RobustListHead, SchedAgentRef, SigQueues, SigSet, Task, Thread, ThreadId, ThreadInner,
|
||||
ThreadName, ThreadRef,
|
||||
};
|
||||
@ -20,6 +20,7 @@ pub struct ThreadBuilder {
|
||||
fs: Option<FsViewRef>,
|
||||
files: Option<FileTableRef>,
|
||||
sched: Option<SchedAgentRef>,
|
||||
nice: Option<NiceValueRef>,
|
||||
rlimits: Option<ResourceLimitsRef>,
|
||||
sig_mask: Option<SigSet>,
|
||||
clear_ctid: Option<NonNull<pid_t>>,
|
||||
@ -37,6 +38,7 @@ impl ThreadBuilder {
|
||||
fs: None,
|
||||
files: None,
|
||||
sched: None,
|
||||
nice: None,
|
||||
rlimits: None,
|
||||
sig_mask: None,
|
||||
clear_ctid: None,
|
||||
@ -85,6 +87,11 @@ impl ThreadBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn nice(mut self, nice: NiceValueRef) -> Self {
|
||||
self.nice = Some(nice);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rlimits(mut self, rlimits: ResourceLimitsRef) -> Self {
|
||||
self.rlimits = Some(rlimits);
|
||||
self
|
||||
@ -122,6 +129,7 @@ impl ThreadBuilder {
|
||||
let fs = self.fs.unwrap_or_default();
|
||||
let files = self.files.unwrap_or_default();
|
||||
let sched = self.sched.unwrap_or_default();
|
||||
let nice = self.nice.unwrap_or_default();
|
||||
let rlimits = self.rlimits.unwrap_or_default();
|
||||
let name = RwLock::new(self.name.unwrap_or_default());
|
||||
let sig_mask = RwLock::new(self.sig_mask.unwrap_or_default());
|
||||
@ -147,6 +155,7 @@ impl ThreadBuilder {
|
||||
fs,
|
||||
files,
|
||||
sched,
|
||||
nice,
|
||||
rlimits,
|
||||
name,
|
||||
sig_queues,
|
||||
|
@ -3,7 +3,7 @@ use std::ptr::NonNull;
|
||||
|
||||
use super::task::Task;
|
||||
use super::{
|
||||
FileTableRef, ForcedExitStatus, FsViewRef, ProcessRef, ProcessVM, ProcessVMRef,
|
||||
FileTableRef, ForcedExitStatus, FsViewRef, NiceValueRef, ProcessRef, ProcessVM, ProcessVMRef,
|
||||
ResourceLimitsRef, RobustListHead, SchedAgentRef, TermStatus, ThreadRef,
|
||||
};
|
||||
use crate::events::HostEventFd;
|
||||
@ -38,6 +38,7 @@ pub struct Thread {
|
||||
fs: FsViewRef,
|
||||
files: FileTableRef,
|
||||
sched: SchedAgentRef,
|
||||
nice: NiceValueRef,
|
||||
rlimits: ResourceLimitsRef,
|
||||
// Signal
|
||||
sig_queues: RwLock<SigQueues>,
|
||||
@ -156,6 +157,10 @@ impl Thread {
|
||||
&self.fs
|
||||
}
|
||||
|
||||
pub fn nice(&self) -> &NiceValueRef {
|
||||
&self.nice
|
||||
}
|
||||
|
||||
pub fn rlimits(&self) -> &ResourceLimitsRef {
|
||||
&self.rlimits
|
||||
}
|
||||
|
71
src/libos/src/sched/do_priority.rs
Normal file
71
src/libos/src/sched/do_priority.rs
Normal file
@ -0,0 +1,71 @@
|
||||
use super::priority::{NiceValue, PrioWhich};
|
||||
use crate::prelude::*;
|
||||
use crate::process::table::{get_all_processes, get_pgrp, get_process};
|
||||
|
||||
pub fn do_set_priority(which: PrioWhich, who: i32, prio: NiceValue) -> Result<()> {
|
||||
debug!(
|
||||
"set_priority: which: {:?}, who: {}, prio: {:?}",
|
||||
which, who, prio
|
||||
);
|
||||
|
||||
let processes = get_processes(which, who)?;
|
||||
for process in processes.iter() {
|
||||
let main_thread = process
|
||||
.main_thread()
|
||||
.ok_or_else(|| errno!(ESRCH, "invalid pid"))?;
|
||||
*main_thread.nice().write().unwrap() = prio;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn do_get_priority(which: PrioWhich, who: i32) -> Result<NiceValue> {
|
||||
debug!("get_priority: which: {:?}, who: {}", which, who);
|
||||
|
||||
let processes = get_processes(which, who)?;
|
||||
let prio = {
|
||||
let mut prio = NiceValue::max_value();
|
||||
for process in processes.iter() {
|
||||
let main_thread = process
|
||||
.main_thread()
|
||||
.ok_or_else(|| errno!(ESRCH, "invalid pid"))?;
|
||||
let nice_value = main_thread.nice().read().unwrap();
|
||||
// Returns the highest priority enjoyed by the processes
|
||||
if *nice_value < prio {
|
||||
prio = *nice_value;
|
||||
}
|
||||
}
|
||||
prio
|
||||
};
|
||||
Ok(prio)
|
||||
}
|
||||
|
||||
// According to POSIX, the nice value is a per-process setting.
|
||||
// In our implementation, the threads belong to same process share the same nice value.
|
||||
fn get_processes(which: PrioWhich, who: i32) -> Result<Vec<crate::process::ProcessRef>> {
|
||||
Ok(match which {
|
||||
PrioWhich::PRIO_PROCESS => {
|
||||
let process = if who == 0 {
|
||||
current!().process().clone()
|
||||
} else {
|
||||
get_process(who as pid_t)?
|
||||
};
|
||||
vec![process]
|
||||
}
|
||||
PrioWhich::PRIO_PGRP => {
|
||||
let pgrp = if who == 0 {
|
||||
current!().process().pgrp()
|
||||
} else {
|
||||
get_pgrp(who as pid_t)?
|
||||
};
|
||||
pgrp.get_all_processes()
|
||||
}
|
||||
PrioWhich::PRIO_USER => {
|
||||
if who == 0 {
|
||||
get_all_processes()
|
||||
} else {
|
||||
warn!("only root user is supported in Occlum");
|
||||
return_errno!(ESRCH, "no such user");
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
@ -1,11 +1,14 @@
|
||||
/// CPU scheduling for threads.
|
||||
mod cpu_set;
|
||||
mod do_getcpu;
|
||||
mod do_priority;
|
||||
mod do_sched_affinity;
|
||||
mod do_sched_yield;
|
||||
mod priority;
|
||||
mod sched_agent;
|
||||
mod syscalls;
|
||||
|
||||
pub use cpu_set::NCORES;
|
||||
pub use priority::NiceValue;
|
||||
pub use sched_agent::SchedAgent;
|
||||
pub use syscalls::*;
|
||||
|
66
src/libos/src/sched/priority.rs
Normal file
66
src/libos/src/sched/priority.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use crate::prelude::*;
|
||||
use core::convert::TryFrom;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum PrioWhich {
|
||||
PRIO_PROCESS = 0,
|
||||
PRIO_PGRP = 1,
|
||||
PRIO_USER = 2,
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for PrioWhich {
|
||||
type Error = crate::error::Error;
|
||||
|
||||
fn try_from(raw: i32) -> Result<Self> {
|
||||
if raw > Self::PRIO_USER as i32 || raw < Self::PRIO_PROCESS as i32 {
|
||||
return_errno!(EINVAL, "invalid which value");
|
||||
}
|
||||
Ok(unsafe { core::mem::transmute(raw as u8) })
|
||||
}
|
||||
}
|
||||
|
||||
/// Process priority value
|
||||
///
|
||||
/// Lower values give a process a higher scheduling priority.
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)]
|
||||
pub struct NiceValue {
|
||||
value: i32,
|
||||
}
|
||||
|
||||
impl NiceValue {
|
||||
const MAX_PRIO: i32 = 19;
|
||||
|
||||
const MIN_PRIO: i32 = -20;
|
||||
|
||||
pub fn max_value() -> Self {
|
||||
Self {
|
||||
value: Self::MAX_PRIO,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn min_value() -> Self {
|
||||
Self {
|
||||
value: Self::MIN_PRIO,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert [19,-20] to rlimit style value [1,40].
|
||||
pub fn to_rlimit_val(&self) -> i32 {
|
||||
Self::MAX_PRIO - self.value + 1
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for NiceValue {
|
||||
fn from(raw: i32) -> Self {
|
||||
let value = if raw < Self::MIN_PRIO {
|
||||
Self::MIN_PRIO
|
||||
} else if raw > Self::MAX_PRIO {
|
||||
Self::MAX_PRIO
|
||||
} else {
|
||||
raw
|
||||
};
|
||||
Self { value }
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
use super::cpu_set::{CpuSet, AVAIL_CPUSET};
|
||||
use super::priority::{NiceValue, PrioWhich};
|
||||
use crate::prelude::*;
|
||||
use crate::util::mem_util::from_user::*;
|
||||
use core::convert::TryFrom;
|
||||
|
||||
pub fn do_sched_yield() -> Result<isize> {
|
||||
super::do_sched_yield::do_sched_yield();
|
||||
@ -78,3 +80,19 @@ pub fn do_getcpu(cpu_ptr: *mut u32, node_ptr: *mut u32) -> Result<isize> {
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn do_set_priority(which: i32, who: i32, prio: i32) -> Result<isize> {
|
||||
let which = PrioWhich::try_from(which)?;
|
||||
let prio = NiceValue::from(prio);
|
||||
super::do_priority::do_set_priority(which, who, prio)?;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn do_get_priority(which: i32, who: i32) -> Result<isize> {
|
||||
let which = PrioWhich::try_from(which)?;
|
||||
let prio = super::do_priority::do_get_priority(which, who)?;
|
||||
// To avoid negative return values, "getpriority()" will
|
||||
// not return the normal nice-value, but a negated value that
|
||||
// has been offset by 20 (ie it returns 40..1 instead of -20..19)
|
||||
Ok(prio.to_rlimit_val() as isize)
|
||||
}
|
||||
|
@ -50,7 +50,10 @@ use crate::process::{
|
||||
do_spawn_for_glibc, do_spawn_for_musl, do_vfork, do_wait4, pid_t, posix_spawnattr_t, FdOp,
|
||||
RobustListHead, SpawnFileActions, ThreadStatus,
|
||||
};
|
||||
use crate::sched::{do_getcpu, do_sched_getaffinity, do_sched_setaffinity, do_sched_yield};
|
||||
use crate::sched::{
|
||||
do_get_priority, do_getcpu, do_sched_getaffinity, do_sched_setaffinity, do_sched_yield,
|
||||
do_set_priority,
|
||||
};
|
||||
use crate::signal::{
|
||||
do_kill, do_rt_sigaction, do_rt_sigpending, do_rt_sigprocmask, do_rt_sigreturn,
|
||||
do_rt_sigtimedwait, do_sigaltstack, do_tgkill, do_tkill, sigaction_t, siginfo_t, sigset_t,
|
||||
@ -230,8 +233,8 @@ macro_rules! process_syscall_table_with_callback {
|
||||
(Statfs = 137) => do_statfs(path: *const i8, statfs_buf: *mut Statfs),
|
||||
(Fstatfs = 138) => do_fstatfs(fd: FileDesc, statfs_buf: *mut Statfs),
|
||||
(SysFs = 139) => handle_unsupported(),
|
||||
(Getpriority = 140) => handle_unsupported(),
|
||||
(Setpriority = 141) => handle_unsupported(),
|
||||
(Getpriority = 140) => do_get_priority(which: i32, who: i32),
|
||||
(Setpriority = 141) => do_set_priority(which: i32, who: i32, prio: i32),
|
||||
(SchedSetparam = 142) => handle_unsupported(),
|
||||
(SchedGetparam = 143) => handle_unsupported(),
|
||||
(SchedSetscheduler = 144) => handle_unsupported(),
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <sched.h>
|
||||
#include <errno.h>
|
||||
#include <spawn.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include "test.h"
|
||||
@ -303,6 +304,58 @@ static int test_getcpu_after_setaffinity() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Test cases for setpriority and getpriority
|
||||
// ============================================================================
|
||||
|
||||
static int test_set_get_priority(int which, id_t who, int prio) {
|
||||
if (setpriority(which, who, prio) < 0) {
|
||||
THROW_ERROR("failed to setpriority");
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
int ret_prio = getpriority(which, who);
|
||||
if (errno != 0) {
|
||||
THROW_ERROR("failed to getpriority");
|
||||
}
|
||||
|
||||
if (ret_prio != prio) {
|
||||
THROW_ERROR("failed to check prio after set");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_set_get_priority_process() {
|
||||
int which = PRIO_PROCESS;
|
||||
id_t who = getpid();
|
||||
int prio = 10;
|
||||
if (test_set_get_priority(which, who, prio) < 0) {
|
||||
THROW_ERROR("failed to test process");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_set_get_priority_pgrp() {
|
||||
int which = PRIO_PGRP;
|
||||
id_t who = getpgrp();
|
||||
int prio = -10;
|
||||
if (test_set_get_priority(which, who, prio) < 0) {
|
||||
THROW_ERROR("failed to test pgrp");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_set_get_priority_user() {
|
||||
int which = PRIO_USER;
|
||||
id_t who = 0;
|
||||
int prio = -1;
|
||||
if (test_set_get_priority(which, who, prio) < 0) {
|
||||
THROW_ERROR("failed to test user");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Test suite main
|
||||
// ============================================================================
|
||||
@ -321,6 +374,9 @@ static test_case_t test_cases[] = {
|
||||
TEST_CASE(test_sched_xetaffinity_children_inheritance),
|
||||
TEST_CASE(test_getcpu),
|
||||
TEST_CASE(test_getcpu_after_setaffinity),
|
||||
TEST_CASE(test_set_get_priority_process),
|
||||
TEST_CASE(test_set_get_priority_pgrp),
|
||||
TEST_CASE(test_set_get_priority_user),
|
||||
};
|
||||
|
||||
int main() {
|
||||
|
Loading…
Reference in New Issue
Block a user