This commit is contained in:
2026-02-03 03:08:13 +01:00
parent 5c805c60d7
commit a07a87a35f
6 changed files with 129 additions and 95 deletions

View File

@@ -6,13 +6,9 @@ use std::sync::atomic::AtomicU32;
use std::sync::atomic::{AtomicI64, AtomicU64};
use std::sync::Arc;
use std::thread::{self, JoinHandle};
use std::time::Duration;
#[cfg(not(unix))]
use thread_priority::set_current_thread_priority;
#[allow(unused_imports)]
use thread_priority::ThreadPriority;
use super::dispatcher::{dispatcher_loop, DispatchCommand, TimedCommand};
use super::realtime::{precise_sleep_us, set_realtime_priority};
use super::{micros_until_next_substep, substeps_crossed, LinkState, StepTiming, SyncTime};
use crate::model::{
CcAccess, Dictionary, ExecutionTrace, Rng, ScriptEngine, StepContext, Value, Variables,
@@ -1188,74 +1184,6 @@ fn sequencer_loop(
/// spinning is counterproductive and we sleep the entire duration.
const SPIN_THRESHOLD_US: SyncTime = 100;
/// High-precision sleep using clock_nanosleep on Linux
#[cfg(target_os = "linux")]
fn precise_sleep(micros: u64) {
let duration_ns = micros * 1000;
let ts = libc::timespec {
tv_sec: (duration_ns / 1_000_000_000) as i64,
tv_nsec: (duration_ns % 1_000_000_000) as i64,
};
unsafe {
libc::clock_nanosleep(libc::CLOCK_MONOTONIC, 0, &ts, std::ptr::null_mut());
}
}
#[cfg(not(target_os = "linux"))]
fn precise_sleep(micros: u64) {
thread::sleep(Duration::from_micros(micros));
}
/// Attempts to set realtime scheduling priority for the current thread.
/// Returns true if RT priority was successfully set, false otherwise.
///
/// On Linux, this requires either:
/// - CAP_SYS_NICE capability, or
/// - Configured rtprio limits in /etc/security/limits.conf:
/// @audio - rtprio 95
/// @audio - memlock unlimited
#[cfg(unix)]
pub fn set_realtime_priority() -> bool {
use thread_priority::unix::{
set_thread_priority_and_policy, thread_native_id, NormalThreadSchedulePolicy,
RealtimeThreadSchedulePolicy, ThreadSchedulePolicy,
};
use thread_priority::ThreadPriority;
let tid = thread_native_id();
// Try SCHED_FIFO first (requires CAP_SYS_NICE on Linux)
let fifo = ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Fifo);
if set_thread_priority_and_policy(tid, ThreadPriority::Max, fifo).is_ok() {
return true;
}
// Try SCHED_RR (round-robin realtime, sometimes works without caps)
let rr = ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::RoundRobin);
if set_thread_priority_and_policy(tid, ThreadPriority::Max, rr).is_ok() {
return true;
}
// Fall back to highest normal priority (SCHED_OTHER)
let _ = set_thread_priority_and_policy(
tid,
ThreadPriority::Max,
ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Other),
);
// Also try nice -20 on Linux
#[cfg(target_os = "linux")]
unsafe {
libc::setpriority(libc::PRIO_PROCESS, 0, -20);
}
false
}
#[cfg(not(unix))]
pub fn set_realtime_priority() -> bool {
set_current_thread_priority(ThreadPriority::Max).is_ok()
}
/// Two-phase wait: sleep most of the time, optionally spin-wait for final precision.
/// With RT priority: sleep + spin for precision
@@ -1267,7 +1195,7 @@ fn wait_until(target_us: SyncTime, link: &LinkState, has_rt_priority: bool) {
if has_rt_priority {
// With RT priority: sleep most, spin for final precision
if remaining > SPIN_THRESHOLD_US {
precise_sleep(remaining - SPIN_THRESHOLD_US);
precise_sleep_us(remaining - SPIN_THRESHOLD_US);
}
while (link.clock_micros() as SyncTime) < target_us {
std::hint::spin_loop();
@@ -1275,7 +1203,7 @@ fn wait_until(target_us: SyncTime, link: &LinkState, has_rt_priority: bool) {
} else {
// Without RT priority: sleep the entire time (spin-waiting is counterproductive)
if remaining > 0 {
precise_sleep(remaining);
precise_sleep_us(remaining);
}
}
}