use clap::{crate_version, Arg, ArgAction, Command};
use std::{env, thread};
use uucore::display::Quotable;
use uucore::error::{UResult, USimpleError};
use uucore::{format_usage, help_about, help_usage};
#[cfg(any(target_os = "linux", target_os = "android"))]
pub const _SC_NPROCESSORS_CONF: libc::c_int = 83;
#[cfg(target_vendor = "apple")]
pub const _SC_NPROCESSORS_CONF: libc::c_int = libc::_SC_NPROCESSORS_CONF;
#[cfg(target_os = "freebsd")]
pub const _SC_NPROCESSORS_CONF: libc::c_int = 57;
#[cfg(target_os = "netbsd")]
pub const _SC_NPROCESSORS_CONF: libc::c_int = 1001;
static OPT_ALL: &str = "all";
static OPT_IGNORE: &str = "ignore";
const ABOUT: &str = help_about!("nproc.md");
const USAGE: &str = help_usage!("nproc.md");
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uu_app().try_get_matches_from(args)?;
let ignore = match matches.get_one::<String>(OPT_IGNORE) {
Some(numstr) => match numstr.trim().parse() {
Ok(num) => num,
Err(e) => {
return Err(USimpleError::new(
1,
format!("{} is not a valid number: {}", numstr.quote(), e),
));
}
},
None => 0,
};
let limit = match env::var("OMP_THREAD_LIMIT") {
Ok(threadstr) => match threadstr.parse() {
Ok(0) | Err(_) => usize::MAX,
Ok(n) => n,
},
Err(_) => usize::MAX,
};
let mut cores = if matches.get_flag(OPT_ALL) {
num_cpus_all()
} else {
match env::var("OMP_NUM_THREADS") {
Ok(threadstr) => {
let thread: Vec<&str> = threadstr.split_terminator(',').collect();
match &thread[..] {
[] => available_parallelism(),
[s, ..] => match s.parse() {
Ok(0) | Err(_) => available_parallelism(),
Ok(n) => n,
},
}
}
Err(_) => available_parallelism(),
}
};
cores = std::cmp::min(limit, cores);
if cores <= ignore {
cores = 1;
} else {
cores -= ignore;
}
println!("{cores}");
Ok(())
}
pub fn uu_app() -> Command {
Command::new(uucore::util_name())
.version(crate_version!())
.about(ABOUT)
.override_usage(format_usage(USAGE))
.infer_long_args(true)
.arg(
Arg::new(OPT_ALL)
.long(OPT_ALL)
.help("print the number of cores available to the system")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(OPT_IGNORE)
.long(OPT_IGNORE)
.value_name("N")
.help("ignore up to N cores"),
)
}
#[cfg(any(
target_os = "linux",
target_vendor = "apple",
target_os = "freebsd",
target_os = "netbsd"
))]
fn num_cpus_all() -> usize {
let nprocs = unsafe { libc::sysconf(_SC_NPROCESSORS_CONF) };
if nprocs == 1 {
available_parallelism()
} else if nprocs > 0 {
nprocs as usize
} else {
1
}
}
#[cfg(not(any(
target_os = "linux",
target_vendor = "apple",
target_os = "freebsd",
target_os = "netbsd"
)))]
fn num_cpus_all() -> usize {
available_parallelism()
}
fn available_parallelism() -> usize {
match thread::available_parallelism() {
Ok(n) => n.get(),
Err(_) => 1,
}
}