From 8274d2d3fc798932210017fa89fb77f690900074 Mon Sep 17 00:00:00 2001 From: Luca Toniolo <10792599+grandixximo@users.noreply.github.com> Date: Tue, 2 Jun 2026 21:19:51 +0800 Subject: [PATCH 1/3] latency-test, latency-histogram: warn when rtapi_app lacks RT privileges Without 'sudo make setuid' (or 'sudo make setcap') rtapi_app runs unprivileged: no SCHED_FIFO, no locked memory, so latency readings are wildly inflated and easy to mistake for a code regression. Warn, for a non-root user, when rtapi_app is neither setuid root nor carries the cap_sys_nice capability. Closes #4044 --- scripts/latency-histogram | 21 +++++++++++++++++++++ scripts/latency-test | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/scripts/latency-histogram b/scripts/latency-histogram index 014b63f582f..cf9fc662b27 100755 --- a/scripts/latency-histogram +++ b/scripts/latency-histogram @@ -111,6 +111,26 @@ proc which_exe {name} { return -code error "$name: executable not found" } ;# which_exe +proc check_rt_privileges {} { + # Without 'sudo make setuid' (or 'sudo make setcap') rtapi_app runs + # unprivileged: realtime threads get no SCHED_FIFO and no locked memory, so + # the latency readings are wildly inflated. Warn rather than mislead. + if {![catch {exec id -u} uid] && $uid == 0} return ;# root has every privilege + if {[catch {which_exe rtapi_app} rtapi]} return ;# cannot locate, stay quiet + if {![catch {file attributes $rtapi -permissions} mode] && ($mode & 04000)} return ;# setuid root + if {![catch {exec getcap $rtapi} caps] && [string match *cap_sys_nice* $caps]} return ;# file caps + set msg "Warning: rtapi_app is not setuid root and has no realtime capabilities." + append msg "\nRealtime threads get no SCHED_FIFO priority or locked memory," + append msg "\nso the latency shown will be far worse than reality." + append msg "\nRun 'sudo make setuid' (or 'sudo make setcap') in src/." + puts stderr $msg + if {$::LH(use_x)} { + package require Tk + tk_messageBox -parent . -icon warning -type ok \ + -title "Latency Warning" -message $msg + } +} ;# check_rt_privileges + proc program_check {plist} { foreach prog $plist { if [catch { @@ -944,6 +964,7 @@ proc windowToFile { win } { if ![info exists ::LH(start)] { set_defaults config + check_rt_privileges progress "Loading packages" load_packages signal trap SIGINT finish diff --git a/scripts/latency-test b/scripts/latency-test index 63b34c0034d..334cee44e07 100755 --- a/scripts/latency-test +++ b/scripts/latency-test @@ -16,6 +16,25 @@ kversion=$(uname -v) calc() { awk "BEGIN { print ($1); }" < /dev/null; } icalc() { awk "BEGIN { printf \"%.0f\n\", ($1); }" < /dev/null; } +# Without 'sudo make setuid' (or 'sudo make setcap') rtapi_app runs +# unprivileged: realtime threads get no SCHED_FIFO and no locked memory, so the +# latency readings are wildly inflated. Warn rather than mislead. +check_rt_privileges () { + [ "$(id -u)" = 0 ] && return 0 # root has every privilege + rtapi_app=$(command -v rtapi_app) || return 0 + [ -n "$rtapi_app" ] || return 0 + [ -u "$rtapi_app" ] && return 0 # setuid root + if command -v getcap >/dev/null 2>&1; then + case $(getcap "$rtapi_app" 2>/dev/null) in + *cap_sys_nice*) return 0 ;; # file capabilities + esac + fi + echo "Warning: rtapi_app is not setuid root and has no realtime capabilities." >&2 + echo " Realtime threads get no SCHED_FIFO priority or locked memory," >&2 + echo " so the latency shown will be far worse than reality." >&2 + echo " Run 'sudo make setuid' (or 'sudo make setcap') in src/." >&2 +} + parse_time () { case $1 in -) echo "0" ;; @@ -170,4 +189,6 @@ L=\$(($SIGNALS echo \$L > "$HOME"/.latency EOF +check_rt_privileges + halrun lat.hal From ecc6b299dabf83b1a7fe0fbd8d7e3f208683204c Mon Sep 17 00:00:00 2001 From: Luca Toniolo <10792599+grandixximo@users.noreply.github.com> Date: Tue, 2 Jun 2026 22:25:37 +0800 Subject: [PATCH 2/3] latency: skip RT-privilege warning on non-RT kernels Only warn under PREEMPT_RT or RTAI; on a non-RT kernel the privileges do not matter, so the check would be noise. --- scripts/latency-histogram | 5 +++++ scripts/latency-test | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/scripts/latency-histogram b/scripts/latency-histogram index cf9fc662b27..160da08ba4f 100755 --- a/scripts/latency-histogram +++ b/scripts/latency-histogram @@ -115,6 +115,11 @@ proc check_rt_privileges {} { # Without 'sudo make setuid' (or 'sudo make setcap') rtapi_app runs # unprivileged: realtime threads get no SCHED_FIFO and no locked memory, so # the latency readings are wildly inflated. Warn rather than mislead. + # Only meaningful on an RT-capable kernel; stay quiet on non-RT (e.g. dev). + set rt 0 + if {![catch {exec uname -v} kv] && [string match *PREEMPT_RT* $kv]} {set rt 1} + if {[string first rtai [string tolower $::tcl_platform(osVersion)]] >= 0} {set rt 1} + if {!$rt} return if {![catch {exec id -u} uid] && $uid == 0} return ;# root has every privilege if {[catch {which_exe rtapi_app} rtapi]} return ;# cannot locate, stay quiet if {![catch {file attributes $rtapi -permissions} mode] && ($mode & 04000)} return ;# setuid root diff --git a/scripts/latency-test b/scripts/latency-test index 334cee44e07..94bab7e1dcf 100755 --- a/scripts/latency-test +++ b/scripts/latency-test @@ -20,6 +20,11 @@ icalc() { awk "BEGIN { printf \"%.0f\n\", ($1); }" < /dev/null; } # unprivileged: realtime threads get no SCHED_FIFO and no locked memory, so the # latency readings are wildly inflated. Warn rather than mislead. check_rt_privileges () { + # only meaningful on an RT-capable kernel; stay quiet on non-RT (e.g. dev) + case "$(uname -v) $(uname -r)" in + *PREEMPT_RT*|*rtai*) ;; + *) return 0 ;; + esac [ "$(id -u)" = 0 ] && return 0 # root has every privilege rtapi_app=$(command -v rtapi_app) || return 0 [ -n "$rtapi_app" ] || return 0 From a3df81c6c06486f17790f36817f1c52f7bb31957 Mon Sep 17 00:00:00 2001 From: Luca Toniolo <10792599+grandixximo@users.noreply.github.com> Date: Fri, 5 Jun 2026 08:38:15 +0800 Subject: [PATCH 3/3] latency: detect realtime via halcmd getrt instead of setuid heuristic Query realtime status with 'halcmd getrt' (hdiethelm's PR) rather than probing the setuid bit. latency-histogram asks inside its own running session, so no stray HAL segment is created. latency-test drops its check and relies on the existing "POSIX non-realtime" note. --- scripts/latency-histogram | 25 +++++++++---------------- scripts/latency-test | 26 -------------------------- 2 files changed, 9 insertions(+), 42 deletions(-) diff --git a/scripts/latency-histogram b/scripts/latency-histogram index 160da08ba4f..4ccd70a820e 100755 --- a/scripts/latency-histogram +++ b/scripts/latency-histogram @@ -112,22 +112,15 @@ proc which_exe {name} { } ;# which_exe proc check_rt_privileges {} { - # Without 'sudo make setuid' (or 'sudo make setcap') rtapi_app runs - # unprivileged: realtime threads get no SCHED_FIFO and no locked memory, so - # the latency readings are wildly inflated. Warn rather than mislead. - # Only meaningful on an RT-capable kernel; stay quiet on non-RT (e.g. dev). - set rt 0 - if {![catch {exec uname -v} kv] && [string match *PREEMPT_RT* $kv]} {set rt 1} - if {[string first rtai [string tolower $::tcl_platform(osVersion)]] >= 0} {set rt 1} - if {!$rt} return - if {![catch {exec id -u} uid] && $uid == 0} return ;# root has every privilege - if {[catch {which_exe rtapi_app} rtapi]} return ;# cannot locate, stay quiet - if {![catch {file attributes $rtapi -permissions} mode] && ($mode & 04000)} return ;# setuid root - if {![catch {exec getcap $rtapi} caps] && [string match *cap_sys_nice* $caps]} return ;# file caps - set msg "Warning: rtapi_app is not setuid root and has no realtime capabilities." - append msg "\nRealtime threads get no SCHED_FIFO priority or locked memory," + # Query the running session (realtime already up) via 'halcmd getrt'. + # Warn on "No realtime available", usually a missing 'sudo make setuid'. + set out "" + catch {exec $::LH(prog,halcmd) getrt 2>@1} out + if {![string match {*No realtime available*} $out]} return + set msg "Warning: realtime is not available." + append msg "\nThreads get no SCHED_FIFO priority or locked memory," append msg "\nso the latency shown will be far worse than reality." - append msg "\nRun 'sudo make setuid' (or 'sudo make setcap') in src/." + append msg "\nOn a run-in-place build, run 'sudo make setuid' (or 'sudo make setcap') in src/." puts stderr $msg if {$::LH(use_x)} { package require Tk @@ -647,6 +640,7 @@ proc start_collection {} { } } hal start + check_rt_privileges if {!$::LH(legacy)} { # Attach the Tcl hal_stream binding (added in halsh.c) to each # thread's latencybinstream FIFO. The handle stays open for the @@ -969,7 +963,6 @@ proc windowToFile { win } { if ![info exists ::LH(start)] { set_defaults config - check_rt_privileges progress "Loading packages" load_packages signal trap SIGINT finish diff --git a/scripts/latency-test b/scripts/latency-test index 94bab7e1dcf..63b34c0034d 100755 --- a/scripts/latency-test +++ b/scripts/latency-test @@ -16,30 +16,6 @@ kversion=$(uname -v) calc() { awk "BEGIN { print ($1); }" < /dev/null; } icalc() { awk "BEGIN { printf \"%.0f\n\", ($1); }" < /dev/null; } -# Without 'sudo make setuid' (or 'sudo make setcap') rtapi_app runs -# unprivileged: realtime threads get no SCHED_FIFO and no locked memory, so the -# latency readings are wildly inflated. Warn rather than mislead. -check_rt_privileges () { - # only meaningful on an RT-capable kernel; stay quiet on non-RT (e.g. dev) - case "$(uname -v) $(uname -r)" in - *PREEMPT_RT*|*rtai*) ;; - *) return 0 ;; - esac - [ "$(id -u)" = 0 ] && return 0 # root has every privilege - rtapi_app=$(command -v rtapi_app) || return 0 - [ -n "$rtapi_app" ] || return 0 - [ -u "$rtapi_app" ] && return 0 # setuid root - if command -v getcap >/dev/null 2>&1; then - case $(getcap "$rtapi_app" 2>/dev/null) in - *cap_sys_nice*) return 0 ;; # file capabilities - esac - fi - echo "Warning: rtapi_app is not setuid root and has no realtime capabilities." >&2 - echo " Realtime threads get no SCHED_FIFO priority or locked memory," >&2 - echo " so the latency shown will be far worse than reality." >&2 - echo " Run 'sudo make setuid' (or 'sudo make setcap') in src/." >&2 -} - parse_time () { case $1 in -) echo "0" ;; @@ -194,6 +170,4 @@ L=\$(($SIGNALS echo \$L > "$HOME"/.latency EOF -check_rt_privileges - halrun lat.hal