@@ -772,7 +772,10 @@ static int handle_command(const std::vector<std::string> &args) {
772772 if (args.size () == 0 ) {
773773 return 0 ;
774774 }
775- if (args.size () == 1 && args[0 ] == " exit" ) {
775+ if (args.size () == 1 && args[0 ] == " start" ) {
776+ rtapi_print_msg (RTAPI_MSG_ERR , " rtapi_app: start received while running\n " );
777+ return 0 ;
778+ } else if (args.size () == 1 && args[0 ] == " exit" ) {
776779 force_exit = 1 ;
777780 return 0 ;
778781 } else if (args.size () >= 2 && args[0 ] == " load" ) {
@@ -790,7 +793,7 @@ static int handle_command(const std::vector<std::string> &args) {
790793 } else if (args.size () == 1 && args[0 ] == " check_rt" ) {
791794 return do_check_rt_cmd ();
792795 } else {
793- rtapi_print_msg (RTAPI_MSG_ERR , " Unrecognized command starting with %s\n " , args[0 ].c_str ());
796+ rtapi_print_msg (RTAPI_MSG_ERR , " rtapi_app: unrecognized command starting with %s\n " , args[0 ].c_str ());
794797 return -1 ;
795798 }
796799}
@@ -849,12 +852,12 @@ static bool master_process_socket_command(int fd) {
849852 }
850853 close (fd1);
851854 }
852- return !force_exit && instance_count > 0 ;
855+ return !force_exit;
853856}
854857
855858static pthread_t main_thread{};
856859
857- static int master (int fd, const std::vector<std::string> &args ) {
860+ static int master (int fd) {
858861 is_master = true ;
859862 main_thread = pthread_self ();
860863 int result;
@@ -864,18 +867,9 @@ static int master(int fd, const std::vector<std::string> &args) {
864867 return -1 ;
865868 }
866869 do_load_cmd (" hal_lib" , std::vector<std::string>());
867- instance_count = 0 ;
868870 App (); // force rtapi_app to be created
869- if (args.size ()) {
870- result = handle_command (args);
871- if (result != 0 )
872- goto out;
873- if (force_exit || instance_count == 0 )
874- goto out;
875- }
876871 // Process commands as long as master should not exit
877872 while (master_process_socket_command (fd));
878- out:
879873 do_unload_cmd (" hal_lib" );
880874 pthread_cancel (queue_thread);
881875 pthread_join (queue_thread, nullptr );
@@ -928,6 +922,65 @@ static double diff_timespec(const struct timespec *time1, const struct timespec
928922static void raise_net_admin_ambient (void );
929923#endif
930924
925+ static int create_socket (){
926+ int fd = socket (PF_UNIX , SOCK_STREAM , 0 );
927+ if (fd == -1 ) {
928+ perror (" socket" );
929+ return fd;
930+ }
931+
932+ int enable = 1 ;
933+ setsockopt (fd, SOL_SOCKET , SO_REUSEADDR , &enable, sizeof (enable));
934+ return fd;
935+ }
936+
937+ static int start_master (int fd){
938+ int result = listen (fd, 10 );
939+ if (result != 0 ) {
940+ perror (" listen" );
941+ return 1 ;
942+ }
943+ // Demonize
944+ pid_t pid = fork ();
945+ if (pid < 0 ){
946+ perror (" fork" );
947+ return 1 ;
948+ }
949+ if (pid == 0 ){
950+ setsid (); // create a new session if we can...
951+ result = master (fd);
952+ exit (result);
953+ }else {
954+ return 0 ;
955+ }
956+ }
957+
958+ static int run_slave_cmd (struct sockaddr_un *addr, int fd, const std::vector<std::string> &args){
959+ int result = -1 ;
960+ struct timespec start, now;
961+ clock_gettime (CLOCK_MONOTONIC , &start);
962+ clock_gettime (CLOCK_MONOTONIC , &now);
963+ srand48 (start.tv_sec ^ start.tv_nsec );
964+ while (diff_timespec (&now, &start) < 3.0 ) {
965+ result = connect (fd, (sockaddr *)addr, sizeof (*addr));
966+ if (result == 0 )
967+ break ;
968+
969+ usleep ((useconds_t )(lrand48 () % 100000 ) + 100 ); // Random sleep min 100us max 100100us
970+ clock_gettime (CLOCK_MONOTONIC , &now);
971+ }
972+ if (result < 0 && errno == ECONNREFUSED ) {
973+ fprintf (stderr, " Waited 3 seconds for master. giving up.\n " );
974+ close (fd);
975+ return 1 ;
976+ }
977+ if (result < 0 ) {
978+ fprintf (stderr, " connect %s: %s" , addr->sun_path , strerror (errno));
979+ return 1 ;
980+ }
981+ return slave (fd, args);
982+ }
983+
931984int main (int argc, char **argv) {
932985 if (getuid () == 0 ) {
933986 char *fallback_uid_str = getenv (" RTAPI_UID" );
@@ -966,29 +1019,25 @@ int main(int argc, char **argv) {
9661019 args.push_back (std::string (argv[i]));
9671020 }
9681021
969- become_master:
970- int fd = socket (PF_UNIX , SOCK_STREAM , 0 );
971- if (fd == -1 ) {
972- perror (" socket" );
973- exit (1 );
974- }
975-
976- int enable = 1 ;
977- setsockopt (fd, SOL_SOCKET , SO_REUSEADDR , &enable, sizeof (enable));
9781022 struct sockaddr_un addr;
9791023 memset (&addr, 0x0 , sizeof (addr));
9801024 addr.sun_family = AF_UNIX ;
9811025 if (!get_fifo_path_to_addr (&addr))
9821026 exit (1 );
9831027
1028+ int fd = create_socket ();
1029+ if (fd < 0 ) {
1030+ exit (1 );
1031+ }
1032+
9841033 // plus one because we use the abstract namespace, it will show up in
9851034 // /proc/net/unix prefixed with an @
9861035 int result = bind (fd, (sockaddr *)&addr, sizeof (addr));
9871036
9881037 if (result == 0 ) {
989- // If exit is called and master is not running, do not start master
990- // and exit again
1038+ // If exit is called and master is not running, just give a warning
9911039 if (args.size () == 1 && args[0 ] == " exit" ) {
1040+ rtapi_print_msg (RTAPI_MSG_ERR , " rtapi_app: exit received while not running\n " );
9921041 return 0 ;
9931042 }
9941043 // If check_rt is called and master is not running, do not start master
@@ -999,37 +1048,31 @@ int main(int argc, char **argv) {
9991048 if (args.size () == 1 && args[0 ] == " check_rt" ) {
10001049 return do_check_rt_cmd ();
10011050 }
1002- int result = listen (fd, 10 );
1003- if (result != 0 ) {
1004- perror (" listen" );
1005- exit (1 );
1006- }
1007- setsid (); // create a new session if we can...
1008- result = master (fd, args);
1009- return result;
1010- } else if (errno == EADDRINUSE ) {
1011- struct timespec start, now;
1012- clock_gettime (CLOCK_MONOTONIC , &start);
1013- clock_gettime (CLOCK_MONOTONIC , &now);
1014- srand48 (start.tv_sec ^ start.tv_nsec );
1015- while (diff_timespec (&now, &start) < 3.0 ) {
1016- result = connect (fd, (sockaddr *)&addr, sizeof (addr));
1017- if (result == 0 )
1018- break ;
1019-
1020- usleep ((useconds_t )(lrand48 () % 100000 ) + 100 ); // Random sleep min 100us max 100100us
1021- clock_gettime (CLOCK_MONOTONIC , &now);
1022- }
1023- if (result < 0 && errno == ECONNREFUSED ) {
1024- fprintf (stderr, " Waited 3 seconds for master. giving up.\n " );
1051+ // Start a master on start command
1052+ if (args.size () == 1 && args[0 ] == " start" ) {
1053+ result = start_master (fd);
1054+ exit (result);
1055+ }else {
1056+ fprintf (stderr, " WARNING: Deprecated: No master found. Use \" realtime start\" to start one.\n "
1057+ " A master is started automatically.\n "
1058+ " If this appears while using halcmd: Use halrun instead.\n "
1059+ " halcmd should only be used with an already running realtime environment.\n "
1060+ " halrun creates a realtime environment and tears it down at exit.\n " );
1061+ result = start_master (fd);
1062+ if (result != 0 ) {
1063+ exit (result);
1064+ }
1065+ // Need to close and reopen the socket
1066+ // It is already bound and master is using it
10251067 close (fd);
1026- goto become_master ;
1027- }
1028- if (result < 0 ) {
1029- fprintf (stderr, " connect %s: %s " , addr. sun_path , strerror (errno));
1030- exit ( 1 );
1068+ int fd = create_socket () ;
1069+ if (fd < 0 ) {
1070+ exit ( 1 );
1071+ }
1072+ return run_slave_cmd (&addr, fd, args );
10311073 }
1032- return slave (fd, args);
1074+ } else if (errno == EADDRINUSE ) {
1075+ return run_slave_cmd (&addr, fd, args);
10331076 } else {
10341077 perror (" bind" );
10351078 exit (1 );
0 commit comments