Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/sys/linux/sched.rs
5394 views
1
// Copyright 2019 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
//! Wrappers for CPU affinity functions.
6
7
use std::iter::FromIterator;
8
use std::mem;
9
10
use libc::cpu_set_t;
11
use libc::prctl;
12
use libc::sched_getaffinity;
13
use libc::sched_setaffinity;
14
use libc::CPU_ISSET;
15
use libc::CPU_SET;
16
use libc::CPU_SETSIZE;
17
use libc::CPU_ZERO;
18
use libc::EINVAL;
19
20
use super::Error;
21
use super::Result;
22
23
// This is needed because otherwise the compiler will complain that the
24
// impl doesn't reference any types from inside this crate.
25
struct CpuSet(cpu_set_t);
26
27
impl CpuSet {
28
pub fn new() -> CpuSet {
29
// SAFETY:
30
// cpu_set_t is a C struct and can be safely initialized with zeroed memory.
31
let mut cpuset: cpu_set_t = unsafe { mem::MaybeUninit::zeroed().assume_init() };
32
// SAFETY:
33
// Safe because we pass a valid cpuset pointer.
34
unsafe { CPU_ZERO(&mut cpuset) };
35
CpuSet(cpuset)
36
}
37
38
#[allow(clippy::unnecessary_cast)]
39
pub fn to_cpus(&self) -> Vec<usize> {
40
let mut cpus = Vec::new();
41
for i in 0..(CPU_SETSIZE as usize) {
42
// SAFETY: Safe because `i` and `self.0` are valid.
43
if unsafe { CPU_ISSET(i, &self.0) } {
44
cpus.push(i);
45
}
46
}
47
cpus
48
}
49
}
50
51
impl FromIterator<usize> for CpuSet {
52
fn from_iter<I: IntoIterator<Item = usize>>(cpus: I) -> Self {
53
let mut cpuset = CpuSet::new();
54
for cpu in cpus {
55
// SAFETY:
56
// Safe because we pass a valid cpu index and cpuset.0 is a valid pointer.
57
unsafe { CPU_SET(cpu, &mut cpuset.0) };
58
}
59
cpuset
60
}
61
}
62
63
/// Set the CPU affinity of the current thread to a given set of CPUs.
64
///
65
/// # Examples
66
///
67
/// Set the calling thread's CPU affinity so it will run on only CPUs
68
/// 0, 1, 5, and 6.
69
///
70
/// ```
71
/// # use base::linux::set_cpu_affinity;
72
/// set_cpu_affinity(vec![0, 1, 5, 6]).unwrap();
73
/// ```
74
#[allow(clippy::unnecessary_cast)]
75
pub fn set_cpu_affinity<I: IntoIterator<Item = usize>>(cpus: I) -> Result<()> {
76
let CpuSet(cpuset) = cpus
77
.into_iter()
78
.map(|cpu| {
79
if cpu < CPU_SETSIZE as usize {
80
Ok(cpu)
81
} else {
82
Err(Error::new(EINVAL))
83
}
84
})
85
.collect::<Result<CpuSet>>()?;
86
87
// SAFETY:
88
// Safe because we pass 0 for the current thread, and cpuset is a valid pointer and only
89
// used for the duration of this call.
90
crate::syscall!(unsafe { sched_setaffinity(0, mem::size_of_val(&cpuset), &cpuset) })?;
91
92
Ok(())
93
}
94
95
pub fn get_cpu_affinity() -> Result<Vec<usize>> {
96
let mut cpu_set = CpuSet::new();
97
98
// SAFETY:
99
// Safe because we pass 0 for the current thread, and cpu_set.0 is a valid pointer and only
100
// used for the duration of this call.
101
crate::syscall!(unsafe { sched_getaffinity(0, mem::size_of_val(&cpu_set.0), &mut cpu_set.0) })?;
102
103
Ok(cpu_set.to_cpus())
104
}
105
106
/// Enable experimental core scheduling for the current thread.
107
///
108
/// If successful, the kernel should not schedule this thread with any other thread within the same
109
/// SMT core. Because this is experimental, this will return success on kernels which do not support
110
/// this function.
111
pub fn enable_core_scheduling() -> Result<()> {
112
const PR_SCHED_CORE: i32 = 62;
113
const PR_SCHED_CORE_CREATE: i32 = 1;
114
115
#[allow(clippy::upper_case_acronyms, non_camel_case_types, dead_code)]
116
/// Specifies the scope of the pid parameter of `PR_SCHED_CORE`.
117
enum pid_type {
118
/// `PID` refers to threads.
119
PIDTYPE_PID,
120
/// `TGPID` refers to a process.
121
PIDTYPE_TGID,
122
/// `TGPID` refers to a process group.
123
PIDTYPE_PGID,
124
}
125
126
// SAFETY: Safe because we check the return value to prctl.
127
let ret = unsafe {
128
prctl(
129
PR_SCHED_CORE,
130
PR_SCHED_CORE_CREATE,
131
0, // id of target task, 0 indicates current task
132
pid_type::PIDTYPE_PID as i32, // PID scopes to this thread only
133
0, // ignored by PR_SCHED_CORE_CREATE command
134
)
135
};
136
if ret == -1 {
137
let error = Error::last();
138
// prctl returns EINVAL for unknown functions, which we will ignore for now.
139
if error.errno() != libc::EINVAL {
140
return Err(error);
141
}
142
}
143
Ok(())
144
}
145
146