diff --git a/scripts/realtime.in b/scripts/realtime.in index 286d57e0aee..036fde1353f 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 3f9bda20ecb..24a89109e4d 100644 --- a/src/rtapi/uspace_rtapi_main.cc +++ b/src/rtapi/uspace_rtapi_main.cc @@ -772,7 +772,10 @@ static int handle_command(const std::vector &args) { 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") { @@ -790,7 +793,7 @@ static int handle_command(const std::vector &args) { } else if (args.size() == 1 && args[0] == "check_rt") { return do_check_rt_cmd(); } 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; } } @@ -849,12 +852,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; @@ -864,18 +867,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()) { - result = handle_command(args); - if (result != 0) - goto out; - if (force_exit || instance_count == 0) - goto out; - } //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); @@ -928,6 +922,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"); @@ -966,29 +1019,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 @@ -999,37 +1048,26 @@ int main(int argc, char **argv) { if (args.size() == 1 && args[0] == "check_rt") { return do_check_rt_cmd(); } - int result = listen(fd, 10); - if (result != 0) { - perror("listen"); - exit(1); + //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 automaticaly.\n"); + result = start_master(fd); + if (result != 0) { + exit(result); + } + close(fd); //Need to close the socket, it is already bound and master is using it + int fd = create_socket(); + if (fd < 0) { + exit(1); + } + return run_slave_cmd(&addr, fd, args); } - 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"); - close(fd); - goto become_master; - } - if (result < 0) { - fprintf(stderr, "connect %s: %s", addr.sun_path, strerror(errno)); - exit(1); - } - return slave(fd, args); + return run_slave_cmd(&addr, fd, args); } else { perror("bind"); exit(1); 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/test index af44c73404c..07eedac263b 100755 --- a/tests/raster/test +++ b/tests/raster/test @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import hal import time -import os +import subprocess from raster import * theta = 0.005 @@ -193,10 +193,19 @@ def main(): prog = RasterProgrammer("programmer") - #instantiate the raster component, - #add it to a thread and link all signals from - #the test component here - assert os.system('halcmd -f raster.hal') == 0, "raster.hal script failed" + #instantiate the raster component + #use interactive mode to be have the hal running + #while needed and exit with writing "exit" at the end + halrun = subprocess.Popen(["halrun", "-Is", "raster.hal"], stdin=subprocess.PIPE) + #Test the last connection added in raster.hal + #to determine if hal is up and running + deadline = time.time() + 5 + while time.time() < deadline: + if hal.pin_has_writer("test.fraction"): + break + time.sleep(0.01) + else: + raise RuntimeError("raster.hal did not come up within 5s") testInvalidOffset(prog, pin) testInvalidBPP(prog, pin) @@ -252,7 +261,21 @@ def main(): finally: c.exit() prog.exit() - os.system('halrun -U') + try: + try: + halrun.communicate(input=b"exit\n", timeout=5) + except subprocess.TimeoutExpired: + halrun.kill() + halrun.communicate() + exit_status = halrun.returncode + if exit_status == 0: + return 0 + else: + print("Halrun failed, exit status " + str(exit_status)) + return 1 + except Exception as e: + print("error: Test failed: {}".format(traceback.format_exc())) + return 1 return 0 if __name__ == "__main__":