use core::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WaitPolicy {
idle_spin: Duration,
idle_runs_rayon: bool,
}
impl WaitPolicy {
pub const DEFAULT: WaitPolicy = WaitPolicy {
idle_spin: Duration::from_millis(200),
idle_runs_rayon: false,
};
pub const fn new(idle_spin: Duration, idle_runs_rayon: bool) -> Self {
WaitPolicy {
idle_spin,
idle_runs_rayon,
}
}
pub const fn idle_spin(&self) -> Duration {
self.idle_spin
}
pub const fn idle_runs_rayon(&self) -> bool {
self.idle_runs_rayon
}
#[must_use]
pub fn with(self, over: WaitOverride) -> Self {
WaitPolicy {
idle_spin: over.idle_spin.unwrap_or(self.idle_spin),
idle_runs_rayon: over.idle_runs_rayon.unwrap_or(self.idle_runs_rayon),
}
}
}
impl Default for WaitPolicy {
fn default() -> Self {
WaitPolicy::DEFAULT
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct WaitOverride {
pub(crate) idle_spin: Option<Duration>,
pub(crate) idle_runs_rayon: Option<bool>,
}
impl WaitOverride {
pub const fn new() -> Self {
WaitOverride {
idle_spin: None,
idle_runs_rayon: None,
}
}
#[must_use]
pub const fn idle_spin(mut self, spin: Duration) -> Self {
self.idle_spin = Some(spin);
self
}
#[must_use]
pub const fn idle_runs_rayon(mut self, on: bool) -> Self {
self.idle_runs_rayon = Some(on);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Qos {
Default,
Utility,
UserInitiated,
UserInteractive,
}
impl Qos {
#[cfg_attr(not(feature = "parallel"), allow(dead_code))]
pub(crate) const PLATFORM_DEFAULT: Option<Qos> = if cfg!(target_vendor = "apple") {
Some(Qos::UserInitiated)
} else {
None
};
#[cfg(feature = "parallel")]
pub(crate) fn apply_to_current_thread(self) {
self.apply_to_current_thread_always();
}
#[allow(dead_code)] pub(crate) fn apply_to_current_thread_always(self) {
#[cfg(target_vendor = "apple")]
{
let class = match self {
Qos::Default => libc::qos_class_t::QOS_CLASS_DEFAULT,
Qos::Utility => libc::qos_class_t::QOS_CLASS_UTILITY,
Qos::UserInitiated => libc::qos_class_t::QOS_CLASS_USER_INITIATED,
Qos::UserInteractive => libc::qos_class_t::QOS_CLASS_USER_INTERACTIVE,
};
unsafe {
libc::pthread_set_qos_class_self_np(class, 0);
}
}
#[cfg(not(target_vendor = "apple"))]
let _ = self;
}
}
pub fn raise_current_thread_qos(qos: Qos) {
#[cfg(target_vendor = "apple")]
{
use libc::qos_class_t as C;
let rank = |c: C| match c {
C::QOS_CLASS_USER_INTERACTIVE => 5,
C::QOS_CLASS_USER_INITIATED => 4,
C::QOS_CLASS_DEFAULT => 3,
C::QOS_CLASS_UTILITY => 2,
C::QOS_CLASS_BACKGROUND => 1,
_ => 0,
};
let wanted = match qos {
Qos::Default => C::QOS_CLASS_DEFAULT,
Qos::Utility => C::QOS_CLASS_UTILITY,
Qos::UserInitiated => C::QOS_CLASS_USER_INITIATED,
Qos::UserInteractive => C::QOS_CLASS_USER_INTERACTIVE,
};
let mut current = C::QOS_CLASS_UNSPECIFIED;
let mut relative = 0;
let ok = unsafe {
libc::pthread_get_qos_class_np(libc::pthread_self(), &mut current, &mut relative)
} == 0;
if !ok || rank(current) < rank(wanted) {
qos.apply_to_current_thread_always();
}
}
#[cfg(not(target_vendor = "apple"))]
let _ = qos;
}