Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@ jobs:
- name: Test
shell: bash
run: rustup run ${{ matrix.rust }} cargo test --all
# setrlimit64 error in the CI container, macOS not supported
if: matrix.os != 'ubuntu-24.04' && matrix.os != 'macos-14'
# setrlimit64 error in the CI container
if: matrix.os != 'ubuntu-24.04'
2 changes: 0 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,6 @@ impl Error for AudioThreadPriorityError {
cfg_if! {
if #[cfg(target_os = "macos")] {
mod rt_mach;
#[allow(unused, non_camel_case_types, non_snake_case, non_upper_case_globals)]
mod mach_sys;
extern crate mach2;
extern crate libc;
use rt_mach::promote_current_thread_to_real_time_internal;
Expand Down
36 changes: 0 additions & 36 deletions src/mach_sys.rs

This file was deleted.

63 changes: 27 additions & 36 deletions src/rt_mach.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,15 @@
use crate::mach_sys::*;
use crate::AudioThreadPriorityError;
use libc::{pthread_self, pthread_t};
use libc::{pthread_mach_thread_np, pthread_self, thread_policy_t};
use log::info;
use mach2::boolean::boolean_t;
use mach2::kern_return::{kern_return_t, KERN_SUCCESS};
use mach2::mach_time::{mach_timebase_info, mach_timebase_info_data_t};
use mach2::message::mach_msg_type_number_t;
use mach2::port::mach_port_t;
use std::mem::size_of;

extern "C" {
fn pthread_mach_thread_np(tid: pthread_t) -> mach_port_t;
// Those functions are commented out in thread_policy.h but somehow it works just fine !?
fn thread_policy_set(
thread: thread_t,
flavor: thread_policy_flavor_t,
policy_info: thread_policy_t,
count: mach_msg_type_number_t,
) -> kern_return_t;
fn thread_policy_get(
thread: thread_t,
flavor: thread_policy_flavor_t,
policy_info: thread_policy_t,
count: &mut mach_msg_type_number_t,
get_default: &mut boolean_t,
) -> kern_return_t;
}

// can't use size_of in const fn just now in stable, use a macro for now.
macro_rules! THREAD_TIME_CONSTRAINT_POLICY_COUNT {
() => {
(size_of::<thread_time_constraint_policy_data_t>() / size_of::<integer_t>()) as u32
};
}
use mach2::thread_policy::{
thread_policy_get, thread_policy_set, thread_time_constraint_policy_data_t,
THREAD_TIME_CONSTRAINT_POLICY, THREAD_TIME_CONSTRAINT_POLICY_COUNT,
};

#[derive(Debug)]
pub struct RtPriorityHandleInternal {
Expand Down Expand Up @@ -68,7 +46,7 @@ pub fn demote_current_thread_from_real_time_internal(
h.tid,
THREAD_TIME_CONSTRAINT_POLICY,
(&mut h.previous_time_constraint_policy) as *mut _ as thread_policy_t,
THREAD_TIME_CONSTRAINT_POLICY_COUNT!(),
THREAD_TIME_CONSTRAINT_POLICY_COUNT,
);
if rv != KERN_SUCCESS {
return Err(AudioThreadPriorityError::new(
Expand Down Expand Up @@ -110,7 +88,7 @@ pub fn promote_current_thread_to_real_time_internal(
// returning, it means there are no current settings because of other factor, and the
// default was returned instead.
let mut get_default: boolean_t = 0;
let mut count: mach_msg_type_number_t = THREAD_TIME_CONSTRAINT_POLICY_COUNT!();
let mut count: mach_msg_type_number_t = THREAD_TIME_CONSTRAINT_POLICY_COUNT;
let mut rv: kern_return_t = thread_policy_get(
tid,
THREAD_TIME_CONSTRAINT_POLICY,
Expand All @@ -127,18 +105,31 @@ pub fn promote_current_thread_to_real_time_internal(

rt_priority_handle.previous_time_constraint_policy = time_constraints;

let cb_duration = buffer_frames as f32 / (audio_samplerate_hz as f32) * 1000.;
// The multiplicators are somwhat arbitrary for now.

let mut timebase_info = mach_timebase_info_data_t { denom: 0, numer: 0 };
mach_timebase_info(&mut timebase_info);

let ms2abs: f32 = ((timebase_info.denom as f32) / timebase_info.numer as f32) * 1000000.;

// Computation time is half of constraint, per macOS 12 behaviour.
// The time constraint calculations are somewhat arbitrary for now.
let cb_duration = buffer_frames as f32 / (audio_samplerate_hz as f32) * 1000.;

// Computation time is half of constraint, per macOS 12 behaviour. And capped at 50ms per macOS limits:
// https://github.com/apple-oss-distributions/xnu/blob/e3723e1f17661b24996789d8afc084c0c3303b26/osfmk/kern/thread_policy.c#L408
// https://github.com/apple-oss-distributions/xnu/blob/e3723e1f17661b24996789d8afc084c0c3303b26/osfmk/kern/sched_prim.c#L822
const MAX_RT_QUANTUM: f32 = 50.0;
let computation = cb_duration / 2.0;
let computation = if computation > MAX_RT_QUANTUM {
info!(
"thread computation time capped at {MAX_RT_QUANTUM}ms ({computation}ms requested)."
);
MAX_RT_QUANTUM
} else {
computation
};

time_constraints = thread_time_constraint_policy_data_t {
period: (cb_duration * ms2abs) as u32,
computation: (cb_duration / 2.0 * ms2abs) as u32,
computation: (computation * ms2abs) as u32,
constraint: (cb_duration * ms2abs) as u32,
preemptible: 1, // true
};
Expand All @@ -147,7 +138,7 @@ pub fn promote_current_thread_to_real_time_internal(
tid,
THREAD_TIME_CONSTRAINT_POLICY,
(&mut time_constraints) as *mut _ as thread_policy_t,
THREAD_TIME_CONSTRAINT_POLICY_COUNT!(),
THREAD_TIME_CONSTRAINT_POLICY_COUNT,
);
if rv != KERN_SUCCESS {
return Err(AudioThreadPriorityError::new(
Expand Down
Loading