Extract platform-specific QoS code into module
This commit is contained in:
parent
bb02ae7532
commit
a416248296
@ -207,105 +207,120 @@ pub enum QoSClass {
|
|||||||
UserInteractive,
|
UserInteractive,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_vendor = "apple")]
|
pub const IS_QOS_AVAILABLE: bool = imp::IS_QOS_AVAILABLE;
|
||||||
pub const IS_QOS_AVAILABLE: bool = true;
|
|
||||||
|
|
||||||
#[cfg(not(target_vendor = "apple"))]
|
pub fn set_current_thread_qos_class(class: QoSClass) {
|
||||||
pub const IS_QOS_AVAILABLE: bool = false;
|
imp::set_current_thread_qos_class(class)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_current_thread_qos_class() -> Option<QoSClass> {
|
||||||
|
imp::get_current_thread_qos_class()
|
||||||
|
}
|
||||||
|
|
||||||
// All Apple platforms use XNU as their kernel
|
// All Apple platforms use XNU as their kernel
|
||||||
// and thus have the concept of QoS.
|
// and thus have the concept of QoS.
|
||||||
#[cfg(target_vendor = "apple")]
|
#[cfg(target_vendor = "apple")]
|
||||||
pub fn set_current_thread_qos_class(class: QoSClass) {
|
mod imp {
|
||||||
let c = match class {
|
use super::QoSClass;
|
||||||
QoSClass::UserInteractive => libc::qos_class_t::QOS_CLASS_USER_INTERACTIVE,
|
|
||||||
QoSClass::UserInitiated => libc::qos_class_t::QOS_CLASS_USER_INITIATED,
|
|
||||||
QoSClass::Utility => libc::qos_class_t::QOS_CLASS_UTILITY,
|
|
||||||
QoSClass::Background => libc::qos_class_t::QOS_CLASS_BACKGROUND,
|
|
||||||
};
|
|
||||||
|
|
||||||
let code = unsafe { libc::pthread_set_qos_class_self_np(c, 0) };
|
pub(super) const IS_QOS_AVAILABLE: bool = true;
|
||||||
|
|
||||||
if code == 0 {
|
pub(super) fn set_current_thread_qos_class(class: QoSClass) {
|
||||||
return;
|
let c = match class {
|
||||||
}
|
QoSClass::UserInteractive => libc::qos_class_t::QOS_CLASS_USER_INTERACTIVE,
|
||||||
|
QoSClass::UserInitiated => libc::qos_class_t::QOS_CLASS_USER_INITIATED,
|
||||||
|
QoSClass::Utility => libc::qos_class_t::QOS_CLASS_UTILITY,
|
||||||
|
QoSClass::Background => libc::qos_class_t::QOS_CLASS_BACKGROUND,
|
||||||
|
};
|
||||||
|
|
||||||
let errno = unsafe { *libc::__error() };
|
let code = unsafe { libc::pthread_set_qos_class_self_np(c, 0) };
|
||||||
|
|
||||||
match errno {
|
if code == 0 {
|
||||||
libc::EPERM => {
|
return;
|
||||||
// This thread has been excluded from the QoS system
|
|
||||||
// due to a previous call to a function such as `pthread_setschedparam`
|
|
||||||
// which is incompatible with QoS.
|
|
||||||
//
|
|
||||||
// Panic instead of returning an error
|
|
||||||
// to maintain the invariant that we only use QoS APIs.
|
|
||||||
panic!("tried to set QoS of thread which has opted out of QoS (os error {errno})")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
libc::EINVAL => {
|
|
||||||
// This is returned if we pass something other than a qos_class_t
|
|
||||||
// to `pthread_set_qos_class_self_np`.
|
|
||||||
//
|
|
||||||
// This is impossible, so again panic.
|
|
||||||
unreachable!("invalid qos_class_t value was passed to pthread_set_qos_class_self_np")
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
// `pthread_set_qos_class_self_np`’s documentation
|
|
||||||
// does not mention any other errors.
|
|
||||||
unreachable!("`pthread_set_qos_class_self_np` returned unexpected error {errno}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_vendor = "apple"))]
|
|
||||||
pub fn set_current_thread_qos_class(class: QoSClass) {
|
|
||||||
// FIXME: Windows has QoS APIs, we should use them!
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_vendor = "apple")]
|
|
||||||
pub fn get_current_thread_qos_class() -> Option<QoSClass> {
|
|
||||||
let current_thread = unsafe { libc::pthread_self() };
|
|
||||||
let mut qos_class_raw = libc::qos_class_t::QOS_CLASS_UNSPECIFIED;
|
|
||||||
let code = unsafe {
|
|
||||||
libc::pthread_get_qos_class_np(current_thread, &mut qos_class_raw, std::ptr::null_mut())
|
|
||||||
};
|
|
||||||
|
|
||||||
if code != 0 {
|
|
||||||
// `pthread_get_qos_class_np`’s documentation states that
|
|
||||||
// an error value is placed into errno if the return code is not zero.
|
|
||||||
// However, it never states what errors are possible.
|
|
||||||
// Inspecting the source[0] shows that, as of this writing, it always returns zero.
|
|
||||||
//
|
|
||||||
// Whatever errors the function could report in future are likely to be
|
|
||||||
// ones which we cannot handle anyway
|
|
||||||
//
|
|
||||||
// 0: https://github.com/apple-oss-distributions/libpthread/blob/67e155c94093be9a204b69637d198eceff2c7c46/src/qos.c#L171-L177
|
|
||||||
let errno = unsafe { *libc::__error() };
|
let errno = unsafe { *libc::__error() };
|
||||||
unreachable!("`pthread_get_qos_class_np` failed unexpectedly (os error {errno})");
|
|
||||||
|
match errno {
|
||||||
|
libc::EPERM => {
|
||||||
|
// This thread has been excluded from the QoS system
|
||||||
|
// due to a previous call to a function such as `pthread_setschedparam`
|
||||||
|
// which is incompatible with QoS.
|
||||||
|
//
|
||||||
|
// Panic instead of returning an error
|
||||||
|
// to maintain the invariant that we only use QoS APIs.
|
||||||
|
panic!("tried to set QoS of thread which has opted out of QoS (os error {errno})")
|
||||||
|
}
|
||||||
|
|
||||||
|
libc::EINVAL => {
|
||||||
|
// This is returned if we pass something other than a qos_class_t
|
||||||
|
// to `pthread_set_qos_class_self_np`.
|
||||||
|
//
|
||||||
|
// This is impossible, so again panic.
|
||||||
|
unreachable!(
|
||||||
|
"invalid qos_class_t value was passed to pthread_set_qos_class_self_np"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
// `pthread_set_qos_class_self_np`’s documentation
|
||||||
|
// does not mention any other errors.
|
||||||
|
unreachable!("`pthread_set_qos_class_self_np` returned unexpected error {errno}")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match qos_class_raw {
|
pub(super) fn get_current_thread_qos_class() -> Option<QoSClass> {
|
||||||
libc::qos_class_t::QOS_CLASS_USER_INTERACTIVE => Some(QoSClass::UserInteractive),
|
let current_thread = unsafe { libc::pthread_self() };
|
||||||
libc::qos_class_t::QOS_CLASS_USER_INITIATED => Some(QoSClass::UserInitiated),
|
let mut qos_class_raw = libc::qos_class_t::QOS_CLASS_UNSPECIFIED;
|
||||||
libc::qos_class_t::QOS_CLASS_DEFAULT => None, // QoS has never been set
|
let code = unsafe {
|
||||||
libc::qos_class_t::QOS_CLASS_UTILITY => Some(QoSClass::Utility),
|
libc::pthread_get_qos_class_np(current_thread, &mut qos_class_raw, std::ptr::null_mut())
|
||||||
libc::qos_class_t::QOS_CLASS_BACKGROUND => Some(QoSClass::Background),
|
};
|
||||||
|
|
||||||
libc::qos_class_t::QOS_CLASS_UNSPECIFIED => {
|
if code != 0 {
|
||||||
// Using manual scheduling APIs causes threads to “opt out” of QoS.
|
// `pthread_get_qos_class_np`’s documentation states that
|
||||||
// At this point they become incompatible with QoS,
|
// an error value is placed into errno if the return code is not zero.
|
||||||
// and as such have the “unspecified” QoS class.
|
// However, it never states what errors are possible.
|
||||||
|
// Inspecting the source[0] shows that, as of this writing, it always returns zero.
|
||||||
//
|
//
|
||||||
// Panic instead of returning an error
|
// Whatever errors the function could report in future are likely to be
|
||||||
// to maintain the invariant that we only use QoS APIs.
|
// ones which we cannot handle anyway
|
||||||
panic!("tried to get QoS of thread which has opted out of QoS")
|
//
|
||||||
|
// 0: https://github.com/apple-oss-distributions/libpthread/blob/67e155c94093be9a204b69637d198eceff2c7c46/src/qos.c#L171-L177
|
||||||
|
let errno = unsafe { *libc::__error() };
|
||||||
|
unreachable!("`pthread_get_qos_class_np` failed unexpectedly (os error {errno})");
|
||||||
|
}
|
||||||
|
|
||||||
|
match qos_class_raw {
|
||||||
|
libc::qos_class_t::QOS_CLASS_USER_INTERACTIVE => Some(QoSClass::UserInteractive),
|
||||||
|
libc::qos_class_t::QOS_CLASS_USER_INITIATED => Some(QoSClass::UserInitiated),
|
||||||
|
libc::qos_class_t::QOS_CLASS_DEFAULT => None, // QoS has never been set
|
||||||
|
libc::qos_class_t::QOS_CLASS_UTILITY => Some(QoSClass::Utility),
|
||||||
|
libc::qos_class_t::QOS_CLASS_BACKGROUND => Some(QoSClass::Background),
|
||||||
|
|
||||||
|
libc::qos_class_t::QOS_CLASS_UNSPECIFIED => {
|
||||||
|
// Using manual scheduling APIs causes threads to “opt out” of QoS.
|
||||||
|
// At this point they become incompatible with QoS,
|
||||||
|
// and as such have the “unspecified” QoS class.
|
||||||
|
//
|
||||||
|
// Panic instead of returning an error
|
||||||
|
// to maintain the invariant that we only use QoS APIs.
|
||||||
|
panic!("tried to get QoS of thread which has opted out of QoS")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Windows has QoS APIs, we should use them!
|
||||||
#[cfg(not(target_vendor = "apple"))]
|
#[cfg(not(target_vendor = "apple"))]
|
||||||
pub fn get_current_thread_qos_class() -> Option<QoSClass> {
|
mod imp {
|
||||||
None
|
use super::QoSClass;
|
||||||
|
|
||||||
|
pub(super) const IS_QOS_AVAILABLE: bool = false;
|
||||||
|
|
||||||
|
pub(super) fn set_current_thread_qos_class(_: QoSClass) {}
|
||||||
|
|
||||||
|
pub(super) fn get_current_thread_qos_class() -> Option<QoSClass> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user