pub use impl_::*;
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum PriorityError {
#[class(inherit)]
#[error("{0}")]
Io(#[from] std::io::Error),
#[cfg(windows)]
#[class(type)]
#[error("Invalid priority")]
InvalidPriority,
}
#[cfg(unix)]
mod impl_ {
use errno::Errno;
use errno::errno;
use errno::set_errno;
use libc::PRIO_PROCESS;
use libc::id_t;
pub fn get_priority(pid: u32) -> Result<i32, super::PriorityError> {
set_errno(Errno(0));
match (
unsafe { libc::getpriority(PRIO_PROCESS, pid as id_t) },
errno(),
) {
(-1, Errno(0)) => Ok(-1),
(-1, _) => Err(std::io::Error::last_os_error().into()),
(priority, _) => Ok(priority),
}
}
pub fn set_priority(
pid: u32,
priority: i32,
) -> Result<(), super::PriorityError> {
match unsafe { libc::setpriority(PRIO_PROCESS, pid as id_t, priority) } {
-1 => Err(std::io::Error::last_os_error().into()),
_ => Ok(()),
}
}
}
#[cfg(windows)]
mod impl_ {
use winapi::shared::minwindef::DWORD;
use winapi::shared::minwindef::FALSE;
use winapi::shared::ntdef::NULL;
use winapi::um::handleapi::CloseHandle;
use winapi::um::processthreadsapi::GetCurrentProcess;
use winapi::um::processthreadsapi::GetPriorityClass;
use winapi::um::processthreadsapi::OpenProcess;
use winapi::um::processthreadsapi::SetPriorityClass;
use winapi::um::winbase::ABOVE_NORMAL_PRIORITY_CLASS;
use winapi::um::winbase::BELOW_NORMAL_PRIORITY_CLASS;
use winapi::um::winbase::HIGH_PRIORITY_CLASS;
use winapi::um::winbase::IDLE_PRIORITY_CLASS;
use winapi::um::winbase::NORMAL_PRIORITY_CLASS;
use winapi::um::winbase::REALTIME_PRIORITY_CLASS;
use winapi::um::winnt::PROCESS_QUERY_LIMITED_INFORMATION;
use winapi::um::winnt::PROCESS_SET_INFORMATION;
const PRIORITY_LOW: i32 = 19;
const PRIORITY_BELOW_NORMAL: i32 = 10;
const PRIORITY_NORMAL: i32 = 0;
const PRIORITY_ABOVE_NORMAL: i32 = -7;
const PRIORITY_HIGH: i32 = -14;
const PRIORITY_HIGHEST: i32 = -20;
pub fn get_priority(pid: u32) -> Result<i32, super::PriorityError> {
unsafe {
let handle = if pid == 0 {
GetCurrentProcess()
} else {
OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid as DWORD)
};
if handle == NULL {
Err(std::io::Error::last_os_error().into())
} else {
let result = match GetPriorityClass(handle) {
0 => Err(std::io::Error::last_os_error().into()),
REALTIME_PRIORITY_CLASS => Ok(PRIORITY_HIGHEST),
HIGH_PRIORITY_CLASS => Ok(PRIORITY_HIGH),
ABOVE_NORMAL_PRIORITY_CLASS => Ok(PRIORITY_ABOVE_NORMAL),
NORMAL_PRIORITY_CLASS => Ok(PRIORITY_NORMAL),
BELOW_NORMAL_PRIORITY_CLASS => Ok(PRIORITY_BELOW_NORMAL),
IDLE_PRIORITY_CLASS => Ok(PRIORITY_LOW),
_ => Ok(PRIORITY_LOW),
};
CloseHandle(handle);
result
}
}
}
pub fn set_priority(
pid: u32,
priority: i32,
) -> Result<(), super::PriorityError> {
unsafe {
let handle = if pid == 0 {
GetCurrentProcess()
} else {
OpenProcess(PROCESS_SET_INFORMATION, FALSE, pid as DWORD)
};
if handle == NULL {
Err(std::io::Error::last_os_error().into())
} else {
let priority_class =
if !(PRIORITY_HIGHEST..=PRIORITY_LOW).contains(&priority) {
return Err(super::PriorityError::InvalidPriority);
} else if priority < PRIORITY_HIGH {
REALTIME_PRIORITY_CLASS
} else if priority < PRIORITY_ABOVE_NORMAL {
HIGH_PRIORITY_CLASS
} else if priority < PRIORITY_NORMAL {
ABOVE_NORMAL_PRIORITY_CLASS
} else if priority < PRIORITY_BELOW_NORMAL {
NORMAL_PRIORITY_CLASS
} else if priority < PRIORITY_LOW {
BELOW_NORMAL_PRIORITY_CLASS
} else {
IDLE_PRIORITY_CLASS
};
let result = match SetPriorityClass(handle, priority_class) {
FALSE => Err(std::io::Error::last_os_error().into()),
_ => Ok(()),
};
CloseHandle(handle);
result
}
}
}
}