use winapi::ctypes::c_int;
use winapi::shared::minwindef::DWORD;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::processthreadsapi::{
GetCurrentThread, GetThreadPriority, SetThreadIdealProcessor, SetThreadPriority,
SetThreadPriorityBoost,
};
use winapi::um::winbase;
use winapi::um::winnt::HANDLE;
use crate::{Error, ThreadPriority};
pub type IdealProcessor = DWORD;
pub type ThreadId = HANDLE;
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum WinAPIThreadPriority {
BackgroundModeBegin = winbase::THREAD_MODE_BACKGROUND_BEGIN,
BackgroundModeEnd = winbase::THREAD_MODE_BACKGROUND_END,
AboveNormal = winbase::THREAD_PRIORITY_ABOVE_NORMAL,
BelowNormal = winbase::THREAD_PRIORITY_BELOW_NORMAL,
Highest = winbase::THREAD_PRIORITY_HIGHEST,
Idle = winbase::THREAD_PRIORITY_IDLE,
Lowest = winbase::THREAD_PRIORITY_LOWEST,
Normal = winbase::THREAD_PRIORITY_NORMAL,
TimeCritical = winbase::THREAD_PRIORITY_TIME_CRITICAL,
}
impl std::convert::TryFrom<ThreadPriority> for WinAPIThreadPriority {
type Error = crate::Error;
fn try_from(priority: ThreadPriority) -> Result<Self, Self::Error> {
Ok(match priority {
ThreadPriority::Min => WinAPIThreadPriority::Lowest,
ThreadPriority::Specific(p) => match p {
0 => WinAPIThreadPriority::Idle,
1..=19 => WinAPIThreadPriority::Lowest,
21..=39 => WinAPIThreadPriority::BelowNormal,
41..=59 => WinAPIThreadPriority::Normal,
61..=79 => WinAPIThreadPriority::AboveNormal,
81..=99 => WinAPIThreadPriority::Highest,
_ => return Err(Error::Priority("The value is out of range [0; 99]")),
},
ThreadPriority::Max => WinAPIThreadPriority::Highest,
})
}
}
impl std::convert::TryFrom<DWORD> for WinAPIThreadPriority {
type Error = crate::Error;
fn try_from(priority: DWORD) -> Result<Self, Self::Error> {
Ok(match priority {
winbase::THREAD_MODE_BACKGROUND_BEGIN => WinAPIThreadPriority::BackgroundModeBegin,
winbase::THREAD_MODE_BACKGROUND_END => WinAPIThreadPriority::BackgroundModeEnd,
winbase::THREAD_PRIORITY_ABOVE_NORMAL => WinAPIThreadPriority::AboveNormal,
winbase::THREAD_PRIORITY_BELOW_NORMAL => WinAPIThreadPriority::BelowNormal,
winbase::THREAD_PRIORITY_HIGHEST => WinAPIThreadPriority::Highest,
winbase::THREAD_PRIORITY_IDLE => WinAPIThreadPriority::Idle,
winbase::THREAD_PRIORITY_LOWEST => WinAPIThreadPriority::Lowest,
winbase::THREAD_PRIORITY_NORMAL => WinAPIThreadPriority::Normal,
winbase::THREAD_PRIORITY_TIME_CRITICAL => WinAPIThreadPriority::TimeCritical,
_ => return Err(Error::Priority("Priority couldn't be parsed")),
})
}
}
pub fn set_thread_priority(native: ThreadId, priority: ThreadPriority) -> Result<(), Error> {
use std::convert::TryFrom;
unsafe {
if SetThreadPriority(native, WinAPIThreadPriority::try_from(priority)? as c_int) != 0 {
Ok(())
} else {
Err(Error::OS(GetLastError() as i32))
}
}
}
pub fn set_current_thread_priority(priority: ThreadPriority) -> Result<(), Error> {
let thread_id = thread_native_id();
set_thread_priority(thread_id, priority)
}
pub fn thread_priority() -> Result<ThreadPriority, Error> {
use std::convert::TryFrom;
unsafe {
let ret = GetThreadPriority(thread_native_id());
if ret as u32 != winbase::THREAD_PRIORITY_ERROR_RETURN {
Ok(ThreadPriority::Specific(
WinAPIThreadPriority::try_from(ret as DWORD)? as u32,
))
} else {
Err(Error::OS(GetLastError() as i32))
}
}
}
pub fn thread_native_id() -> ThreadId {
unsafe { GetCurrentThread() }
}
pub fn set_thread_priority_boost(native: ThreadId, enabled: bool) -> Result<(), Error> {
unsafe {
if SetThreadPriorityBoost(native, enabled as i32) != 0 {
Ok(())
} else {
Err(Error::OS(GetLastError() as i32))
}
}
}
pub fn set_current_thread_priority_boost(enabled: bool) -> Result<(), Error> {
set_thread_priority_boost(thread_native_id(), enabled)
}
pub fn set_thread_ideal_processor(
native: ThreadId,
ideal_processor: IdealProcessor,
) -> Result<IdealProcessor, Error> {
unsafe {
let ret = SetThreadIdealProcessor(native, ideal_processor);
if ret == IdealProcessor::max_value() - 1 {
Err(Error::OS(GetLastError() as i32))
} else {
Ok(ret)
}
}
}
pub fn set_current_thread_ideal_processor(
ideal_processor: IdealProcessor,
) -> Result<IdealProcessor, Error> {
set_thread_ideal_processor(thread_native_id(), ideal_processor)
}