indexbus_platform_ops/
cpu.rs1use crate::errors::{Error, Result};
12
13pub fn current_thread_allowed_cpus() -> Result<Vec<usize>> {
17 #[cfg(target_os = "linux")]
18 {
19 let mut set: libc::cpu_set_t = unsafe { std::mem::zeroed() };
20 let rc =
21 unsafe { libc::sched_getaffinity(0, std::mem::size_of::<libc::cpu_set_t>(), &mut set) };
22 if rc != 0 {
23 return Err(Error::msg(format!(
24 "sched_getaffinity failed: {}",
25 std::io::Error::last_os_error()
26 )));
27 }
28
29 let max_cpus = std::mem::size_of::<libc::cpu_set_t>() * 8;
30 let mut out = Vec::new();
31 for cpu in 0..max_cpus {
32 if unsafe { libc::CPU_ISSET(cpu, &set) } {
33 out.push(cpu);
34 }
35 }
36 Ok(out)
37 }
38
39 #[cfg(not(target_os = "linux"))]
40 {
41 Err(Error::msg("CPU affinity is only supported on Linux"))
42 }
43}
44
45pub fn fmt_cpu_list(cpus: &[usize]) -> String {
49 if cpus.is_empty() {
50 return "<none>".to_string();
51 }
52
53 let mut out = String::new();
54 for (i, cpu) in cpus.iter().enumerate() {
55 if i > 0 {
56 out.push(',');
57 }
58 out.push_str(&cpu.to_string());
59 }
60 out
61}
62
63pub fn pin_current_thread_to_cpu(cpu: usize) -> Result<()> {
71 #[cfg(target_os = "linux")]
72 {
73 let max_cpus = std::mem::size_of::<libc::cpu_set_t>() * 8;
74 if cpu >= max_cpus {
75 return Err(Error::msg(format!(
76 "cpu pin out of range for cpu_set_t: requested cpu={cpu}, max_supported={max_cpus}"
77 )));
78 }
79
80 let mut set: libc::cpu_set_t = unsafe { std::mem::zeroed() };
81 unsafe {
82 libc::CPU_ZERO(&mut set);
83 libc::CPU_SET(cpu, &mut set);
84 }
85
86 let rc = unsafe {
87 libc::sched_setaffinity(
88 0,
89 std::mem::size_of::<libc::cpu_set_t>(),
90 &set as *const libc::cpu_set_t,
91 )
92 };
93
94 if rc != 0 {
95 let os_err = std::io::Error::last_os_error();
96 let allowed = current_thread_allowed_cpus().unwrap_or_default();
97 let allowed_list = fmt_cpu_list(&allowed);
98 return Err(Error::msg(format!(
99 "sched_setaffinity(cpu={cpu}) failed: {os_err}; allowed_cpus={allowed_list}"
100 )));
101 }
102
103 Ok(())
104 }
105
106 #[cfg(not(target_os = "linux"))]
107 {
108 Err(Error::msg("CPU pinning is only supported on Linux"))
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn fmt_cpu_list_formats_empty() {
118 assert_eq!(fmt_cpu_list(&[]), "<none>");
119 }
120
121 #[test]
122 fn fmt_cpu_list_formats_values() {
123 assert_eq!(fmt_cpu_list(&[0]), "0");
124 assert_eq!(fmt_cpu_list(&[0, 2, 7]), "0,2,7");
125 }
126}