#[derive(Default, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
#[derive(Deserialize, Serialize)]
pub struct LogicalCore(u16);
impl Display for LogicalCore
{
#[inline(always)]
fn fmt(&self, f: &mut Formatter) -> fmt::Result
{
write!(f, "{}", self.0)
}
}
impl Into<u16> for LogicalCore
{
#[inline(always)]
fn into(self) -> u16
{
self.0 as u16
}
}
impl Into<u32> for LogicalCore
{
#[inline(always)]
fn into(self) -> u32
{
self.0 as u32
}
}
impl Into<u64> for LogicalCore
{
#[inline(always)]
fn into(self) -> u64
{
self.0 as u64
}
}
impl Into<usize> for LogicalCore
{
#[inline(always)]
fn into(self) -> usize
{
self.0 as usize
}
}
impl Into<isize> for LogicalCore
{
#[inline(always)]
fn into(self) -> isize
{
self.0 as isize
}
}
impl LogicalCore
{
pub const Maximum: usize = RTE_MAX_LCORE;
#[inline(always)]
pub fn from_u16(value: u16) -> Result<Self, ()>
{
if unlikely!(Self::is_invalid(value))
{
Err(())
}
else
{
Ok(LogicalCore(value))
}
}
#[inline(always)]
pub(crate) fn is_invalid(value: u16) -> bool
{
debug_assert!((value as usize) < Self::Maximum, "value '{}' exceeds Self::Maximum '{}'", value, Self::Maximum);
Self::logical_core_global_configuration()[value as usize].core_index < 0
}
#[inline(always)]
pub fn current_logical_core_cpu_set() -> &'static mut rte_cpuset_t
{
unsafe { &mut per_lcore__cpuset }
}
#[inline(always)]
pub fn current_logical_core_error_number() -> i32
{
unsafe { per_lcore__rte_errno }
}
#[inline(always)]
pub fn current_logical_core_thread_affinity() -> rte_cpuset_t
{
let mut cpu_set = unsafe { uninitialized() };
unsafe { rte_thread_get_affinity(&mut cpu_set) }
cpu_set
}
#[inline(always)]
pub fn override_current_logical_core_thread_affinity(cpu_set: &mut rte_cpuset_t)
{
if unlikely!(rte_thread_set_affinity(cpu_set) != 0)
{
panic!("Could not set current logical core thread affinity");
}
}
#[inline(always)]
pub fn number_of_logical_cores() -> usize
{
DpdkProcess::global_configuration().lcore_count as usize
}
#[inline(always)]
pub fn number_of_service_cores() -> usize
{
DpdkProcess::global_configuration().service_lcore_count as usize
}
#[inline(always)]
pub fn master() -> Self
{
let master = DpdkProcess::global_configuration().master_lcore;
debug_assert!(master <= (::std::u16::MAX as u32), "master '{}' is larger than ::std::u16::MAX '{}'", master, ::std::u16::MAX);
LogicalCore::from_u16(master as u16).unwrap()
}
#[inline(always)]
pub fn number_of_logical_cores_used_as_service_cores() -> usize
{
let result = unsafe { rte_service_lcore_count() };
if likely!(result >= 0)
{
result as usize
}
else
{
panic!("rte_service_lcore_count failed")
}
}
#[inline(always)]
pub fn list_service_logical_cores() -> Vec<LogicalCore>
{
let mut array: [u32; LogicalCore::Maximum] = unsafe { uninitialized() };
let result = unsafe { rte_service_lcore_list(array.as_mut_ptr(), array.len() as u32) };
if likely!(result >= 0)
{
let count = result as usize;
let mut list = Vec::with_capacity(count);
let mut index = 0;
while index < count
{
list.push(LogicalCore::from_u16(array[index] as u16).unwrap());
index += 1;
}
list
}
else
{
panic!("rte_service_lcore_list failed");
}
}
#[inline(always)]
pub fn start_power_management(self) -> Result<LogicalCorePowerManagement, ()>
{
LogicalCorePowerManagement::start(self)
}
#[inline(always)]
pub fn is_role_normal(self) -> bool
{
self.logical_core_role() == rte_lcore_role_t::ROLE_RTE
}
#[inline(always)]
pub fn is_role_service(self) -> bool
{
self.logical_core_role() == rte_lcore_role_t::ROLE_SERVICE
}
#[inline(always)]
pub fn number_of_services_running_on_this_service_core(self) -> Option<usize>
{
if self.is_role_service()
{
let result = unsafe { rte_service_lcore_count_services(self.into()) };
if likely!(result >= 0)
{
Some(result as usize)
}
else
{
panic!("rte_service_lcore_count_services() failed")
}
}
else
{
None
}
}
#[inline(always)]
pub fn add_to_logical_cores_used_as_service_cores(self) -> Result<(), ()>
{
let result = unsafe { rte_service_lcore_add(self.into()) };
if likely!(result == 0)
{
Ok(())
}
else
{
match result
{
NegativeE::EBUSY | NegativeE::EALREADY => Err(()),
NegativeE::EINVAL => panic!("EINVAL from rte_service_lcore_add()"),
unexpected @ _ => panic!("Unexpected '{}' from rte_service_lcore_add()", unexpected),
}
}
}
#[inline(always)]
pub fn remove_from_logical_cores_used_as_service_cores(self) -> Result<(), ()>
{
debug_assert!(self.is_role_service(), "Is not a service core");
let result = unsafe { rte_service_lcore_del(self.into()) };
if likely!(result == 0)
{
Ok(())
}
else
{
match result
{
NegativeE::EBUSY => Err(()),
NegativeE::EINVAL => panic!("EINVAL from rte_service_lcore_del()"),
unexpected @ _ => panic!("Unexpected '{}' from rte_service_lcore_del()", unexpected),
}
}
}
pub fn start_service_core(self) -> Result<(), ()>
{
debug_assert!(self.is_role_service(), "Is not a service core");
let result = unsafe { rte_service_lcore_start(self.into()) };
if likely!(result == 0)
{
Ok(())
}
else
{
match result
{
NegativeE::EINVAL => panic!("EINVAL from rte_service_lcore_start()"),
unexpected @ _ => panic!("Unexpected '{}' from rte_service_lcore_start()", unexpected),
}
}
}
pub fn stop_service_core(self) -> Result<(), ()>
{
debug_assert!(self.is_role_service(), "Is not a service core");
let result = unsafe { rte_service_lcore_stop(self.into()) };
if likely!(result == 0)
{
Ok(())
}
else
{
match result
{
NegativeE::EBUSY | NegativeE::EALREADY => Err(()),
NegativeE::EINVAL => panic!("EINVAL from rte_service_lcore_stop()"),
unexpected @ _ => panic!("Unexpected '{}' from rte_service_lcore_stop()", unexpected),
}
}
}
#[inline(always)]
pub fn index(self) -> usize
{
let core_index = self.logical_core_configuration().core_index;
debug_assert!(core_index >= 0, "logical core is not one configured for use with DPDK");
core_index as usize
}
#[inline(always)]
pub fn numa_node(self) -> NumaNode
{
let socket_id = self.logical_core_configuration().socket_id;
NumaNode::from_u32(socket_id)
}
#[inline(always)]
pub fn thread(self) -> pthread_t
{
self.logical_core_configuration().thread_id
}
#[inline(always)]
pub fn set_thread_name(self, name: &CStr)
{
if unlikely!(rte_thread_setname(self.thread(), name.as_ptr()) != 0)
{
panic!("Could not set thread name for logical core");
}
}
#[inline(always)]
pub fn all_logical_cores() -> AllLogicalCoreIterator
{
Default::default()
}
#[inline(always)]
pub fn slave_logical_cores() -> SlaveLogicalCoreIterator
{
Default::default()
}
#[inline(always)]
pub fn slave_logical_cores_without_service_cores() -> impl Iterator<Item=Self>
{
Self::slave_logical_cores().filter(|slave_logical_core| !slave_logical_core.is_role_service())
}
#[inline(always)]
pub fn execution_state(self) -> rte_lcore_state_t
{
Self::debug_assert_code_is_currently_running_on_the_master_logical_core();
self.logical_core_configuration().state
}
#[inline(always)]
pub fn execute_code_on_slave<F: SlaveLogicalCoreFunction>(self, function_to_execute_on_slave: Box<F>) -> Result<(), ()>
{
Self::debug_assert_code_is_currently_running_on_the_master_logical_core();
debug_assert_ne!(&self, &Self::master(), "Can not wait for a slave when self is master logical core");
unsafe extern "C" fn execute<F: SlaveLogicalCoreFunction>(arg1: *mut c_void) -> i32
{
debug_assert!(arg1.is_not_null(), "arg1 is null");
let mut this = Box::from_raw(arg1 as *mut F);
this.execute();
0
}
let arg1 = Box::into_raw(function_to_execute_on_slave) as *mut c_void;
match unsafe { rte_eal_remote_launch(execute::<F>, arg1, self.into()) }
{
0 => Ok(()),
NegativeE::EBUSY =>
{
drop(unsafe { Box::from_raw(arg1) });
Err(())
}
invalid @ _ => panic!("Invalid result from rte_eal_remote_launch '{}'", invalid),
}
}
#[inline(always)]
pub fn block_until_all_slaves_are_in_the_wait_state()
{
Self::debug_assert_code_is_currently_running_on_the_master_logical_core();
for slave_logical_core in Self::slave_logical_cores()
{
slave_logical_core.block_until_this_slave_is_in_the_wait_state()
}
}
pub fn block_until_this_slave_is_in_the_wait_state(self)
{
Self::debug_assert_code_is_currently_running_on_the_master_logical_core();
debug_assert_ne!(&self, &Self::master(), "Can not wait for a slave when self is master logical core");
unsafe { rte_eal_wait_lcore(self.into()) };
}
#[inline(always)]
fn debug_assert_code_is_currently_running_on_the_master_logical_core()
{
debug_assert_eq!(Self::master(), LogicalCoreChoice::current_logical_core().expect("current core is not a logical core"), "Code must be running on the master logical core to use this functionality");
}
#[inline(always)]
fn logical_core_role(self) -> rte_lcore_role_t
{
let index: usize = self.into();
DpdkProcess::global_configuration().lcore_role[index]
}
#[inline(always)]
fn logical_core_configuration(self) -> &'static mut lcore_config
{
let index: usize = self.into();
&mut Self::logical_core_global_configuration()[index]
}
#[inline(always)]
fn logical_core_global_configuration() -> &'static mut [lcore_config; Self::Maximum]
{
unsafe { &mut lcore_config }
}
}