diff --git a/score/launch_manager/src/daemon/src/control/BUILD b/score/launch_manager/src/daemon/src/control/BUILD index 090ccec7d..2d1bc3e9d 100644 --- a/score/launch_manager/src/daemon/src/control/BUILD +++ b/score/launch_manager/src/daemon/src/control/BUILD @@ -27,6 +27,7 @@ cc_library( "//score/launch_manager/src/daemon/src/common:constants", "//score/launch_manager/src/daemon/src/common:log", "//score/launch_manager/src/daemon/src/common:process_group_state_id", + "//score/launch_manager/src/daemon/src/common:signal_safe_log", "//score/launch_manager/src/daemon/src/osal:ipc_comms", "@score_baselibs//score/language/futurecpp", ], diff --git a/score/launch_manager/src/daemon/src/control/control_client_channel.cpp b/score/launch_manager/src/daemon/src/control/control_client_channel.cpp index 6f6fba6fc..a305a1185 100644 --- a/score/launch_manager/src/daemon/src/control/control_client_channel.cpp +++ b/score/launch_manager/src/daemon/src/control/control_client_channel.cpp @@ -20,15 +20,32 @@ #include "control_client_channel.hpp" #include "score/mw/launch_manager/common/constants.hpp" #include "score/mw/launch_manager/common/log.hpp" +#include "score/mw/launch_manager/common/signal_safe_log.hpp" -namespace score +namespace score::lcm::internal { -namespace lcm +bool ControlClientChannel::loadControlNudge() { + if (nudgeControlClientHandler_ != nullptr) + { + LM_LOG_ERROR() << "Semaphore was already mapped!"; + return false; + } -namespace internal -{ + void* nudgeBuf = mmap( + NULL, sizeof(osal::Semaphore), PROT_WRITE, MAP_SHARED, osal::IpcCommsSync::control_client_handler_nudge_fd, 0); + + if (nudgeBuf == MAP_FAILED) + { + LM_LOG_ERROR() << "mmap of nudge semaphore failed in initializeControlClientChannel:" + << std::string_view{std::strerror(errno)}; + return false; + } + + nudgeControlClientHandler_ = static_cast(nudgeBuf); + return true; +} void ControlClientChannel::initialize() { @@ -81,6 +98,8 @@ bool ControlClientChannel::getResponse(ControlClientMessage& msg) LM_LOG_DEBUG() << "Response retrieved."; } + nudgeControlClientHandler(); + return result; } @@ -89,25 +108,7 @@ void ControlClientChannel::sendRequest(ControlClientMessage& msg) request_.msg_ = msg; request_.empty_ = false; - // now map the semaphore and post on it - // Attempt to map the semaphore - auto* nudgeLM = mmap( - NULL, sizeof(osal::Semaphore), PROT_WRITE, MAP_SHARED, osal::IpcCommsSync::control_client_handler_nudge_fd, 0); - - // RULECHECKER_comment(1, 1, check_c_style_cast, "This is the definition provided by the OS and does a C-style - // cast.", true) - if (nudgeLM != MAP_FAILED) - { - LM_LOG_DEBUG() << "Request sent. Waiting for acknowledgment..."; - auto* semaphore = static_cast(nudgeLM); - - // coverity[cert_mem52_cpp_violation:FALSE] The allocated memory is checked by the containing if statement. - const auto result = semaphore->post(); - SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE( - result == osal::OsalReturnType::kSuccess, "ControlClientChannel semaphore post failed"); - - munmap(nudgeLM, sizeof(osal::Semaphore)); // Unmap the semaphore - } + nudgeControlClientHandler(); const auto result = nudge_LM_Handler_.wait(); SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE( @@ -197,6 +198,9 @@ ControlClientChannelP ControlClientChannel::initializeControlClientChannel(int f lock.unlock(); init_cv_.notify_all(); } + + loadControlNudge(); + return result; } @@ -240,21 +244,24 @@ ControlClientChannelP ControlClientChannel::getControlClientChannel(osal::IpcCom void ControlClientChannel::nudgeControlClientHandler() { - if (nudgeControlClientHandler_) + if (nudgeControlClientHandler_ != nullptr) { - const auto result = nudgeControlClientHandler_->post(); - SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE( - result == osal::OsalReturnType::kSuccess, "ControlClientChannel semaphore post failed"); - - LM_LOG_DEBUG() << "Control Client handler nudged"; + if (nudgeControlClientHandler_->post() != osal::OsalReturnType::kSuccess) + { + static_cast(signal_safe_log("ControlClientChannel semaphore post failed")); + exit(EXIT_FAILURE); + } } } void ControlClientChannel::nudgeLMHandler() { const auto result = nudge_LM_Handler_.post(); - SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE( - result == osal::OsalReturnType::kSuccess, "ControlClientChannel semaphore post failed"); + if (result != osal::OsalReturnType::kSuccess) + { + static_cast(signal_safe_log("ControlClientChannel semaphore post failed")); + exit(EXIT_FAILURE); + } } void ControlClientChannel::releaseParentMapping() @@ -280,8 +287,4 @@ bool ControlClientChannel::is_initialized_ = false; std::condition_variable ControlClientChannel::init_cv_{}; std::mutex ControlClientChannel::init_mutex_{}; -} // namespace internal - -} // namespace lcm - -} // namespace score +} // namespace score::lcm::internal diff --git a/score/launch_manager/src/daemon/src/control/control_client_channel.hpp b/score/launch_manager/src/daemon/src/control/control_client_channel.hpp index 86d6cd370..73d928389 100644 --- a/score/launch_manager/src/daemon/src/control/control_client_channel.hpp +++ b/score/launch_manager/src/daemon/src/control/control_client_channel.hpp @@ -171,6 +171,9 @@ class ControlClientChannel final /// @brief Desctructor, deleted. We cannot create or delete objects of this type in the normal ways. ~ControlClientChannel() = delete; + /// @brief loads the control channel's nudge semaphore. + static bool loadControlNudge(); + /// @brief Initialise the comms channels /// called when the shared memory is initially created by Launch Manager void initialize(); diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/process_group_manager.cpp b/score/launch_manager/src/daemon/src/process_group_manager/details/process_group_manager.cpp index eb75ade8c..dc0a529c1 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/process_group_manager.cpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/process_group_manager.cpp @@ -31,6 +31,7 @@ static std::atomic_bool em_cancelled{false}; static void my_signal_handler(int) { em_cancelled.store(true); + ControlClientChannel::nudgeControlClientHandler(); } void ProcessGroupManager::cancel() @@ -164,60 +165,56 @@ void ProcessGroupManager::deinitialize() inline bool ProcessGroupManager::initializeControlClientHandler() { - bool result = false; - // Create shared memory for the nudge semaphore, using the specific // file descriptor osal::Comms::control_client_handler_nudge_fd, and a random name. // The name is removed from the file system after creation, memory // is mapped and a pointer stored, the FD is kept open. ControlClientChannel::nudgeControlClientHandler_ = nullptr; - char shm_name[static_cast(score::lcm::internal::ProcessLimits::maxLocalBuffSize)]; + constexpr static std::string_view shm_name{"/_nudge~._.~me_"}; - static_cast(snprintf( - shm_name, - static_cast(score::lcm::internal::ProcessLimits::maxLocalBuffSize), - "/_nudge~._.~me_")); // random name - int fd = shm_open(shm_name, O_CREAT | O_EXCL | O_RDWR, 0U); + int fd = shm_open(shm_name.begin(), O_CREAT | O_EXCL | O_RDWR, 0U); + if (fd <= 0) + { + return false; + } + shm_unlink(shm_name.begin()); - if (fd >= 0) + if (0 != ftruncate(fd, static_cast(sizeof(osal::Semaphore)))) { - shm_unlink(shm_name); + ::close(fd); + return false; + } - if (0 == ftruncate(fd, static_cast(sizeof(osal::Semaphore)))) - { - int fd2 = - dup2(fd, osal::IpcCommsSync::control_client_handler_nudge_fd); // always make sure we are using fd=4 - close(fd); + int fd2 = dup2(fd, osal::IpcCommsSync::control_client_handler_nudge_fd); // always make sure we are using fd=4 + ::close(fd); - // dup2 clears the O_CLOEXEC flag so this needs to be set again - if (fcntl(fd2, F_SETFD, FD_CLOEXEC) != 0) - { - ::close(fd2); - return false; - } + // dup2 clears the O_CLOEXEC flag so this needs to be set again + if (fcntl(fd2, F_SETFD, FD_CLOEXEC) != 0) + { + ::close(fd2); + return false; + } - if (osal::IpcCommsSync::control_client_handler_nudge_fd == fd2) - { - void* buf = mmap(NULL, sizeof(osal::Semaphore), PROT_WRITE, MAP_SHARED, fd2, 0); + if (osal::IpcCommsSync::control_client_handler_nudge_fd != fd2) + { + ::close(fd2); + return false; + } - // RULECHECKER_comment(1, 1, check_c_style_cast, "This is the definition provided by the OS and does a - // C-style cast.", true) - if (MAP_FAILED != buf) - { - ControlClientChannel::nudgeControlClientHandler_ = static_cast(buf); - // coverity[cert_mem52_cpp_violation:FALSE] The allocated memory is checked by the containing if - // statement. - const auto osal_result = ControlClientChannel::nudgeControlClientHandler_->init(0U, true); - SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE( - osal_result == OsalReturnType::kSuccess, "ControlClientChannel semaphore init failed"); - - result = true; - } - } - } + void* buf = mmap(NULL, sizeof(osal::Semaphore), PROT_WRITE, MAP_SHARED, fd2, 0); + + if (MAP_FAILED == buf) + { + ::close(fd2); + return false; } - return result; + ControlClientChannel::nudgeControlClientHandler_ = static_cast(buf); + const auto osal_result = ControlClientChannel::nudgeControlClientHandler_->init(0U, true); + SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE( + osal_result == OsalReturnType::kSuccess, "ControlClientChannel semaphore init failed"); + + return true; } inline bool ProcessGroupManager::initializeProcessGroups() @@ -512,27 +509,23 @@ bool ProcessGroupManager::sendResponse(ControlClientMessage msg) { auto pin = getProcessInfoNode( msg.originating_control_client_.process_group_index_, msg.originating_control_client_.process_index_); - bool ret = true; - if (pin) + if (pin == nullptr) { - auto scc = pin->getControlClientChannel(); + return false; + } + auto scc = pin->getControlClientChannel(); - if (scc) - { - LM_LOG_DEBUG() << "ProcessGroupManager::ControlClientHandler: Sending" - << scc->toString(msg.request_or_response_) << "(" - << static_cast(msg.request_or_response_) << ") re state" - << msg.process_group_state_.pg_state_name_ << "of PG" << msg.process_group_state_.pg_name_; - ret = scc->sendResponse(msg); - if (!ret) - { - ControlClientChannel::nudgeControlClientHandler(); - } - } + if (scc == nullptr) + { + return false; } - return ret; + LM_LOG_DEBUG() << "ProcessGroupManager::ControlClientHandler: Sending" << scc->toString(msg.request_or_response_) + << "(" << static_cast(msg.request_or_response_) << ") re state" + << msg.process_group_state_.pg_state_name_ << "of PG" << msg.process_group_state_.pg_name_; + + return scc->sendResponse(msg); } inline void ProcessGroupManager::controlClientRequests(Graph& pg)