Add sched_xetaffinity() system calls in Occlum
1. LibOS support sched_getaffinity() and sched_setaffinity() system calls 2. Add sched_cpu_affinity test cases in occlum/test/sched
This commit is contained in:
parent
03c19ae2c6
commit
cff0de1c39
@ -9,7 +9,7 @@ enclave {
|
|||||||
trusted {
|
trusted {
|
||||||
/* define ECALLs here. */
|
/* define ECALLs here. */
|
||||||
public int libos_boot([in, string] const char* executable_path, [user_check] const char** argv);
|
public int libos_boot([in, string] const char* executable_path, [user_check] const char** argv);
|
||||||
public int libos_run(void);
|
public int libos_run(int host_tid);
|
||||||
/* This is only for debug usage */
|
/* This is only for debug usage */
|
||||||
public int dummy_ecall(void);
|
public int dummy_ecall(void);
|
||||||
};
|
};
|
||||||
@ -20,5 +20,7 @@ enclave {
|
|||||||
void ocall_gettimeofday([out] long* sec, [out] long* us);
|
void ocall_gettimeofday([out] long* sec, [out] long* us);
|
||||||
void ocall_clock_gettime(int clockid, [out] long* sec, [out] long* ns);
|
void ocall_clock_gettime(int clockid, [out] long* sec, [out] long* ns);
|
||||||
void ocall_sync(void);
|
void ocall_sync(void);
|
||||||
|
int ocall_sched_getaffinity([out] int *error, int pid, size_t cpusize, [out, size=cpusize] unsigned char* buf);
|
||||||
|
int ocall_sched_setaffinity([out] int *error, int pid, size_t cpusize, [in, size=cpusize] const unsigned char* buf);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use process::pid_t;
|
||||||
use std::ffi::{CStr, CString, OsString};
|
use std::ffi::{CStr, CString, OsString};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use util::mem_util::from_untrusted::*;
|
use util::mem_util::from_untrusted::*;
|
||||||
@ -32,10 +33,10 @@ pub extern "C" fn libos_boot(path_buf: *const c_char, argv: *const *const c_char
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn libos_run() -> i32 {
|
pub extern "C" fn libos_run(host_tid: i32) -> i32 {
|
||||||
let _ = backtrace::enable_backtrace("libocclum.signed.so", PrintFormat::Short);
|
let _ = backtrace::enable_backtrace("libocclum.signed.so", PrintFormat::Short);
|
||||||
panic::catch_unwind(|| {
|
panic::catch_unwind(|| {
|
||||||
backtrace::__rust_begin_short_backtrace(|| match do_run() {
|
backtrace::__rust_begin_short_backtrace(|| match do_run(host_tid as pid_t) {
|
||||||
Ok(exit_status) => exit_status,
|
Ok(exit_status) => exit_status,
|
||||||
Err(err) => EXIT_STATUS_INTERNAL_ERROR,
|
Err(err) => EXIT_STATUS_INTERNAL_ERROR,
|
||||||
})
|
})
|
||||||
@ -91,8 +92,8 @@ fn do_boot(path_str: &str, argv: &Vec<CString>) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make sure do_run() cannot be called after do_boot()
|
// TODO: make sure do_run() cannot be called after do_boot()
|
||||||
fn do_run() -> Result<i32, Error> {
|
fn do_run(host_tid: pid_t) -> Result<i32, Error> {
|
||||||
let exit_status = process::run_task()?;
|
let exit_status = process::run_task(host_tid)?;
|
||||||
|
|
||||||
// sync file system
|
// sync file system
|
||||||
// TODO: only sync when all processes exit
|
// TODO: only sync when all processes exit
|
||||||
|
@ -7,6 +7,7 @@ pub use self::spawn::{do_spawn, FileAction};
|
|||||||
pub use self::task::{current_pid, get_current, run_task};
|
pub use self::task::{current_pid, get_current, run_task};
|
||||||
pub use self::thread::{do_clone, do_set_tid_address, CloneFlags, ThreadGroup};
|
pub use self::thread::{do_clone, do_set_tid_address, CloneFlags, ThreadGroup};
|
||||||
pub use self::wait::{WaitQueue, Waiter};
|
pub use self::wait::{WaitQueue, Waiter};
|
||||||
|
pub use self::sched::{CpuSet, do_sched_getaffinity, do_sched_setaffinity};
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub type pid_t = u32;
|
pub type pid_t = u32;
|
||||||
@ -18,6 +19,7 @@ pub struct Process {
|
|||||||
pid: pid_t,
|
pid: pid_t,
|
||||||
pgid: pid_t,
|
pgid: pid_t,
|
||||||
tgid: pid_t,
|
tgid: pid_t,
|
||||||
|
host_tid: pid_t,
|
||||||
exit_status: i32,
|
exit_status: i32,
|
||||||
// TODO: move cwd, root_inode into a FileSystem structure
|
// TODO: move cwd, root_inode into a FileSystem structure
|
||||||
// TODO: should cwd be a String or INode?
|
// TODO: should cwd be a String or INode?
|
||||||
@ -73,6 +75,7 @@ mod spawn;
|
|||||||
mod task;
|
mod task;
|
||||||
mod thread;
|
mod thread;
|
||||||
mod wait;
|
mod wait;
|
||||||
|
mod sched;
|
||||||
|
|
||||||
use self::task::Task;
|
use self::task::Task;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -12,6 +12,7 @@ lazy_static! {
|
|||||||
pid: 0,
|
pid: 0,
|
||||||
pgid: 1,
|
pgid: 1,
|
||||||
tgid: 0,
|
tgid: 0,
|
||||||
|
host_tid: 0,
|
||||||
exit_status: 0,
|
exit_status: 0,
|
||||||
cwd: "/".to_owned(),
|
cwd: "/".to_owned(),
|
||||||
clear_child_tid: None,
|
clear_child_tid: None,
|
||||||
@ -40,6 +41,7 @@ impl Process {
|
|||||||
pid: new_pid,
|
pid: new_pid,
|
||||||
pgid: 1, // TODO: implement pgid
|
pgid: 1, // TODO: implement pgid
|
||||||
tgid: new_pid,
|
tgid: new_pid,
|
||||||
|
host_tid: 0,
|
||||||
cwd: cwd.to_owned(),
|
cwd: cwd.to_owned(),
|
||||||
clear_child_tid: None,
|
clear_child_tid: None,
|
||||||
exit_status: 0,
|
exit_status: 0,
|
||||||
@ -70,6 +72,12 @@ impl Process {
|
|||||||
pub fn get_pgid(&self) -> pid_t {
|
pub fn get_pgid(&self) -> pid_t {
|
||||||
self.pgid
|
self.pgid
|
||||||
}
|
}
|
||||||
|
pub fn get_host_tid(&self) -> pid_t {
|
||||||
|
self.host_tid
|
||||||
|
}
|
||||||
|
pub fn set_host_tid(&mut self, host_tid: pid_t) {
|
||||||
|
self.host_tid = host_tid;
|
||||||
|
}
|
||||||
pub fn get_status(&self) -> Status {
|
pub fn get_status(&self) -> Status {
|
||||||
self.status
|
self.status
|
||||||
}
|
}
|
||||||
|
112
src/libos/src/process/sched.rs
Normal file
112
src/libos/src/process/sched.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn ocall_sched_getaffinity(ret: *mut i32, errno: *mut i32, pid: i32, cpusetsize: size_t, mask: *mut c_uchar) -> sgx_status_t;
|
||||||
|
fn ocall_sched_setaffinity(ret: *mut i32, errno: *mut i32, pid: i32, cpusetsize: size_t, mask: *const c_uchar) -> sgx_status_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CpuSet {
|
||||||
|
vec: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CpuSet {
|
||||||
|
pub fn new(len: usize) -> CpuSet {
|
||||||
|
let mut cpuset = CpuSet { vec: Vec::with_capacity(len) };
|
||||||
|
cpuset.vec.resize(len, 0);
|
||||||
|
cpuset
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_raw_buf(ptr: *const u8, cpusize: usize) -> CpuSet {
|
||||||
|
let mut cpuset = CpuSet { vec: Vec::with_capacity(cpusize) };
|
||||||
|
let buf_slice = unsafe { std::slice::from_raw_parts(ptr, cpusize) };
|
||||||
|
cpuset.vec.extend_from_slice(buf_slice);
|
||||||
|
cpuset
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_ptr(&mut self) -> *mut u8 {
|
||||||
|
self.vec.as_mut_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&self) -> *const u8 {
|
||||||
|
self.vec.as_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_slice(&mut self) -> &mut [u8] {
|
||||||
|
self.vec.as_mut_slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
|
self.vec.as_slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.vec.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::LowerHex for CpuSet {
|
||||||
|
fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||||
|
for byte in &(self.vec) {
|
||||||
|
try!(fmtr.write_fmt(format_args!("{:02x}", byte)));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::UpperHex for CpuSet {
|
||||||
|
fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||||
|
for byte in &(self.vec) {
|
||||||
|
try!(fmtr.write_fmt(format_args!("{:02X}", byte)));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_host_tid(pid: pid_t) -> Result<pid_t, Error> {
|
||||||
|
let process_ref = if pid == 0 {
|
||||||
|
get_current()
|
||||||
|
} else {
|
||||||
|
get(pid)?
|
||||||
|
};
|
||||||
|
let mut process = process_ref.lock().unwrap();
|
||||||
|
let host_tid = process.get_host_tid();
|
||||||
|
Ok(host_tid)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_sched_getaffinity(pid: pid_t, cpu_set: &mut CpuSet) -> Result<i32, Error> {
|
||||||
|
let host_tid = match pid {
|
||||||
|
0 => 0,
|
||||||
|
_ => find_host_tid(pid)?,
|
||||||
|
};
|
||||||
|
let buf = cpu_set.as_mut_ptr();
|
||||||
|
let cpusize = cpu_set.len();
|
||||||
|
let mut ret = 0;
|
||||||
|
let mut error = 0;
|
||||||
|
unsafe {
|
||||||
|
ocall_sched_getaffinity(&mut ret, &mut error, host_tid as i32, cpusize, buf);
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
let errno = Errno::from_errno(error);
|
||||||
|
return errno!(errno, "ocall_sched_getaffinity failed");
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_sched_setaffinity(pid: pid_t, cpu_set: &CpuSet) -> Result<i32, Error> {
|
||||||
|
let host_tid = match pid {
|
||||||
|
0 => 0,
|
||||||
|
_ => find_host_tid(pid)?,
|
||||||
|
};
|
||||||
|
let buf = cpu_set.as_ptr();
|
||||||
|
let cpusize = cpu_set.len();
|
||||||
|
let mut ret = 0;
|
||||||
|
let mut error = 0;
|
||||||
|
unsafe {
|
||||||
|
ocall_sched_setaffinity(&mut ret, &mut error, host_tid as i32, cpusize, buf);
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
let errno = Errno::from_errno(error);
|
||||||
|
return errno!(errno, "ocall_sched_setaffinity failed");
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
@ -72,13 +72,14 @@ fn dequeue_task() -> Option<ProcessRef> {
|
|||||||
NEW_PROCESS_QUEUE.lock().unwrap().pop_front()
|
NEW_PROCESS_QUEUE.lock().unwrap().pop_front()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_task() -> Result<i32, Error> {
|
pub fn run_task(host_tid: pid_t) -> Result<i32, Error> {
|
||||||
let new_process: ProcessRef =
|
let new_process: ProcessRef =
|
||||||
dequeue_task().ok_or_else(|| (Errno::EAGAIN, "No new processes to run"))?;
|
dequeue_task().ok_or_else(|| (Errno::EAGAIN, "No new processes to run"))?;
|
||||||
set_current(&new_process);
|
set_current(&new_process);
|
||||||
|
|
||||||
let (pid, task) = {
|
let (pid, task) = {
|
||||||
let mut process = new_process.lock().unwrap();
|
let mut process = new_process.lock().unwrap();
|
||||||
|
process.set_host_tid(host_tid);
|
||||||
let pid = process.get_pid();
|
let pid = process.get_pid();
|
||||||
let task = process.get_task_mut() as *mut Task;
|
let task = process.get_task_mut() as *mut Task;
|
||||||
(pid, task)
|
(pid, task)
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
use fs::*;
|
use fs::*;
|
||||||
use misc::{resource_t, rlimit_t, utsname_t};
|
use misc::{resource_t, rlimit_t, utsname_t};
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
use process::{pid_t, ChildProcessFilter, CloneFlags, FileAction, FutexFlags, FutexOp};
|
use process::{pid_t, ChildProcessFilter, CloneFlags, FileAction, FutexFlags, FutexOp, CpuSet};
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use time::{timeval_t, clockid_t, timespec_t};
|
use time::{timeval_t, clockid_t, timespec_t};
|
||||||
@ -175,6 +175,8 @@ pub extern "C" fn dispatch_syscall(
|
|||||||
),
|
),
|
||||||
SYS_ARCH_PRCTL => do_arch_prctl(arg0 as u32, arg1 as *mut usize),
|
SYS_ARCH_PRCTL => do_arch_prctl(arg0 as u32, arg1 as *mut usize),
|
||||||
SYS_SET_TID_ADDRESS => do_set_tid_address(arg0 as *mut pid_t),
|
SYS_SET_TID_ADDRESS => do_set_tid_address(arg0 as *mut pid_t),
|
||||||
|
SYS_SCHED_GETAFFINITY => do_sched_getaffinity(arg0 as pid_t, arg1 as size_t, arg2 as *mut c_uchar),
|
||||||
|
SYS_SCHED_SETAFFINITY => do_sched_setaffinity(arg0 as pid_t, arg1 as size_t, arg2 as *const c_uchar),
|
||||||
|
|
||||||
// memory
|
// memory
|
||||||
SYS_MMAP => do_mmap(
|
SYS_MMAP => do_mmap(
|
||||||
@ -960,6 +962,45 @@ fn do_set_tid_address(tidptr: *mut pid_t) -> Result<isize, Error> {
|
|||||||
process::do_set_tid_address(tidptr).map(|tid| tid as isize)
|
process::do_set_tid_address(tidptr).map(|tid| tid as isize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn do_sched_getaffinity(pid: pid_t, cpusize: size_t, buf: *mut c_uchar) -> Result<isize, Error> {
|
||||||
|
// Construct safe Rust types
|
||||||
|
let mut buf_slice = {
|
||||||
|
check_mut_array(buf, cpusize)?;
|
||||||
|
if cpusize == 0 {
|
||||||
|
return errno!(EINVAL, "cpuset size must be greater than zero");
|
||||||
|
}
|
||||||
|
if buf as *const _ == std::ptr::null() {
|
||||||
|
return errno!(EFAULT, "cpuset mask must NOT be null");
|
||||||
|
}
|
||||||
|
unsafe { std::slice::from_raw_parts_mut(buf, cpusize) }
|
||||||
|
};
|
||||||
|
// Call the memory-safe do_sched_getaffinity
|
||||||
|
let mut cpuset = CpuSet::new(cpusize);
|
||||||
|
let ret = process::do_sched_getaffinity(pid, &mut cpuset)?;
|
||||||
|
debug!("sched_getaffinity cpuset: {:#x}", cpuset);
|
||||||
|
// Copy from Rust types to C types
|
||||||
|
buf_slice.copy_from_slice(cpuset.as_slice());
|
||||||
|
Ok(ret as isize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_sched_setaffinity(pid: pid_t, cpusize: size_t, buf: *const c_uchar) -> Result<isize, Error> {
|
||||||
|
// Convert unsafe C types into safe Rust types
|
||||||
|
let cpuset = {
|
||||||
|
check_array(buf, cpusize)?;
|
||||||
|
if cpusize == 0 {
|
||||||
|
return errno!(EINVAL, "cpuset size must be greater than zero");
|
||||||
|
}
|
||||||
|
if buf as *const _ == std::ptr::null() {
|
||||||
|
return errno!(EFAULT, "cpuset mask must NOT be null");
|
||||||
|
}
|
||||||
|
CpuSet::from_raw_buf(buf, cpusize)
|
||||||
|
};
|
||||||
|
debug!("sched_setaffinity cpuset: {:#x}", cpuset);
|
||||||
|
// Call the memory-safe do_sched_setaffinity
|
||||||
|
let ret = process::do_sched_setaffinity(pid, &cpuset)?;
|
||||||
|
Ok(ret as isize)
|
||||||
|
}
|
||||||
|
|
||||||
fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result<isize, Error> {
|
fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result<isize, Error> {
|
||||||
info!(
|
info!(
|
||||||
"socket: domain: {}, socket_type: {}, protocol: {}",
|
"socket: domain: {}, socket_type: {}, protocol: {}",
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#define MAX_PATH FILENAME_MAX
|
#define MAX_PATH FILENAME_MAX
|
||||||
|
|
||||||
@ -213,6 +215,22 @@ void ocall_clock_gettime(int clockid, time_t* sec, long* ns) {
|
|||||||
*ns = ts.tv_nsec;
|
*ns = ts.tv_nsec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ocall_sched_getaffinity(int* error, int pid, size_t cpusize, unsigned char* buf) {
|
||||||
|
int ret = syscall(__NR_sched_getaffinity, pid, cpusize, buf);
|
||||||
|
if (error) {
|
||||||
|
*error = (ret == -1) ? errno : 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ocall_sched_setaffinity(int* error, int pid, size_t cpusize, const unsigned char* buf) {
|
||||||
|
int ret = syscall(__NR_sched_setaffinity, pid, cpusize, buf);
|
||||||
|
if (error) {
|
||||||
|
*error = (ret == -1) ? errno : 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void ocall_sync(void) {
|
void ocall_sync(void) {
|
||||||
sync();
|
sync();
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
#include "atomic.h"
|
#include "atomic.h"
|
||||||
#include "futex.h"
|
#include "futex.h"
|
||||||
#include "sgx_urts.h"
|
#include "sgx_urts.h"
|
||||||
#include "Enclave_u.h"
|
#include "Enclave_u.h"
|
||||||
|
|
||||||
|
int syscall();
|
||||||
|
#define gettid() syscall(__NR_gettid)
|
||||||
|
|
||||||
static volatile int num_tasks = 0;
|
static volatile int num_tasks = 0;
|
||||||
static volatile int main_task_status = 0;
|
static volatile int main_task_status = 0;
|
||||||
static volatile int any_fatal_error = 0;
|
static volatile int any_fatal_error = 0;
|
||||||
@ -29,7 +34,7 @@ static void* __run_task_thread(void* _data) {
|
|||||||
int status = 0;
|
int status = 0;
|
||||||
struct task_thread_data* data = _data;
|
struct task_thread_data* data = _data;
|
||||||
|
|
||||||
sgx_status_t sgx_ret = libos_run(data->eid, &status);
|
sgx_status_t sgx_ret = libos_run(data->eid, &status, gettid());
|
||||||
if(sgx_ret != SGX_SUCCESS) {
|
if(sgx_ret != SGX_SUCCESS) {
|
||||||
// TODO: deal with ECALL error
|
// TODO: deal with ECALL error
|
||||||
printf("ERROR: ECall libos_run failed\n");
|
printf("ERROR: ECall libos_run failed\n");
|
||||||
|
@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../)
|
|||||||
# Dependencies: need to be compiled but not to run by any Makefile target
|
# Dependencies: need to be compiled but not to run by any Makefile target
|
||||||
TEST_DEPS := dev_null
|
TEST_DEPS := dev_null
|
||||||
# Tests: need to be compiled and run by test-% target
|
# Tests: need to be compiled and run by test-% target
|
||||||
TESTS := empty env hello_world malloc mmap file getpid spawn pipe time \
|
TESTS := empty env hello_world malloc mmap file getpid spawn sched pipe time \
|
||||||
truncate readdir mkdir link tls pthread uname rlimit client server \
|
truncate readdir mkdir link tls pthread uname rlimit client server \
|
||||||
server_epoll unix_socket cout hostfs cpuid rdtsc device
|
server_epoll unix_socket cout hostfs cpuid rdtsc device
|
||||||
# Benchmarks: need to be compiled and run by bench-% target
|
# Benchmarks: need to be compiled and run by bench-% target
|
||||||
|
5
test/sched/Makefile
Normal file
5
test/sched/Makefile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
include ../test_common.mk
|
||||||
|
|
||||||
|
EXTRA_C_FLAGS :=
|
||||||
|
EXTRA_LINK_FLAGS :=
|
||||||
|
BIN_ARGS :=
|
175
test/sched/main.c
Normal file
175
test/sched/main.c
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <spawn.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Test cases for sched_cpu_affinity
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static int test_sched_getaffinity_with_self_pid() {
|
||||||
|
cpu_set_t mask;
|
||||||
|
if (sched_getaffinity(0, sizeof(cpu_set_t), &mask) < 0) {
|
||||||
|
throw_error("failed to call sched_getaffinity");
|
||||||
|
}
|
||||||
|
if (CPU_COUNT(&mask) <= 0) {
|
||||||
|
throw_error("failed to get cpuset mask");
|
||||||
|
}
|
||||||
|
if (sysconf(_SC_NPROCESSORS_ONLN) != CPU_COUNT(&mask)) {
|
||||||
|
throw_error("cpuset num wrong");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_sched_setaffinity_with_self_pid() {
|
||||||
|
int nproc = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
cpu_set_t mask_old;
|
||||||
|
for (int i = 0; i < nproc; ++i) {
|
||||||
|
CPU_SET(i, &mask_old);
|
||||||
|
}
|
||||||
|
cpu_set_t mask;
|
||||||
|
CPU_ZERO(&mask);
|
||||||
|
CPU_SET(0, &mask);
|
||||||
|
if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) < 0) {
|
||||||
|
throw_error("failed to call sched_setaffinity \n");
|
||||||
|
}
|
||||||
|
cpu_set_t mask2;
|
||||||
|
if (sched_getaffinity(0, sizeof(cpu_set_t), &mask2) < 0) {
|
||||||
|
throw_error("failed to call sched_getaffinity");
|
||||||
|
}
|
||||||
|
if (!CPU_EQUAL(&mask, &mask2)) {
|
||||||
|
throw_error("cpuset is wrong after get");
|
||||||
|
}
|
||||||
|
if (sched_setaffinity(0, sizeof(cpu_set_t), &mask_old) < 0) {
|
||||||
|
throw_error("recover cpuset error");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_sched_xetaffinity_with_child_pid() {
|
||||||
|
int status, child_pid;
|
||||||
|
int num = sysconf(_SC_NPROCESSORS_CONF);
|
||||||
|
if (num <= 0) {
|
||||||
|
throw_error("failed to get cpu number");
|
||||||
|
}
|
||||||
|
cpu_set_t mask;
|
||||||
|
CPU_ZERO(&mask);
|
||||||
|
CPU_SET(num - 1 , &mask);
|
||||||
|
int ret = posix_spawn(&child_pid, "getpid", NULL, NULL, NULL, NULL);
|
||||||
|
if (ret < 0 ) {
|
||||||
|
throw_error("spawn process error");
|
||||||
|
}
|
||||||
|
printf("Spawn a child process with pid=%d\n", child_pid);
|
||||||
|
if (sched_setaffinity(child_pid, sizeof(cpu_set_t), &mask) < 0) {
|
||||||
|
throw_error("failed to set child affinity");
|
||||||
|
}
|
||||||
|
cpu_set_t mask2;
|
||||||
|
if (sched_getaffinity(child_pid, sizeof(cpu_set_t), &mask2) < 0) {
|
||||||
|
throw_error("failed to get child affinity");
|
||||||
|
}
|
||||||
|
if (!CPU_EQUAL(&mask, &mask2)) {
|
||||||
|
throw_error("cpuset is wrong in child");
|
||||||
|
}
|
||||||
|
ret = wait4(-1, &status, 0, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
throw_error("failed to wait4 the child proces");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CPU_SET_SIZE_LIMIT (1024)
|
||||||
|
|
||||||
|
static int test_sched_getaffinity_via_explicit_syscall() {
|
||||||
|
unsigned char buf[CPU_SET_SIZE_LIMIT] = { 0 };
|
||||||
|
int ret = syscall(__NR_sched_getaffinity, 0, CPU_SET_SIZE_LIMIT, buf);
|
||||||
|
if (ret <= 0) {
|
||||||
|
throw_error("failed to call __NR_sched_getaffinity");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_sched_setaffinity_via_explicit_syscall() {
|
||||||
|
int nproc = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
cpu_set_t mask_old;
|
||||||
|
for (int i = 0; i < nproc; ++i) {
|
||||||
|
CPU_SET(i, &mask_old);
|
||||||
|
}
|
||||||
|
cpu_set_t mask;
|
||||||
|
CPU_ZERO(&mask);
|
||||||
|
CPU_SET(0, &mask);
|
||||||
|
if (syscall(__NR_sched_setaffinity, 0, sizeof(cpu_set_t), &mask) < 0) {
|
||||||
|
throw_error("failed to call __NR_sched_setaffinity");
|
||||||
|
}
|
||||||
|
cpu_set_t mask2;
|
||||||
|
int ret_nproc = syscall(__NR_sched_getaffinity, 0, sizeof(cpu_set_t), &mask2);
|
||||||
|
if (ret_nproc <= 0) {
|
||||||
|
throw_error("failed to call __NR_sched_getaffinity");
|
||||||
|
}
|
||||||
|
if (!CPU_EQUAL(&mask, &mask2)) {
|
||||||
|
throw_error("explicit syscall cpuset is wrong");
|
||||||
|
}
|
||||||
|
if (syscall(__NR_sched_setaffinity, 0, sizeof(cpu_set_t), &mask_old) < 0) {
|
||||||
|
throw_error("recover cpuset error");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_sched_getaffinity_with_zero_cpusetsize() {
|
||||||
|
cpu_set_t mask;
|
||||||
|
if (sched_getaffinity(0, 0, &mask) != -1) {
|
||||||
|
throw_error("check invalid cpusetsize(0) fail");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_sched_setaffinity_with_zero_cpusetsize() {
|
||||||
|
cpu_set_t mask;
|
||||||
|
if (sched_setaffinity(0, 0, &mask) != -1) {
|
||||||
|
throw_error("check invalid cpusetsize(0) fail");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_sched_getaffinity_with_null_buffer() {
|
||||||
|
unsigned char *buf = NULL;
|
||||||
|
if (sched_getaffinity(0, sizeof(cpu_set_t), (cpu_set_t*)buf) != -1) {
|
||||||
|
throw_error("check invalid buffer pointer(NULL) fail");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_sched_setaffinity_with_null_buffer() {
|
||||||
|
unsigned char *buf = NULL;
|
||||||
|
if (sched_setaffinity(0, sizeof(cpu_set_t), (cpu_set_t*)buf) != -1) {
|
||||||
|
throw_error("check invalid buffer pointer(NULL) fail");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Test suite main
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static test_case_t test_cases[] = {
|
||||||
|
TEST_CASE(test_sched_xetaffinity_with_child_pid),
|
||||||
|
TEST_CASE(test_sched_getaffinity_with_self_pid),
|
||||||
|
TEST_CASE(test_sched_setaffinity_with_self_pid),
|
||||||
|
TEST_CASE(test_sched_getaffinity_via_explicit_syscall),
|
||||||
|
TEST_CASE(test_sched_setaffinity_via_explicit_syscall),
|
||||||
|
TEST_CASE(test_sched_getaffinity_with_zero_cpusetsize),
|
||||||
|
TEST_CASE(test_sched_setaffinity_with_zero_cpusetsize),
|
||||||
|
TEST_CASE(test_sched_getaffinity_with_null_buffer),
|
||||||
|
TEST_CASE(test_sched_setaffinity_with_null_buffer),
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
return test_suite_run(test_cases, ARRAY_SIZE(test_cases));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user