use alloc::{
string::{String, ToString},
vec::Vec,
};
#[cfg(any(unix, all(windows, feature = "std")))]
use crate::Error;
#[cfg(feature = "std")]
use std::{env, process::Command};
#[cfg(all(unix, feature = "std"))]
pub mod unix_shmem_server;
#[cfg(unix)]
pub mod unix_signals;
#[cfg(all(unix, feature = "std"))]
pub mod pipes;
#[cfg(all(unix, feature = "std"))]
use std::ffi::CString;
#[cfg(all(windows, feature = "std"))]
#[allow(missing_docs, overflowing_literals)]
pub mod windows_exceptions;
#[cfg(unix)]
use libc::pid_t;
#[cfg(unix)]
#[derive(Debug)]
pub struct ChildHandle {
pub pid: pid_t,
}
#[cfg(unix)]
impl ChildHandle {
#[must_use]
pub fn status(&self) -> i32 {
let mut status = -1;
unsafe {
libc::waitpid(self.pid, &mut status, 0);
}
status
}
}
#[cfg(unix)]
#[derive(Debug)]
pub enum ForkResult {
Parent(ChildHandle),
Child,
}
#[cfg(unix)]
pub unsafe fn fork() -> Result<ForkResult, Error> {
match libc::fork() {
pid if pid > 0 => Ok(ForkResult::Parent(ChildHandle { pid })),
pid if pid < 0 => {
#[cfg(feature = "std")]
{
let err_str = CString::new("Fork failed").unwrap();
libc::perror(err_str.as_ptr());
}
Err(Error::Unknown(format!("Fork failed ({})", pid)))
}
_ => Ok(ForkResult::Child),
}
}
#[cfg(feature = "std")]
pub fn startable_self() -> Result<Command, Error> {
let mut startable = Command::new(env::current_exe()?);
startable
.current_dir(env::current_dir()?)
.args(env::args().skip(1));
Ok(startable)
}
#[cfg(all(unix, feature = "std"))]
pub fn dup2(fd: i32, device: i32) -> Result<(), Error> {
match unsafe { libc::dup2(fd, device) } {
-1 => Err(Error::File(std::io::Error::last_os_error())),
_ => Ok(()),
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CoreId {
pub id: usize,
}
#[cfg(feature = "std")]
impl From<&CoreId> for core_affinity::CoreId {
fn from(core_id: &CoreId) -> Self {
core_affinity::CoreId { id: core_id.id }
}
}
#[cfg(feature = "std")]
impl From<CoreId> for core_affinity::CoreId {
fn from(core_id: CoreId) -> Self {
core_affinity::CoreId { id: core_id.id }
}
}
#[cfg(feature = "std")]
impl CoreId {
pub fn set_affinity(&self) {
core_affinity::set_for_current(self.into());
}
}
impl From<usize> for CoreId {
fn from(id: usize) -> Self {
CoreId { id }
}
}
#[cfg(feature = "std")]
impl From<&core_affinity::CoreId> for CoreId {
fn from(core_id: &core_affinity::CoreId) -> Self {
CoreId { id: core_id.id }
}
}
#[cfg(feature = "std")]
impl From<core_affinity::CoreId> for CoreId {
fn from(core_id: core_affinity::CoreId) -> Self {
CoreId { id: core_id.id }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Cores {
pub cmdline: String,
pub ids: Vec<CoreId>,
}
#[cfg(feature = "std")]
impl Cores {
pub fn all() -> Result<Self, Error> {
Self::from_cmdline("all")
}
pub fn from_cmdline(args: &str) -> Result<Self, Error> {
let mut cores: Vec<CoreId> = vec![];
if args == "all" {
let num_cores = if let Some(cores) = core_affinity::get_core_ids() {
cores.len()
} else {
return Err(Error::IllegalState(
"Could not read core count from core_affinity".to_string(),
));
};
for x in 0..num_cores {
cores.push(x.into());
}
} else {
let core_args: Vec<&str> = args.split(',').collect();
for csv in core_args {
let core_range: Vec<&str> = csv.split('-').collect();
if core_range.len() == 1 {
cores.push(core_range[0].parse::<usize>()?.into());
} else if core_range.len() == 2 {
for x in core_range[0].parse::<usize>()?..=(core_range[1].parse::<usize>()?) {
cores.push(x.into());
}
}
}
}
if cores.is_empty() {
return Err(Error::IllegalArgument(format!(
"No cores specified! parsed: {}",
args
)));
}
Ok(Self {
cmdline: args.to_string(),
ids: cores,
})
}
}
impl From<&[usize]> for Cores {
fn from(cores: &[usize]) -> Self {
let cmdline = cores
.iter()
.map(ToString::to_string)
.collect::<Vec<String>>()
.join(",");
let ids = cores.iter().map(|x| (*x).into()).collect();
Self { cmdline, ids }
}
}
impl From<Vec<usize>> for Cores {
fn from(cores: Vec<usize>) -> Self {
Self::from(cores.as_slice())
}
}
#[cfg(feature = "std")]
impl TryFrom<&str> for Cores {
type Error = Error;
fn try_from(cores: &str) -> Result<Self, Self::Error> {
Self::from_cmdline(cores)
}
}
#[must_use]
#[cfg(feature = "std")]
#[deprecated(since = "0.7.1", note = "Use Cores::from_cmdline instead")]
pub fn parse_core_bind_arg(args: &str) -> Option<Vec<usize>> {
Cores::from_cmdline(args)
.ok()
.map(|cores| cores.ids.iter().map(|x| x.id).collect())
}