|
1 | 1 | use std::{ |
2 | 2 | ffi::{CString, OsStr, c_long, c_uint}, |
3 | 3 | io, mem, |
| 4 | + num::NonZeroU32, |
4 | 5 | os::fd::{BorrowedFd, FromRawFd as _}, |
5 | 6 | }; |
6 | 7 |
|
@@ -125,7 +126,9 @@ pub(crate) fn perf_event_open( |
125 | 126 |
|
126 | 127 | let (pid, cpu) = match scope { |
127 | 128 | PerfEventScope::CallingProcess { cpu } => (0, cpu.map_or(-1, |cpu| cpu as i32)), |
128 | | - PerfEventScope::OneProcess { pid, cpu } => (pid as i32, cpu.map_or(-1, |cpu| cpu as i32)), |
| 129 | + PerfEventScope::OneProcess { pid, cpu } => { |
| 130 | + (pid.get() as i32, cpu.map_or(-1, |cpu| cpu as i32)) |
| 131 | + } |
129 | 132 | PerfEventScope::AllProcessesOneCpu { cpu } => (-1, cpu as i32), |
130 | 133 | }; |
131 | 134 |
|
@@ -166,9 +169,10 @@ pub(crate) fn perf_event_open_trace_point( |
166 | 169 | event_id: u64, |
167 | 170 | pid: Option<u32>, |
168 | 171 | ) -> io::Result<crate::MockableFd> { |
169 | | - let scope = match pid { |
170 | | - Some(pid) => PerfEventScope::OneProcess { pid, cpu: None }, |
| 172 | + let scope = match pid.map(NonZeroU32::new) { |
171 | 173 | None => PerfEventScope::AllProcessesOneCpu { cpu: 0 }, |
| 174 | + Some(None) => PerfEventScope::CallingProcess { cpu: None }, |
| 175 | + Some(Some(pid)) => PerfEventScope::OneProcess { pid, cpu: None }, |
172 | 176 | }; |
173 | 177 | perf_event_open( |
174 | 178 | PerfEventConfig::TracePoint { event_id }, |
@@ -253,3 +257,47 @@ impl TryFrom<u32> for perf_event_type { |
253 | 257 | } |
254 | 258 | } |
255 | 259 | */ |
| 260 | + |
| 261 | +#[cfg(test)] |
| 262 | +mod tests { |
| 263 | + use std::os::fd::AsRawFd as _; |
| 264 | + |
| 265 | + use libc::pid_t; |
| 266 | + use test_case::test_case; |
| 267 | + |
| 268 | + use super::{PERF_FLAG_FD_CLOEXEC, perf_event_open_trace_point}; |
| 269 | + use crate::sys::{Syscall, override_syscall}; |
| 270 | + |
| 271 | + const EVENT_ID: u64 = 123; |
| 272 | + |
| 273 | + #[test_case(None, -1, 0; "all_processes")] |
| 274 | + #[test_case(Some(0), 0, -1; "calling_process")] |
| 275 | + #[test_case(Some(42), 42, -1; "one_process")] |
| 276 | + fn perf_event_open_trace_point_maps_pid_scope( |
| 277 | + pid: Option<u32>, |
| 278 | + expected_pid: pid_t, |
| 279 | + expected_cpu: i32, |
| 280 | + ) { |
| 281 | + override_syscall(move |call| match call { |
| 282 | + Syscall::PerfEventOpen { |
| 283 | + attr, |
| 284 | + pid: actual_pid, |
| 285 | + cpu: actual_cpu, |
| 286 | + group, |
| 287 | + flags, |
| 288 | + } => { |
| 289 | + assert_eq!(attr.config, EVENT_ID); |
| 290 | + assert_eq!(unsafe { attr.__bindgen_anon_1.sample_period }, 0); |
| 291 | + assert_eq!(actual_pid, expected_pid); |
| 292 | + assert_eq!(actual_cpu, expected_cpu); |
| 293 | + assert_eq!(group, -1); |
| 294 | + assert_eq!(flags, PERF_FLAG_FD_CLOEXEC); |
| 295 | + Ok(crate::MockableFd::mock_signed_fd().into()) |
| 296 | + } |
| 297 | + call => panic!("unexpected syscall: {call:?}"), |
| 298 | + }); |
| 299 | + |
| 300 | + let fd = perf_event_open_trace_point(EVENT_ID, pid).unwrap(); |
| 301 | + assert_eq!(fd.as_raw_fd(), crate::MockableFd::mock_signed_fd()); |
| 302 | + } |
| 303 | +} |
0 commit comments