Skip to content

Commit

Permalink
bolts: core affinity simplification for freebsd (#2049)
Browse files Browse the repository at this point in the history
since 13.1 (EOL since mid-2023) , supports the sched affinity api like linux/dragonflybsd.
  • Loading branch information
devnexen authored Apr 14, 2024
1 parent 0c68ff0 commit 4ec50d6
Showing 1 changed file with 24 additions and 133 deletions.
157 changes: 24 additions & 133 deletions libafl_bolts/src/core_affinity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,27 +215,46 @@ pub fn parse_core_bind_arg(args: &str) -> Result<Vec<usize>, Error> {

// Linux Section

#[cfg(any(target_os = "android", target_os = "linux", target_os = "dragonfly"))]
#[cfg(any(
target_os = "android",
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd"
))]
#[inline]
fn get_core_ids_helper() -> Result<Vec<CoreId>, Error> {
linux::get_core_ids()
}

#[cfg(any(target_os = "android", target_os = "linux", target_os = "dragonfly"))]
#[cfg(any(
target_os = "android",
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd"
))]
#[inline]
fn set_for_current_helper(core_id: CoreId) -> Result<(), Error> {
linux::set_for_current(core_id)
}

#[cfg(any(target_os = "android", target_os = "linux", target_os = "dragonfly"))]
#[cfg(any(
target_os = "android",
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd"
))]
mod linux {
use alloc::{string::ToString, vec::Vec};
use std::mem;

#[cfg(not(target_os = "freebsd"))]
use libc::cpu_set_t;
#[cfg(target_os = "freebsd")]
use libc::cpuset_t as cpu_set_t;
#[cfg(target_os = "dragonfly")]
use libc::{cpu_set_t, sched_getaffinity, sched_setaffinity, CPU_ISSET, CPU_SET};
use libc::{sched_getaffinity, sched_setaffinity, CPU_ISSET, CPU_SET};
#[cfg(not(target_os = "dragonfly"))]
use libc::{cpu_set_t, sched_getaffinity, sched_setaffinity, CPU_ISSET, CPU_SET, CPU_SETSIZE};
use libc::{sched_getaffinity, sched_setaffinity, CPU_ISSET, CPU_SET, CPU_SETSIZE};
#[cfg(target_os = "dragonfly")]
const CPU_SETSIZE: libc::c_int = 256;

Expand Down Expand Up @@ -667,134 +686,6 @@ mod apple {
}
}

// FreeBSD Section

#[cfg(target_os = "freebsd")]
#[inline]
fn get_core_ids_helper() -> Result<Vec<CoreId>, Error> {
freebsd::get_core_ids()
}

#[cfg(target_os = "freebsd")]
#[inline]
fn set_for_current_helper(core_id: CoreId) -> Result<(), Error> {
freebsd::set_for_current(core_id)
}

#[cfg(target_os = "freebsd")]
mod freebsd {
use alloc::vec::Vec;
use std::{mem, thread::available_parallelism};

use libc::{cpuset_setaffinity, cpuset_t, CPU_LEVEL_WHICH, CPU_SET, CPU_WHICH_PID};

use super::CoreId;
use crate::Error;

#[allow(trivial_numeric_casts)]
pub fn get_core_ids() -> Result<Vec<CoreId>, Error> {
Ok((0..(usize::from(available_parallelism()?)))
.map(CoreId)
.collect::<Vec<_>>())
}

pub fn set_for_current(core_id: CoreId) -> Result<(), Error> {
// Turn `core_id` into a `libc::cpuset_t` with only
let mut set = new_cpuset();

unsafe { CPU_SET(core_id.0, &mut set) };

// Set the current thread's core affinity.
let result = unsafe {
cpuset_setaffinity(
CPU_LEVEL_WHICH,
CPU_WHICH_PID,
-1, // Defaults to current thread
mem::size_of::<cpuset_t>(),
&set,
)
};

if result < 0 {
Err(Error::unknown("Failed to set_for_current"))
} else {
Ok(())
}
}

#[cfg(test)]
fn get_affinity_mask() -> Result<cpuset_t, Error> {
let mut set = new_cpuset();

// Try to get current core affinity mask.
let result = unsafe {
libc::cpuset_getaffinity(
CPU_LEVEL_WHICH,
CPU_WHICH_PID,
-1, // Defaults to current thread
mem::size_of::<cpuset_t>(),
&mut set,
)
};

if result == 0 {
Ok(set)
} else {
Err(Error::unknown(
"Failed to retrieve affinity using cpuset_getaffinity",
))
}
}

fn new_cpuset() -> cpuset_t {
unsafe { mem::zeroed::<cpuset_t>() }
}

// FIXME: unstable for now on freebsd
#[cfg(test)]
mod tests {
use libc::CPU_ISSET;

use super::*;

#[test]
#[ignore]
fn test_freebsd_get_affinity_mask() {
get_affinity_mask().unwrap();
}

#[test]
#[ignore]
fn test_freebsd_set_for_current() {
let ids = get_core_ids().unwrap();

assert!(!ids.is_empty());

ids[0].set_affinity().unwrap();

// Ensure that the system pinned the current thread
// to the specified core.
let mut core_mask = new_cpuset();
unsafe { CPU_SET(ids[0].0, &mut core_mask) };

let new_mask = get_affinity_mask().unwrap();

let mut is_equal = true;

for i in 0..256 {
let is_set1 = unsafe { CPU_ISSET(i, &core_mask) };
let is_set2 = unsafe { CPU_ISSET(i, &new_mask) };

if is_set1 != is_set2 {
is_equal = false;
}
}

assert!(is_equal);
}
}
}

// NetBSD Section

#[cfg(target_os = "netbsd")]
Expand Down

0 comments on commit 4ec50d6

Please sign in to comment.