diff --git a/Tools/sitl_multiple_run.sh b/Tools/sitl_multiple_run.sh index a15ab1d3ec..826931f3f1 100755 --- a/Tools/sitl_multiple_run.sh +++ b/Tools/sitl_multiple_run.sh @@ -43,7 +43,7 @@ while [ $n -le $sitl_num ]; do pushd "$working_dir" &>/dev/null echo "starting instance $n in $(pwd)" - sudo -b -u $user ../bin/px4 -d "$src_path" rcS >out.log 2>err.log + sudo -b -u $user ../bin/px4 -i $n -d "$src_path" -s rcS >out.log 2>err.log popd &>/dev/null n=$(($n + 1)) diff --git a/cmake/posix/px4-alias.sh_in b/cmake/posix/px4-alias.sh_in index e0c361feb3..bd79461192 100644 --- a/cmake/posix/px4-alias.sh_in +++ b/cmake/posix/px4-alias.sh_in @@ -18,4 +18,9 @@ set() { # Don't stop on errors. #set -e +# Arguments passed to this script: +# $1: optional instance id +px4_instance=0 +[[ -n "$1" ]] && px4_instance=$1 + ${alias_string} diff --git a/launch/single_vehicle_spawn.launch b/launch/single_vehicle_spawn.launch index 9c2c3fe7b0..c2f8bc5e39 100644 --- a/launch/single_vehicle_spawn.launch +++ b/launch/single_vehicle_spawn.launch @@ -23,7 +23,7 @@ - + diff --git a/platforms/posix/cmake/px4_impl_os.cmake b/platforms/posix/cmake/px4_impl_os.cmake index 217d1662a5..3c6faa944d 100644 --- a/platforms/posix/cmake/px4_impl_os.cmake +++ b/platforms/posix/cmake/px4_impl_os.cmake @@ -123,7 +123,7 @@ function(px4_posix_generate_alias) endforeach() if (MAIN) set(alias_string - "${alias_string}alias ${MAIN}='${PREFIX}${MAIN}'\n" + "${alias_string}alias ${MAIN}='${PREFIX}${MAIN} --instance $px4_instance'\n" ) endif() endforeach() diff --git a/platforms/posix/src/main.cpp b/platforms/posix/src/main.cpp index e2c391ed54..f305009c90 100644 --- a/platforms/posix/src/main.cpp +++ b/platforms/posix/src/main.cpp @@ -99,10 +99,11 @@ static void register_sig_handler(); static void set_cpu_scaling(); static int create_symlinks_if_needed(std::string &data_path); static int create_dirs(); -static int run_startup_bash_script(const std::string &commands_file, const std::string &absolute_binary_path); +static int run_startup_bash_script(const std::string &commands_file, const std::string &absolute_binary_path, + int instance); static std::string get_absolute_binary_path(const std::string &argv0); static void wait_to_exit(); -static bool is_already_running(); +static bool is_already_running(int instance); static void print_usage(); static bool dir_exists(const std::string &path); static bool file_exists(const std::string &name); @@ -141,9 +142,23 @@ int main(int argc, char **argv) absolute_binary_path = get_absolute_binary_path(full_binary_name); } - if (is_client) { - if (!is_already_running()) { + if (is_client) { + int instance = 0; + + if (argc >= 3 && strcmp(argv[1], "--instance") == 0) { + instance = strtoul(argv[2], nullptr, 10); + /* update argv so that "--instance " is not visible anymore */ + argc -= 2; + + for (int i = 1; i < argc; ++i) { + argv[i] = argv[i + 2]; + } + } + + PX4_DEBUG("instance: %i", instance); + + if (!is_already_running(instance)) { PX4_ERR("PX4 daemon not running yet"); return -1; } @@ -151,28 +166,24 @@ int main(int argc, char **argv) /* Remove the path and prefix. */ argv[0] += path_length + strlen(prefix); - px4_daemon::Client client; + px4_daemon::Client client(instance); client.generate_uuid(); client.register_sig_handler(); return client.process_args(argc, (const char **)argv); } else { - if (is_already_running()) { - PX4_ERR("PX4 daemon already running"); - return -1; - } - /* Server/daemon apps need to parse the command line arguments. */ std::string data_path = ""; std::string commands_file = "etc/init.d/rcS"; std::string test_data_path = ""; + int instance = 0; int myoptind = 1; int ch; const char *myoptarg = nullptr; - while ((ch = px4_getopt(argc, argv, "hdt:s:", &myoptind, &myoptarg)) != EOF) { + while ((ch = px4_getopt(argc, argv, "hdt:s:i:", &myoptind, &myoptarg)) != EOF) { switch (ch) { case 'h': print_usage(); @@ -190,6 +201,10 @@ int main(int argc, char **argv) commands_file = myoptarg; break; + case 'i': + instance = strtoul(myoptarg, nullptr, 10); + break; + default: PX4_ERR("unrecognized flag"); print_usage(); @@ -197,10 +212,19 @@ int main(int argc, char **argv) } } + PX4_DEBUG("instance: %i", instance); + if (myoptind < argc) { data_path = argv[myoptind]; } + if (is_already_running(instance)) { + // allow running multiple instances, but the server is only started for the first + PX4_INFO("PX4 daemon already running for instance %i", instance); + return -1; + } + + int ret = create_symlinks_if_needed(data_path); if (ret != PX4_OK) { @@ -223,7 +247,7 @@ int main(int argc, char **argv) register_sig_handler(); set_cpu_scaling(); - px4_daemon::Server server; + px4_daemon::Server server(instance); server.start(); ret = create_dirs(); @@ -237,7 +261,7 @@ int main(int argc, char **argv) px4::init_once(); px4::init(argc, argv, "px4"); - ret = run_startup_bash_script(commands_file, absolute_binary_path); + ret = run_startup_bash_script(commands_file, absolute_binary_path, instance); // We now block here until we need to exit. if (pxh_off) { @@ -432,11 +456,12 @@ std::string get_absolute_binary_path(const std::string &argv0) return pwd() + "/" + base; } -int run_startup_bash_script(const std::string &commands_file, const std::string &absolute_binary_path) +int run_startup_bash_script(const std::string &commands_file, const std::string &absolute_binary_path, + int instance) { std::string bash_command("bash "); - bash_command += commands_file; + bash_command += commands_file + ' ' + std::to_string(instance); // Update the PATH variable to include the absolute_binary_path // (required for the px4-alias.sh script and px4-* commands). @@ -506,24 +531,26 @@ void print_usage() { printf("Usage for Server/daemon process: \n"); printf("\n"); - printf(" px4 [-h|-d] [-s ] [-d ] []\n"); + printf(" px4 [-h|-d] [-s ] [-t ] [] [-i ]\n"); printf("\n"); - printf(" bash start script to be used as startup (default=etc/init.d/rcS)\n"); + printf(" -s bash start script to be used as startup (default=etc/init.d/rcS)\n"); printf(" directory where startup files and mixers are located,\n"); printf(" (if not given, CWD is used)\n"); - printf(" -h help/usage information\n"); - printf(" -d daemon mode, don't start pxh shell\n"); + printf(" -i px4 instance id to run multiple instances [0...N], default=0\n"); + printf(" -h help/usage information\n"); + printf(" -d daemon mode, don't start pxh shell\n"); printf("\n"); printf("Usage for client: \n"); printf("\n"); - printf(" px4-MODULE command using symlink.\n"); + printf(" px4-MODULE [--instance ] command using symlink.\n"); printf(" e.g.: px4-commander status\n"); } -bool is_already_running() +bool is_already_running(int instance) { + const std::string file_lock_path = std::string(LOCK_FILE_PATH) + '-' + std::to_string(instance); struct flock fl; - int fd = open(LOCK_FILE_PATH, O_RDWR | O_CREAT, 0666); + int fd = open(file_lock_path.c_str(), O_RDWR | O_CREAT, 0666); if (fd < 0) { return false; diff --git a/platforms/posix/src/px4_daemon/client.cpp b/platforms/posix/src/px4_daemon/client.cpp index bd064fe34e..bbb3def133 100644 --- a/platforms/posix/src/px4_daemon/client.cpp +++ b/platforms/posix/src/px4_daemon/client.cpp @@ -59,9 +59,10 @@ namespace client static Client *_instance; } -Client::Client() : +Client::Client(int instance_id) : _uuid(0), - _client_send_pipe_fd(-1) + _client_send_pipe_fd(-1), + _instance_id(instance_id) { client::_instance = this; } @@ -166,7 +167,7 @@ Client::_send_cmds(const int argc, const char **argv) // The size is +1 because we want to include the null termination. packet.header.payload_length = cmd_buf.size() + 1; - _client_send_pipe_fd = open(CLIENT_SEND_PIPE_PATH, O_WRONLY); + _client_send_pipe_fd = open(get_client_send_pipe_path(_instance_id).c_str(), O_WRONLY); if (_client_send_pipe_fd < 0) { PX4_ERR("pipe open fail"); diff --git a/platforms/posix/src/px4_daemon/client.h b/platforms/posix/src/px4_daemon/client.h index b0a606cfcb..2e454c4cc2 100644 --- a/platforms/posix/src/px4_daemon/client.h +++ b/platforms/posix/src/px4_daemon/client.h @@ -56,7 +56,7 @@ namespace px4_daemon class Client { public: - Client(); + Client(int instance_id = 0); ~Client(); /** @@ -97,6 +97,7 @@ private: uint64_t _uuid; int _client_send_pipe_fd; char _recv_pipe_path[RECV_PIPE_PATH_LEN]; + int _instance_id; ///< instance ID for running multiple instances of the px4 server }; } // namespace px4_daemon diff --git a/platforms/posix/src/px4_daemon/pipe_protocol.cpp b/platforms/posix/src/px4_daemon/pipe_protocol.cpp index 0cdf49c94b..bbdc0e92a2 100644 --- a/platforms/posix/src/px4_daemon/pipe_protocol.cpp +++ b/platforms/posix/src/px4_daemon/pipe_protocol.cpp @@ -43,6 +43,10 @@ #include "pipe_protocol.h" +static const char CLIENT_SEND_PIPE_PATH[] = "/tmp/px4_client_send_pipe-"; +static const char CLIENT_RECV_PIPE_PATH[] = "/tmp/px4_client_recv_pipe"; + + namespace px4_daemon { @@ -59,9 +63,13 @@ unsigned get_client_recv_packet_length(const client_recv_packet_s *packet) int get_client_recv_pipe_path(const uint64_t uuid, char *path, const size_t path_len) { - return snprintf(path, path_len, "%s_%016" PRIx64, CLIENT_RECV_PIPE_PATH, uuid); + return snprintf(path, path_len, "%s-%016" PRIx64, CLIENT_RECV_PIPE_PATH, uuid); } +std::string get_client_send_pipe_path(int instance_id) +{ + return std::string(CLIENT_SEND_PIPE_PATH) + std::to_string(instance_id); +} } // namespace px4_daemon diff --git a/platforms/posix/src/px4_daemon/pipe_protocol.h b/platforms/posix/src/px4_daemon/pipe_protocol.h index b0bcd0ba37..abc2b9b87a 100644 --- a/platforms/posix/src/px4_daemon/pipe_protocol.h +++ b/platforms/posix/src/px4_daemon/pipe_protocol.h @@ -39,14 +39,11 @@ #pragma once #include +#include namespace px4_daemon { - -static const char CLIENT_SEND_PIPE_PATH[] = "/tmp/px4_client_send_pipe"; -static const char CLIENT_RECV_PIPE_PATH[] = "/tmp/px4_client_recv_pipe"; - static const unsigned RECV_PIPE_PATH_LEN = 64; struct client_send_packet_s { @@ -93,6 +90,7 @@ struct client_recv_packet_s { unsigned get_client_send_packet_length(const client_send_packet_s *packet); unsigned get_client_recv_packet_length(const client_recv_packet_s *packet); int get_client_recv_pipe_path(const uint64_t uuid, char *path, const size_t path_len); +std::string get_client_send_pipe_path(int instance_id); } // namespace px4_daemon diff --git a/platforms/posix/src/px4_daemon/server.cpp b/platforms/posix/src/px4_daemon/server.cpp index cb6e2f1908..f8c544940e 100644 --- a/platforms/posix/src/px4_daemon/server.cpp +++ b/platforms/posix/src/px4_daemon/server.cpp @@ -57,7 +57,8 @@ namespace px4_daemon Server *Server::_instance = nullptr; -Server::Server() +Server::Server(int instance_id) + : _instance_id(instance_id) { _instance = this; } @@ -109,12 +110,14 @@ Server::_server_main(void *arg) return; } + std::string client_send_pipe_path = get_client_send_pipe_path(_instance_id); + // Delete pipe in case it exists already. - unlink(CLIENT_SEND_PIPE_PATH); + unlink(client_send_pipe_path.c_str()); // Create new pipe to listen to clients. - mkfifo(CLIENT_SEND_PIPE_PATH, 0666); - int client_send_pipe_fd = open(CLIENT_SEND_PIPE_PATH, O_RDONLY); + mkfifo(client_send_pipe_path.c_str(), 0666); + int client_send_pipe_fd = open(client_send_pipe_path.c_str(), O_RDONLY); while (true) { @@ -129,7 +132,7 @@ Server::_server_main(void *arg) // 0 means the pipe has been closed by all clients // and we need to re-open it. close(client_send_pipe_fd); - client_send_pipe_fd = open(CLIENT_SEND_PIPE_PATH, O_RDONLY); + client_send_pipe_fd = open(client_send_pipe_path.c_str(), O_RDONLY); } } diff --git a/platforms/posix/src/px4_daemon/server.h b/platforms/posix/src/px4_daemon/server.h index 44bcf0918a..7ef8edd89f 100644 --- a/platforms/posix/src/px4_daemon/server.h +++ b/platforms/posix/src/px4_daemon/server.h @@ -64,7 +64,7 @@ namespace px4_daemon class Server { public: - Server(); + Server(int instance_id = 0); ~Server(); /** @@ -118,6 +118,8 @@ private: pthread_key_t _key; + int _instance_id; ///< instance ID for running multiple instances of the px4 server + static void _pthread_key_destructor(void *arg); static Server *_instance;