#![allow(unsafe_code)]
pub(crate) fn reset_signal_dispositions() {
let signals = signal_range();
for sig in signals {
if sig == libc::SIGKILL || sig == libc::SIGSTOP {
continue;
}
let mut sa: libc::sigaction = unsafe { std::mem::zeroed() };
sa.sa_sigaction = libc::SIG_DFL;
unsafe { libc::sigemptyset(&mut sa.sa_mask) };
sa.sa_flags = 0;
let ret = unsafe { libc::sigaction(sig, &sa, std::ptr::null_mut()) };
if ret != 0 {
let err = std::io::Error::last_os_error();
if err.raw_os_error() != Some(libc::EINVAL) {
panic!("sigaction({sig}) failed: {err}");
}
}
}
}
fn signal_range() -> Vec<i32> {
#[cfg(target_os = "linux")]
{
let rtmin = libc::SIGRTMIN();
let rtmax = libc::SIGRTMAX();
(1..32).chain(rtmin..=rtmax).collect()
}
#[cfg(not(target_os = "linux"))]
{
(1..=64).collect()
}
}
pub(crate) fn raw_close(fd: i32) {
unsafe { libc::close(fd) };
}
pub(crate) fn raw_initgroups(
user: &std::ffi::CStr,
group: libc::gid_t,
) -> Result<(), nix::errno::Errno> {
let ret = unsafe { libc::initgroups(user.as_ptr(), group as _) };
if ret < 0 {
Err(nix::errno::Errno::last())
} else {
Ok(())
}
}
pub(crate) fn raw_exit(code: i32) -> ! {
unsafe { libc::_exit(code) }
}
static CLEANUP_PIDFILE: std::sync::atomic::AtomicPtr<libc::c_char> =
std::sync::atomic::AtomicPtr::new(std::ptr::null_mut());
extern "C" fn pidfile_cleanup_handler(signum: i32) {
use std::sync::atomic::Ordering;
let ptr = CLEANUP_PIDFILE.load(Ordering::Acquire);
if !ptr.is_null() {
unsafe { libc::unlink(ptr) };
}
unsafe { libc::raise(signum) };
}
pub(crate) fn install_pidfile_cleanup_signals(
pidfile: &std::ffi::CStr,
signals: &[i32],
) -> std::io::Result<()> {
use std::sync::atomic::Ordering;
let leaked: *mut libc::c_char = pidfile.to_owned().into_raw();
CLEANUP_PIDFILE.store(leaked, Ordering::Release);
for &sig in signals {
let mut sa: libc::sigaction = unsafe { std::mem::zeroed() };
let handler = pidfile_cleanup_handler as extern "C" fn(i32);
sa.sa_sigaction = handler as usize;
unsafe { libc::sigemptyset(&mut sa.sa_mask) };
sa.sa_flags = libc::SA_RESETHAND;
let ret = unsafe { libc::sigaction(sig, &sa, std::ptr::null_mut()) };
if ret != 0 {
return Err(std::io::Error::last_os_error());
}
}
Ok(())
}
#[cfg(target_os = "macos")]
pub(crate) fn thread_count() -> std::io::Result<usize> {
let mut info: libc::proc_taskinfo = unsafe { std::mem::zeroed() };
let size = std::mem::size_of::<libc::proc_taskinfo>() as libc::c_int;
let written = unsafe {
libc::proc_pidinfo(
libc::getpid(),
libc::PROC_PIDTASKINFO,
0,
(&mut info as *mut libc::proc_taskinfo).cast(),
size,
)
};
if written < size {
return Err(std::io::Error::last_os_error());
}
Ok(info.pti_threadnum.max(0) as usize)
}
#[cfg(target_os = "freebsd")]
pub(crate) fn thread_count() -> std::io::Result<usize> {
let mut kp: libc::kinfo_proc = unsafe { std::mem::zeroed() };
let mut size = std::mem::size_of::<libc::kinfo_proc>();
let mut mib = [
libc::CTL_KERN,
libc::KERN_PROC,
libc::KERN_PROC_PID,
unsafe { libc::getpid() },
];
let rc = unsafe {
libc::sysctl(
mib.as_mut_ptr(),
mib.len() as libc::c_uint,
(&mut kp as *mut libc::kinfo_proc).cast(),
&mut size,
std::ptr::null_mut(),
0,
)
};
if rc != 0 {
return Err(std::io::Error::last_os_error());
}
Ok(kp.ki_numthreads.max(0) as usize)
}
#[cfg(target_os = "netbsd")]
pub(crate) fn thread_count() -> std::io::Result<usize> {
let mut kp: libc::kinfo_proc2 = unsafe { std::mem::zeroed() };
let mut size = std::mem::size_of::<libc::kinfo_proc2>();
let mut mib = [
libc::CTL_KERN,
libc::KERN_PROC2,
libc::KERN_PROC_PID,
unsafe { libc::getpid() },
size as libc::c_int,
1,
];
let rc = unsafe {
libc::sysctl(
mib.as_mut_ptr(),
mib.len() as libc::c_uint,
(&mut kp as *mut libc::kinfo_proc2).cast(),
&mut size,
std::ptr::null_mut(),
0,
)
};
if rc != 0 {
return Err(std::io::Error::last_os_error());
}
Ok(kp.p_nlwps as usize) }
#[cfg(target_os = "openbsd")]
pub(crate) fn thread_count() -> std::io::Result<usize> {
let elem = std::mem::size_of::<libc::kinfo_proc>();
let mut size: libc::size_t = 0;
let mut mib = [
libc::CTL_KERN,
libc::KERN_PROC,
libc::KERN_PROC_PID | libc::KERN_PROC_SHOW_THREADS,
unsafe { libc::getpid() },
elem as libc::c_int,
0,
];
let rc = unsafe {
libc::sysctl(
mib.as_mut_ptr(),
mib.len() as libc::c_uint,
std::ptr::null_mut(),
&mut size,
std::ptr::null_mut(),
0,
)
};
if rc != 0 {
return Err(std::io::Error::last_os_error());
}
if size == 0 {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"sysctl(KERN_PROC_SHOW_THREADS) returned no thread records",
));
}
let mut buf = vec![0u8; size];
mib[5] = (size / elem) as libc::c_int;
let rc = unsafe {
libc::sysctl(
mib.as_mut_ptr(),
mib.len() as libc::c_uint,
buf.as_mut_ptr().cast(),
&mut size,
std::ptr::null_mut(),
0,
)
};
if rc != 0 {
return Err(std::io::Error::last_os_error());
}
Ok(size / elem)
}
pub(crate) fn at_fdcwd() -> std::os::fd::BorrowedFd<'static> {
unsafe { std::os::fd::BorrowedFd::borrow_raw(libc::AT_FDCWD) }
}