sys_util: Add the interface to get CPU affinity

At present we only have a interface to set the CPU affinity and don't
implement the 'get_cpu_affinity' interface.

With a 'get_cpu_affinity' interface, after the thread iterates through
all physical CPUs by setting CPU affinity, it can reset its original CPU
affinity that was obtained and stored through 'get_cpu_affinity' in
advance.

BUG=None
TEST=cargo build
TEST=./test_all
TEST=set the CPU affinity and check the return value of
  'get_cpu_affinity'

Change-Id: I169fbbbb141ca80c980900ed16e4bceed1ba6432
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3217032
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Chirantan Ekbote <chirantan@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
This commit is contained in:
ZhaoLiu 2021-10-10 17:02:49 +08:00 committed by Commit Bot
parent 81d454515f
commit 952feb761d

View file

@ -7,7 +7,10 @@
use std::iter::FromIterator;
use std::mem;
use libc::{cpu_set_t, prctl, sched_setaffinity, CPU_SET, CPU_SETSIZE, CPU_ZERO, EINVAL};
use libc::{
cpu_set_t, prctl, sched_getaffinity, sched_setaffinity, CPU_ISSET, CPU_SET, CPU_SETSIZE,
CPU_ZERO, EINVAL,
};
use crate::{errno_result, Error, Result};
@ -15,6 +18,26 @@ use crate::{errno_result, Error, Result};
// impl doesn't reference any types from inside this crate.
struct CpuSet(cpu_set_t);
impl CpuSet {
pub fn new() -> CpuSet {
// cpu_set_t is a C struct and can be safely initialized with zeroed memory.
let mut cpuset: cpu_set_t = unsafe { mem::MaybeUninit::zeroed().assume_init() };
// Safe because we pass a valid cpuset pointer.
unsafe { CPU_ZERO(&mut cpuset) };
CpuSet(cpuset)
}
pub fn to_cpus(&self) -> Vec<usize> {
let mut cpus = Vec::new();
for i in 0..(CPU_SETSIZE as usize) {
if unsafe { CPU_ISSET(i, &self.0) } {
cpus.push(i);
}
}
cpus
}
}
impl FromIterator<usize> for CpuSet {
fn from_iter<I: IntoIterator<Item = usize>>(cpus: I) -> Self {
// cpu_set_t is a C struct and can be safely initialized with zeroed memory.
@ -63,6 +86,16 @@ pub fn set_cpu_affinity<I: IntoIterator<Item = usize>>(cpus: I) -> Result<()> {
}
}
pub fn get_cpu_affinity() -> Result<Vec<usize>> {
let mut cpu_set = CpuSet::new();
// Safe because we pass 0 for the current thread, and cpu_set.0 is a valid pointer and only
// used for the duration of this call.
crate::syscall!(unsafe { sched_getaffinity(0, mem::size_of_val(&cpu_set.0), &mut cpu_set.0) })?;
Ok(cpu_set.to_cpus())
}
/// Enable experimental core scheduling for the current thread.
///
/// If successful, the kernel should not schedule this thread with any other thread within the same