From 5ef749149e85e87371e66c926ce4285c71dc1bc5 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Tue, 30 Jun 2026 15:18:42 +0200 Subject: [PATCH 1/7] rtapi_app: start command / autostop removed This gives rtapi_app a deterministic behavior. No other changes needed except implementing start / stop in realtime due to all apps run: realtime start at startup realtime stop at exit Autostart is still available with a deprecation message to not break existing setups. But it is done in a different way by forking and then sending the command over the socket. This allows for easy separation into master / client in the future. --- scripts/realtime.in | 22 +++-- src/rtapi/uspace_rtapi_main.cc | 153 +++++++++++++++++++++------------ 2 files changed, 110 insertions(+), 65 deletions(-) diff --git a/scripts/realtime.in b/scripts/realtime.in index bcedea7f3f5..f9daf72d38f 100644 --- a/scripts/realtime.in +++ b/scripts/realtime.in @@ -170,14 +170,20 @@ CheckMem(){ Load(){ CheckKernel - for MOD in $MODULES_LOAD ; do - if ! [ -d "/sys/module/$(basename "$MOD" .ko)" ]; then - $INSMOD "$MOD" || return $? - fi - done - if [ "$DEBUG" != "" ] && [ -w /proc/rtapi/debug ] ; then - echo "$DEBUG" > /proc/rtapi/debug - fi + case $RTPREFIX in + uspace) + rtapi_app start + ;; + (*rtai*) + for MOD in $MODULES_LOAD ; do + if ! [ -d "/sys/module/$(basename "$MOD" .ko)" ]; then + $INSMOD "$MOD" || return $? + fi + done + if [ "$DEBUG" != "" ] && [ -w /proc/rtapi/debug ] ; then + echo "$DEBUG" > /proc/rtapi/debug + fi + esac } CheckLoaded(){ diff --git a/src/rtapi/uspace_rtapi_main.cc b/src/rtapi/uspace_rtapi_main.cc index 9affbd788d3..b9b35f0c57c 100644 --- a/src/rtapi/uspace_rtapi_main.cc +++ b/src/rtapi/uspace_rtapi_main.cc @@ -880,7 +880,10 @@ static int handle_command(const std::vector &args, std::string &out if (args.size() == 0) { return 0; } - if (args.size() == 1 && args[0] == "exit") { + if (args.size() == 1 && args[0] == "start") { + rtapi_print_msg(RTAPI_MSG_ERR, "rtapi_app: start received while running\n"); + return 0; + } else if (args.size() == 1 && args[0] == "exit") { force_exit = 1; return 0; } else if (args.size() >= 2 && args[0] == "load") { @@ -898,7 +901,7 @@ static int handle_command(const std::vector &args, std::string &out } else if (args.size() == 1 && args[0] == "check_rt") { return do_check_rt_cmd(out); } else { - rtapi_print_msg(RTAPI_MSG_ERR, "Unrecognized command starting with %s\n", args[0].c_str()); + rtapi_print_msg(RTAPI_MSG_ERR, "rtapi_app: unrecognized command starting with %s\n", args[0].c_str()); return -1; } } @@ -962,12 +965,12 @@ static bool master_process_socket_command(int fd) { } close(fd1); } - return !force_exit && instance_count > 0; + return !force_exit; } static pthread_t main_thread{}; -static int master(int fd, const std::vector &args) { +static int master(int fd) { is_master = true; main_thread = pthread_self(); int result; @@ -977,22 +980,9 @@ static int master(int fd, const std::vector &args) { return -1; } do_load_cmd("hal_lib", std::vector()); - instance_count = 0; App(); // force rtapi_app to be created - if (args.size()) { - std::string out; - result = handle_command(args, out); - if (result != 0) - goto out; - if (force_exit || instance_count == 0) - goto out; - if (out.length() > 0) { - printf("%s\n", out.c_str()); - } - } //Process commands as long as master should not exit while(master_process_socket_command(fd)); -out: do_unload_cmd("hal_lib"); pthread_cancel(queue_thread); pthread_join(queue_thread, nullptr); @@ -1045,6 +1035,65 @@ static double diff_timespec(const struct timespec *time1, const struct timespec static void raise_net_admin_ambient(void); #endif +static int create_socket(){ + int fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + perror("socket"); + return fd; + } + + int enable = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); + return fd; +} + +static int start_master(int fd){ + int result = listen(fd, 10); + if (result != 0) { + perror("listen"); + return 1; + } + //Demonize + pid_t pid = fork(); + if (pid < 0){ + perror("fork"); + return 1; + } + if(pid == 0){ + setsid(); // create a new session if we can... + result = master(fd); + exit(result); + }else{ + return 0; + } +} + +static int run_slave_cmd(struct sockaddr_un *addr, int fd, const std::vector &args){ + int result = -1; + struct timespec start, now; + clock_gettime(CLOCK_MONOTONIC, &start); + clock_gettime(CLOCK_MONOTONIC, &now); + srand48(start.tv_sec ^ start.tv_nsec); + while (diff_timespec(&now, &start) < 3.0) { + result = connect(fd, (sockaddr *)addr, sizeof(*addr)); + if (result == 0) + break; + + usleep((useconds_t)(lrand48() % 100000) + 100); //Random sleep min 100us max 100100us + clock_gettime(CLOCK_MONOTONIC, &now); + } + if (result < 0 && errno == ECONNREFUSED) { + fprintf(stderr, "Waited 3 seconds for master. giving up.\n"); + close(fd); + return 1; + } + if (result < 0) { + fprintf(stderr, "connect %s: %s", addr->sun_path, strerror(errno)); + return 1; + } + return slave(fd, args); +} + int main(int argc, char **argv) { if (getuid() == 0) { char *fallback_uid_str = getenv("RTAPI_UID"); @@ -1083,29 +1132,25 @@ int main(int argc, char **argv) { args.push_back(std::string(argv[i])); } -become_master: - int fd = socket(PF_UNIX, SOCK_STREAM, 0); - if (fd == -1) { - perror("socket"); - exit(1); - } - - int enable = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); struct sockaddr_un addr; memset(&addr, 0x0, sizeof(addr)); addr.sun_family = AF_UNIX; if (!get_fifo_path_to_addr(&addr)) exit(1); + int fd = create_socket(); + if (fd < 0) { + exit(1); + } + // plus one because we use the abstract namespace, it will show up in // /proc/net/unix prefixed with an @ int result = bind(fd, (sockaddr *)&addr, sizeof(addr)); if (result == 0) { - //If exit is called and master is not running, do not start master - //and exit again + //If exit is called and master is not running, just give a warning if (args.size() == 1 && args[0] == "exit") { + rtapi_print_msg(RTAPI_MSG_ERR, "rtapi_app: exit received while not running\n"); return 0; } //If check_rt is called and master is not running, do not start master @@ -1121,37 +1166,31 @@ int main(int argc, char **argv) { } return ret; } - int result = listen(fd, 10); - if (result != 0) { - perror("listen"); - exit(1); - } - setsid(); // create a new session if we can... - result = master(fd, args); - return result; - } else if (errno == EADDRINUSE) { - struct timespec start, now; - clock_gettime(CLOCK_MONOTONIC, &start); - clock_gettime(CLOCK_MONOTONIC, &now); - srand48(start.tv_sec ^ start.tv_nsec); - while (diff_timespec(&now, &start) < 3.0) { - result = connect(fd, (sockaddr *)&addr, sizeof(addr)); - if (result == 0) - break; - - usleep((useconds_t)(lrand48() % 100000) + 100); //Random sleep min 100us max 100100us - clock_gettime(CLOCK_MONOTONIC, &now); - } - if (result < 0 && errno == ECONNREFUSED) { - fprintf(stderr, "Waited 3 seconds for master. giving up.\n"); + //Start a master on start command + if (args.size() == 1 && args[0] == "start") { + result = start_master(fd); + exit(result); + }else{ + fprintf(stderr, "WARNING: Deprecated: No master found. Use \"realtime start\" to start one.\n" + " A master is started automatically.\n" + " If this appears while using halcmd: Use halrun instead.\n" + " halcmd should only be used with an already running realtime environment.\n" + " halrun creates a realtime environment and tears it down at exit.\n"); + result = start_master(fd); + if (result != 0) { + exit(result); + } + //Need to close and reopen the socket + //It is already bound and master is using it close(fd); - goto become_master; - } - if (result < 0) { - fprintf(stderr, "connect %s: %s", addr.sun_path, strerror(errno)); - exit(1); + int fd = create_socket(); + if (fd < 0) { + exit(1); + } + return run_slave_cmd(&addr, fd, args); } - return slave(fd, args); + } else if (errno == EADDRINUSE) { + return run_slave_cmd(&addr, fd, args); } else { perror("bind"); exit(1); From 44ab47273525043409531487250a46548d1ff9cc Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Tue, 30 Jun 2026 15:22:05 +0200 Subject: [PATCH 2/7] tests: Fixes for rtapi no autostop Due to rtapi_app is started before anything else, the hal-show expected owner id is increased by two. The raster test needs to be started with halrun to have realtime started and stopped properly. --- tests/hal-show/expected | 24 ++++++++++++------------ tests/raster/{test => rastertest.py} | 1 - tests/raster/test.hal | 1 + 3 files changed, 13 insertions(+), 13 deletions(-) rename tests/raster/{test => rastertest.py} (99%) create mode 100644 tests/raster/test.hal diff --git a/tests/hal-show/expected b/tests/hal-show/expected index e4bce169e35..7ecb4551e21 100644 --- a/tests/hal-show/expected +++ b/tests/hal-show/expected @@ -1,11 +1,11 @@ Component Pins: Owner Type Dir Value Name - 8 bit IN FALSE conv-bit-u32.0.in <== net-conv-bit-u32.0.in - 14 float IN 0 conv-float-s32.0.in <== net-conv-float-s32.0.in - 17 s32 IN 0 conv-s32-float.0.in <== net-conv-s32-float.0.in - 20 s64 IN 0 conv-s64-u64.0.in <== net-conv-s64-u64.0.in - 11 u32 IN 0x00000000 conv-u32-bit.0.in <== net-conv-u32-bit.0.in - 23 u64 IN 0x0000000000000000 conv-u64-s64.0.in <== net-conv-u64-s64.0.in + 10 bit IN FALSE conv-bit-u32.0.in <== net-conv-bit-u32.0.in + 16 float IN 0 conv-float-s32.0.in <== net-conv-float-s32.0.in + 19 s32 IN 0 conv-s32-float.0.in <== net-conv-s32-float.0.in + 22 s64 IN 0 conv-s64-u64.0.in <== net-conv-s64-u64.0.in + 13 u32 IN 0x00000000 conv-u32-bit.0.in <== net-conv-u32-bit.0.in + 25 u64 IN 0x0000000000000000 conv-u64-s64.0.in <== net-conv-u64-s64.0.in Signals: Type Value Name (linked to) @@ -36,12 +36,12 @@ s64 0 net-conv-u64-s64.0.out Component Pins: Owner Type Dir Value Name - 8 bit IN TRUE conv-bit-u32.0.in <== net-conv-bit-u32.0.in - 14 float IN 2.147484e+09 conv-float-s32.0.in <== net-conv-float-s32.0.in - 17 s32 IN -2147483648 conv-s32-float.0.in <== net-conv-s32-float.0.in - 20 s64 IN -9223372036854775808 conv-s64-u64.0.in <== net-conv-s64-u64.0.in - 11 u32 IN 0xFFFFFFFF conv-u32-bit.0.in <== net-conv-u32-bit.0.in - 23 u64 IN 0xFFFFFFFFFFFFFFFF conv-u64-s64.0.in <== net-conv-u64-s64.0.in + 10 bit IN TRUE conv-bit-u32.0.in <== net-conv-bit-u32.0.in + 16 float IN 2.147484e+09 conv-float-s32.0.in <== net-conv-float-s32.0.in + 19 s32 IN -2147483648 conv-s32-float.0.in <== net-conv-s32-float.0.in + 22 s64 IN -9223372036854775808 conv-s64-u64.0.in <== net-conv-s64-u64.0.in + 13 u32 IN 0xFFFFFFFF conv-u32-bit.0.in <== net-conv-u32-bit.0.in + 25 u64 IN 0xFFFFFFFFFFFFFFFF conv-u64-s64.0.in <== net-conv-u64-s64.0.in Signals: Type Value Name (linked to) diff --git a/tests/raster/test b/tests/raster/rastertest.py similarity index 99% rename from tests/raster/test rename to tests/raster/rastertest.py index af44c73404c..7ff1c2af394 100755 --- a/tests/raster/test +++ b/tests/raster/rastertest.py @@ -252,7 +252,6 @@ def main(): finally: c.exit() prog.exit() - os.system('halrun -U') return 0 if __name__ == "__main__": diff --git a/tests/raster/test.hal b/tests/raster/test.hal new file mode 100644 index 00000000000..e006f87ed30 --- /dev/null +++ b/tests/raster/test.hal @@ -0,0 +1 @@ +loadusr -w ./rastertest.py From 755b00dcf42dc4d6bf25fd3f31a26dcf1f9566fb Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Wed, 1 Jul 2026 17:28:33 +0200 Subject: [PATCH 3/7] realtime.in: Format script --- scripts/realtime.in | 256 +++++++++++++++++++++++--------------------- 1 file changed, 134 insertions(+), 122 deletions(-) diff --git a/scripts/realtime.in b/scripts/realtime.in index f9daf72d38f..2ed95cf2236 100644 --- a/scripts/realtime.in +++ b/scripts/realtime.in @@ -26,15 +26,17 @@ CheckKernel() { # Shellcheck doesn't know about substitution # shellcheck disable=SC2194 case "@KERNEL_VERS@" in - "") ;; + "") + ;; *) - if [ "$(uname -r)" != "@KERNEL_VERS@" ]; then - cat 1>&2 << EOF + if [ "$(uname -r)" != "@KERNEL_VERS@" ]; then + cat 1>&2 << EOF RTAPI requires the real-time kernel @KERNEL_VERS@ to run. Before running this realtime application, reboot and choose this kernel at the boot menu. EOF - exit 1 - fi + exit 1 + fi + ;; esac } @@ -71,8 +73,8 @@ CheckConfig(){ fi fi if [ -z "$RTAPICONF" ] ; then - echo "Missing rtapi.conf. Check your installation." 1>&2 - exit 1 + echo "Missing rtapi.conf. Check your installation." 1>&2 + exit 1 fi INSMOD="@INSMOD@" RMMOD="@RMMOD@" @@ -94,7 +96,9 @@ CheckConfig(){ MODULES_LOAD= MODULES_UNLOAD= case $RTPREFIX in - uspace) SHM_DEV=/dev/zero;; + uspace) + SHM_DEV=/dev/zero + ;; esac for MOD in $MODULES ; do eval MOD=\${MODPATH_"$MOD"} @@ -108,81 +112,85 @@ CheckConfig(){ MODULES_UNLOAD="$MOD $MODULES_UNLOAD" done case $RTPREFIX in - (*rtai*) - MODULES_LOAD="$MODULES_LOAD $RTLIB_DIR/rtapi$MODULE_EXT $RTLIB_DIR/hal_lib$MODULE_EXT" - MODULES_UNLOAD="hal_lib rtapi $MODULES_UNLOAD" - SHM_DEV=/dev/rtai_shm - ;; - (*) - MODULES_UNLOAD= + *rtai*) + MODULES_LOAD="$MODULES_LOAD $RTLIB_DIR/rtapi$MODULE_EXT $RTLIB_DIR/hal_lib$MODULE_EXT" + MODULES_UNLOAD="hal_lib rtapi $MODULES_UNLOAD" + SHM_DEV=/dev/rtai_shm + ;; + *) + MODULES_UNLOAD= + ;; esac } CheckStatus(){ case $RTPREFIX in - uspace) - if [ -z "$($PS -o stat= -o comm= -C rtapi_app | $GREP -v '^Z')" ]; then - echo rtapi_app is not running - return 1 - else - echo rtapi_app is running - return 0 - fi ;; - *) - # check loaded/unloaded status of modules - unset NOTLOADED - for MOD in $MODULES_UNLOAD ; do - if "$LSMOD" | awk '{print $1}' | $GREP -x "$MOD" >/dev/null ; then - echo "$MOD is loaded" + uspace) + if [ -z "$($PS -o stat= -o comm= -C rtapi_app | $GREP -v '^Z')" ]; then + echo rtapi_app is not running + return 1 else - echo "$MOD is not loaded" - NOTLOADED=NOT + echo rtapi_app is running + return 0 fi - done - if [ -z "$NOTLOADED" ]; then - return 0 - else - return 1 - fi + ;; + *) + # check loaded/unloaded status of modules + unset NOTLOADED + for MOD in $MODULES_UNLOAD ; do + if "$LSMOD" | awk '{print $1}' | $GREP -x "$MOD" >/dev/null ; then + echo "$MOD is loaded" + else + echo "$MOD is not loaded" + NOTLOADED=NOT + fi + done + if [ -z "$NOTLOADED" ]; then + return 0 + else + return 1 + fi + ;; esac } CheckMem(){ # check for user space processes using shared memory if [ -e /dev/mbuff ] ; then - # device file exists, check for processes using it - if $FUSER -s /dev/mbuff 2>/dev/null; then - # at least one process is using it - echo "ERROR: Can't remove RTLinux modules, kill the following process(es) first" - $FUSER -v /dev/mbuff - exit 1 - fi + # device file exists, check for processes using it + if $FUSER -s /dev/mbuff 2>/dev/null; then + # at least one process is using it + echo "ERROR: Can't remove RTLinux modules, kill the following process(es) first" + $FUSER -v /dev/mbuff + exit 1 + fi elif [ -e /dev/rtai_shm ] ; then - # device file exists, check for processes using it - if $FUSER -s /dev/rtai_shm 2>/dev/null; then - # at least one process is using it - echo "ERROR: Can't remove RTAI modules, kill the following process(es) first" - $FUSER -v /dev/rtai_shm - exit 1 - fi + # device file exists, check for processes using it + if $FUSER -s /dev/rtai_shm 2>/dev/null; then + # at least one process is using it + echo "ERROR: Can't remove RTAI modules, kill the following process(es) first" + $FUSER -v /dev/rtai_shm + exit 1 + fi fi } Load(){ CheckKernel case $RTPREFIX in - uspace) - rtapi_app start - ;; - (*rtai*) - for MOD in $MODULES_LOAD ; do - if ! [ -d "/sys/module/$(basename "$MOD" .ko)" ]; then - $INSMOD "$MOD" || return $? - fi - done - if [ "$DEBUG" != "" ] && [ -w /proc/rtapi/debug ] ; then - echo "$DEBUG" > /proc/rtapi/debug - fi + uspace) + rtapi_app start + ;; + *rtai*) + for MOD in $MODULES_LOAD ; do + if ! [ -d "/sys/module/$(basename "$MOD" .ko)" ]; then + $INSMOD "$MOD" || return $? + fi + done + if [ "$DEBUG" != "" ] && [ -w /proc/rtapi/debug ] ; then + echo "$DEBUG" > /proc/rtapi/debug + fi + ;; esac } @@ -202,29 +210,32 @@ CheckLoaded(){ Unload(){ CheckKernel + case $RTPREFIX in - uspace) - rtapi_app exit + uspace) + rtapi_app exit - # wait 5 seconds for rtapi_app to die and be reaped by its parent - START=$SECONDS - local NPROCS - while [ 5 -gt $((SECONDS-START)) ]; do + # wait 5 seconds for rtapi_app to die and be reaped by its parent + START=$SECONDS + local NPROCS + while [ 5 -gt $((SECONDS-START)) ]; do + NPROCS=$(ps -C rtapi_app -o stat= -o comm= | $GREP -v '^Z' | wc -l) + if [ "$NPROCS" -eq 0 ]; then + break + fi + sleep 0.1 + done NPROCS=$(ps -C rtapi_app -o stat= -o comm= | $GREP -v '^Z' | wc -l) - if [ "$NPROCS" -eq 0 ]; then - break + if [ "$NPROCS" -gt 0 ]; then + echo "ERROR: rtapi_app failed to die" 1>&2 fi - sleep 0.1 - done - NPROCS=$(ps -C rtapi_app -o stat= -o comm= | $GREP -v '^Z' | wc -l) - if [ "$NPROCS" -gt 0 ]; then - echo "ERROR: rtapi_app failed to die" 1>&2 - fi - ipcrm -M 0x48414c32 2>/dev/null ;# HAL_KEY - ipcrm -M 0x90280A48 2>/dev/null ;# RTAPI_KEY - ipcrm -M 0x48484c34 2>/dev/null ;# UUID_KEY + ipcrm -M 0x48414c32 2>/dev/null ;# HAL_KEY + ipcrm -M 0x90280A48 2>/dev/null ;# RTAPI_KEY + ipcrm -M 0x48484c34 2>/dev/null ;# UUID_KEY + ;; esac + for module in $MODULES_UNLOAD ; do $RMMOD "$module" done @@ -233,12 +244,13 @@ Unload(){ Verify(){ HAS_REALTIME=false case $RTPREFIX in - uspace) - rtapi_app check_rt && HAS_REALTIME=true - ;; - (*rtai*) - echo "RTAI" - HAS_REALTIME=true + uspace) + rtapi_app check_rt && HAS_REALTIME=true + ;; + *rtai*) + echo "RTAI" + HAS_REALTIME=true + ;; esac if [ $HAS_REALTIME = true ]; then @@ -252,50 +264,50 @@ CheckUnloaded(){ # checks to see if all modules were unloaded STATUS= for module in $MODULES_UNLOAD ; do - # check to see if the module is installed - if "$LSMOD" | awk '{print $1}' | $GREP -x "$module" >/dev/null ; then - echo "ERROR: Could not unload '$module'" - STATUS=error - fi + # check to see if the module is installed + if "$LSMOD" | awk '{print $1}' | $GREP -x "$module" >/dev/null ; then + echo "ERROR: Could not unload '$module'" + STATUS=error + fi done if [ -n "$STATUS" ] ; then - exit 1 + exit 1 fi } CMD=$1 case "$CMD" in - start|load) - CheckConfig - Load || exit $? - CheckLoaded - ;; - restart|force-reload) - CheckConfig - CheckMem - Unload - CheckUnloaded - Load || exit $? - CheckLoaded - ;; - stop|unload) - CheckConfig - CheckMem - Unload || exit $? - ;; - status) - CheckConfig - CheckStatus || exit $? - ;; - verify) - CheckConfig - Verify || exit $? - ;; - *) - echo "Usage: $0 {start|load|stop|unload|restart|force-reload|status|verify}" >&2 - exit 1 - ;; + start|load) + CheckConfig + Load || exit $? + CheckLoaded + ;; + restart|force-reload) + CheckConfig + CheckMem + Unload + CheckUnloaded + Load || exit $? + CheckLoaded + ;; + stop|unload) + CheckConfig + CheckMem + Unload || exit $? + ;; + status) + CheckConfig + CheckStatus || exit $? + ;; + verify) + CheckConfig + Verify || exit $? + ;; + *) + echo "Usage: $0 {start|load|stop|unload|restart|force-reload|status|verify}" >&2 + exit 1 + ;; esac exit 0 From 76fccf9aea5f520b197d75b4e36528e66557aac8 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Wed, 1 Jul 2026 17:57:09 +0200 Subject: [PATCH 4/7] realtime.in: Fix shellcheck issue --- scripts/realtime.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/realtime.in b/scripts/realtime.in index 2ed95cf2236..75dd12231a0 100644 --- a/scripts/realtime.in +++ b/scripts/realtime.in @@ -101,7 +101,7 @@ CheckConfig(){ ;; esac for MOD in $MODULES ; do - eval MOD=\${MODPATH_"$MOD"} + eval MOD="\${MODPATH_${MOD}}" if [ -z "$MOD" ]; then continue; fi if [ -L "$MOD" ]; then MOD=${MOD%/*}/$(readlink "$MOD") From 790bfe4b26eb9498797459377fa49efe4ff5cf94 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Thu, 2 Jul 2026 15:16:38 +0200 Subject: [PATCH 5/7] latency-histogram: Enable realtime start for non RTAI It was only active for RTAI. Do realtime start in forground for RTAI so there is no need to wait an arbitrary time. Additionally, simplify realtime verify. --- scripts/latency-histogram | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/scripts/latency-histogram b/scripts/latency-histogram index b52d896a46f..07be2a3934e 100755 --- a/scripts/latency-histogram +++ b/scripts/latency-histogram @@ -36,10 +36,10 @@ proc set_defaults {} { set ::LH(start) [clock seconds] # don't include glxgears, error suffices program_check {halrun halcmd lsmod pgrep pkill hostname} + set ::LH(realtime) [exec linuxcnc_var REALTIME] + program_check $::LH(realtime) if {[string first rtai [string tolower $::tcl_platform(osVersion)]] >=0} { set ::LH(rtai) rtai - set ::LH(realtime) [exec linuxcnc_var REALTIME] - program_check $::LH(realtime) } set ::LH(use_x) 1 @@ -313,11 +313,7 @@ proc load_packages {} { exit 1 } - if [info exists ::LH(rtai)] { - exec $::LH(realtime) start & - progress "Delay for realtime startup" - after 1000 ;# wait to load Hal package - } + exec $::LH(realtime) start >@stdout 2>@stderr # augment ::auto_path for special case: # 1) RIP build (no install) @@ -343,12 +339,10 @@ proc rt_status_items {} { # realtime: type from 'realtime verify' stdout, yes/no from its exit status. set rt_text "no realtime" set rt_ok 0 - if {![catch {exec linuxcnc_var REALTIME} rt]} { - if {![catch {open [list | $rt verify 2> /dev/null] r} chan]} { - set out [string trim [read $chan]] - set rt_ok [expr {![catch {close $chan}]}] - if {$out ne ""} {set rt_text $out} - } + if {![catch {open [list | $::LH(realtime) verify 2> /dev/null] r} chan]} { + set out [string trim [read $chan]] + set rt_ok [expr {![catch {close $chan}]}] + if {$out ne ""} {set rt_text $out} } lappend items [list $rt_text [expr {$rt_ok ? "" : $red}]] From 57b02a475cd72326875d851f8f101be4a782de77 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Sat, 4 Jul 2026 13:36:08 +0200 Subject: [PATCH 6/7] rtapi_app: Wait until running before exit This way, there is no need to have any other checks in other tools. --- src/rtapi/uspace_rtapi_main.cc | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/rtapi/uspace_rtapi_main.cc b/src/rtapi/uspace_rtapi_main.cc index b9b35f0c57c..331824606bc 100644 --- a/src/rtapi/uspace_rtapi_main.cc +++ b/src/rtapi/uspace_rtapi_main.cc @@ -883,6 +883,9 @@ static int handle_command(const std::vector &args, std::string &out if (args.size() == 1 && args[0] == "start") { rtapi_print_msg(RTAPI_MSG_ERR, "rtapi_app: start received while running\n"); return 0; + } else if (args.size() == 1 && args[0] == "ping") { + //Just return success + return 0; } else if (args.size() == 1 && args[0] == "exit") { force_exit = 1; return 0; @@ -1088,7 +1091,7 @@ static int run_slave_cmd(struct sockaddr_un *addr, int fd, const std::vectorsun_path, strerror(errno)); + fprintf(stderr, "connect %s: %s\n", addr->sun_path, strerror(errno)); return 1; } return slave(fd, args); @@ -1153,6 +1156,10 @@ int main(int argc, char **argv) { rtapi_print_msg(RTAPI_MSG_ERR, "rtapi_app: exit received while not running\n"); return 0; } + //If ping is called and master is not running, return an error + if (args.size() == 1 && args[0] == "ping") { + return 1; + } //If check_rt is called and master is not running, do not start master //execute and return //This is needed for the verify command in the realtime script @@ -1169,7 +1176,19 @@ int main(int argc, char **argv) { //Start a master on start command if (args.size() == 1 && args[0] == "start") { result = start_master(fd); - exit(result); + if (result != 0) { + exit(result); + } + //Need to close and reopen the socket + //It is already bound and master is using it + close(fd); + int fd = create_socket(); + if (fd < 0) { + exit(1); + } + //Ping master to make shure it is running + //before returning + return run_slave_cmd(&addr, fd, {"ping"}); }else{ fprintf(stderr, "WARNING: Deprecated: No master found. Use \"realtime start\" to start one.\n" " A master is started automatically.\n" @@ -1187,6 +1206,8 @@ int main(int argc, char **argv) { if (fd < 0) { exit(1); } + //Run command + //This makes also shure it is running before returning return run_slave_cmd(&addr, fd, args); } } else if (errno == EADDRINUSE) { From dc8cd1de0625820ac4537359ccfdfae7ba414152 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Sat, 4 Jul 2026 14:24:29 +0200 Subject: [PATCH 7/7] realtime: Check if rtapi_app is running using ping --- scripts/realtime.in | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scripts/realtime.in b/scripts/realtime.in index 75dd12231a0..857ac903f55 100644 --- a/scripts/realtime.in +++ b/scripts/realtime.in @@ -126,12 +126,15 @@ CheckConfig(){ CheckStatus(){ case $RTPREFIX in uspace) - if [ -z "$($PS -o stat= -o comm= -C rtapi_app | $GREP -v '^Z')" ]; then - echo rtapi_app is not running - return 1 - else + if rtapi_app ping; then echo rtapi_app is running return 0 + elif [ -n "$($PS -o stat= -o comm= -C rtapi_app | $GREP -v '^Z')" ]; then + echo rtapi_app is running but not reachable + return 1 + else + echo rtapi_app is not running + return 1 fi ;; *)