Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/


#ifndef OSAL_IPC_COMMS_HPP_INCLUDED
#define OSAL_IPC_COMMS_HPP_INCLUDED

Expand All @@ -22,13 +21,17 @@

#include "semaphore.hpp"

namespace score {
namespace score
{

namespace lcm {
namespace lcm
{

namespace internal {
namespace internal
{

namespace osal {
namespace osal
{

struct IpcCommsSync;
using IpcCommsP = std::shared_ptr<IpcCommsSync>;
Expand All @@ -37,8 +40,10 @@ using IpcCommsP = std::shared_ptr<IpcCommsSync>;
/// The `IpcCommsSync` structure is designed to handle synchronization mechanisms required
/// for inter-process communication. It uses semaphores to manage synchronization,
/// a process ID to identify the communicating process, and a flag to manage file descriptor closure.
// RULECHECKER_comment(1, 1, check_incomplete_data_member_construction, "wi 45913 - This struct is POD, which doesn't have user-declared constructor. The rule doesn’t apply.", false)
struct IpcCommsSync final {
// RULECHECKER_comment(1, 1, check_incomplete_data_member_construction, "wi 45913 - This struct is POD, which doesn't
// have user-declared constructor. The rule doesn’t apply.", false)
struct IpcCommsSync final
{
/// @brief Semaphore for synchronizing replies.
/// The `reply_sync_` semaphore is used to synchronize the reception of replies
/// from a communicating process. It ensures that the reply is received before
Expand Down Expand Up @@ -68,6 +73,11 @@ struct IpcCommsSync final {
/// during communication. It is set to a value of 3 by default.
static const int sync_fd = 3;

/// @brief Constant for the file descriptor used to signal state transitions
/// The semaphore used to signal state transitions is stored in an unlinked shared memory area. This requires
/// the constant “control_client_handler_nudge_fd” so that the spawned processes can access this resource.
static const int control_client_handler_nudge_fd = 4;

// Cannot construct or destruct objects of this type

/// @brief Constructor (deleted)
Expand Down Expand Up @@ -95,25 +105,32 @@ struct IpcCommsSync final {
/// file descriptor. The Lifecycle Client library will use the default file descriptor
/// whereas Launch Manager supplies whatever file descriptor it is using for
/// the process it is creating.
static IpcCommsP getCommsObject(int fd = IpcCommsSync::sync_fd) {
static IpcCommsP getCommsObject(int fd = IpcCommsSync::sync_fd)
{
IpcCommsP ret = nullptr;
void* buf = mmap(nullptr, sizeof(IpcCommsSync), PROT_WRITE, MAP_SHARED, 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 (MAP_FAILED != buf) {
// 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)
{
ret = IpcCommsP(static_cast<IpcCommsSync*>(buf), IpcCommsDeletor());
}

return ret;
}

private:
private:
/// @brief Deleter to release IpcCommsSync object
/// This is passed to the constructor of a shared pointer
struct IpcCommsDeletor {
void operator()(IpcCommsSync* ptr) const {
if (nullptr != ptr) {
if (munmap(ptr, sizeof(IpcCommsSync)) == -1) {
struct IpcCommsDeletor
{
void operator()(IpcCommsSync* ptr) const
{
if (nullptr != ptr)
{
if (munmap(ptr, sizeof(IpcCommsSync)) == -1)
{
LM_LOG_ERROR() << "Unmapping of shared memory failed";
}
}
Expand All @@ -123,10 +140,10 @@ struct IpcCommsSync final {

} // namespace osal

} // namespace lcm

} // namespace internal

} // namespace lcm

} // namespace score

#endif // OSAL_IPC_COMMS_HPP_INCLUDED
146 changes: 92 additions & 54 deletions src/launch_manager_daemon/common/src/internal/controlclientchannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,44 +18,55 @@
#include <cstring>
#include <thread>

namespace score {
namespace score
{

namespace lcm {
namespace lcm
{

namespace internal {
namespace internal
{

void ControlClientChannel::initialize() {
void ControlClientChannel::initialize()
{
request_.empty_.store(true);
response_.empty_.store(true);
nudge_LM_Handler_.init(0U, true);
initial_result_count_ = 0U;
LM_LOG_DEBUG() << "ControlClientChannel initialized";
}

void ControlClientChannel::deinitialize() {
void ControlClientChannel::deinitialize()
{
nudge_LM_Handler_.deinit();
}

bool ControlClientChannel::sendResponse(ControlClientMessage& msg) {
bool ControlClientChannel::sendResponse(ControlClientMessage& msg)
{
bool result = false;

if (response_.empty_) {
if (response_.empty_)
{
response_.msg_ = msg;
response_.empty_ = false;
nudge_LM_Handler_.post();
result = true;
LM_LOG_DEBUG() << "Response sent.";
} else {
}
else
{
LM_LOG_DEBUG() << "Failed to send response: response is not empty.";
}

return result;
}

bool ControlClientChannel::getResponse(ControlClientMessage& msg) {
bool ControlClientChannel::getResponse(ControlClientMessage& msg)
{
bool result = !response_.empty_;

if (result) {
if (result)
{
msg = response_.msg_;
response_.empty_ = true;
LM_LOG_DEBUG() << "Response retrieved.";
Expand All @@ -64,16 +75,20 @@ bool ControlClientChannel::getResponse(ControlClientMessage& msg) {
return result;
}

void ControlClientChannel::sendRequest(ControlClientMessage& msg) {
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::sync_fd + 1, 0);
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) {
// 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<osal::Semaphore*>(nudgeLM);
// coverity[cert_mem52_cpp_violation:FALSE] The allocated memory is checked by the containing if statement.
Expand All @@ -85,71 +100,81 @@ void ControlClientChannel::sendRequest(ControlClientMessage& msg) {
nudge_LM_Handler_.wait();

// Wait for acknowledgment
while (!request_.empty_) {
while (!request_.empty_)
{
std::this_thread::sleep_for(kControlClientPollingDelay);
}

msg = request_.msg_;
LM_LOG_DEBUG() << "Request acknowledged.";
}

bool ControlClientChannel::getRequest() {
bool ControlClientChannel::getRequest()
{
return !request_.empty_;
}

ControlClientMessage& ControlClientChannel::request() {
ControlClientMessage& ControlClientChannel::request()
{
return request_.msg_;
}

void ControlClientChannel::acknowledgeRequest() {
void ControlClientChannel::acknowledgeRequest()
{
nudge_LM_Handler_.post();
request_.empty_ = true;
LM_LOG_DEBUG() << "Request acknowledged.";
}

ControlClientChannelP ControlClientChannel::initializeControlClientChannel(int fileDesc, osal::IpcCommsP* mem_ptr) {
ControlClientChannelP ControlClientChannel::initializeControlClientChannel(int fileDesc, osal::IpcCommsP* mem_ptr)
{
ControlClientChannelP result = nullptr;
void* channelMemory = mmap(nullptr,
sizeof(ControlClientChannel) + sizeof(osal::IpcCommsSync),
PROT_WRITE,
MAP_SHARED,
fileDesc,
0);

if (MAP_FAILED == channelMemory) {
void* channelMemory =
mmap(nullptr, sizeof(ControlClientChannel) + sizeof(osal::IpcCommsSync), PROT_WRITE, MAP_SHARED, fileDesc, 0);

if (MAP_FAILED == channelMemory)
{
LM_LOG_ERROR() << "mmap failed in initializeControlClientChannel:" << std::strerror(errno);
return nullptr;
}

auto* commsHeader = static_cast<osal::IpcCommsSync*>(channelMemory);

if (mem_ptr != nullptr) {
if (mem_ptr != nullptr)
{
*mem_ptr = osal::IpcCommsP(commsHeader, [](osal::IpcCommsSync* ptr) {
if (ptr != nullptr) {
if (munmap(ptr, sizeof(ControlClientChannel) + sizeof(osal::IpcCommsSync)) == -1) {
if (ptr != nullptr)
{
if (munmap(ptr, sizeof(ControlClientChannel) + sizeof(osal::IpcCommsSync)) == -1)
{
LM_LOG_ERROR() << "Unmapping of shared memory (creation path) failed";
}
}
});
commsHeader->comms_type_ = osal::CommsType::kControlClient;
} else {
if (commsHeader->comms_type_ != osal::CommsType::kControlClient) {
}
else
{
if (commsHeader->comms_type_ != osal::CommsType::kControlClient)
{
LM_LOG_ERROR() << "Invalid comms type (" << static_cast<int>(commsHeader->comms_type_)
<< ") in initializeControlClientChannel attach path.";
if (munmap(channelMemory, sizeof(ControlClientChannel) + sizeof(osal::IpcCommsSync)) == -1) {
if (munmap(channelMemory, sizeof(ControlClientChannel) + sizeof(osal::IpcCommsSync)) == -1)
{
LM_LOG_ERROR() << "Unmapping after invalid comms type failed";
}
return nullptr;
}
}

char* controlClientStartPtr = std::next(static_cast<char*>(channelMemory),
static_cast<std::ptrdiff_t>(sizeof(osal::IpcCommsSync)));
char* controlClientStartPtr =
std::next(static_cast<char*>(channelMemory), static_cast<std::ptrdiff_t>(sizeof(osal::IpcCommsSync)));
result = ControlClientChannelP(static_cast<ControlClientChannel*>(static_cast<void*>(controlClientStartPtr)),
[](ControlClientChannel*){});
[](ControlClientChannel*) {});
LM_LOG_DEBUG() << "ControlClientChannel mapped (creation path: " << std::boolalpha << (mem_ptr != nullptr) << ")";

if (result) {
if (result)
{
std::unique_lock<std::mutex> lock(init_mutex_);
is_initialized_ = true;
lock.unlock();
Expand All @@ -158,16 +183,21 @@ ControlClientChannelP ControlClientChannel::initializeControlClientChannel(int f
return result;
}

ControlClientChannelP ControlClientChannel::getControlClientChannel(osal::IpcCommsP sync) {
ControlClientChannelP ControlClientChannel::getControlClientChannel(osal::IpcCommsP sync)
{
ControlClientChannelP result = nullptr;
{
std::unique_lock<std::mutex> lock(init_mutex_);
if (!is_initialized_) {
init_cv_.wait(lock, [] { return is_initialized_; });
if (!is_initialized_)
{
init_cv_.wait(lock, [] {
return is_initialized_;
});
}
}

if (sync && osal::CommsType::kControlClient == sync->comms_type_) {
if (sync && osal::CommsType::kControlClient == sync->comms_type_)
{
auto* syncMemory = sync.get();

// Control Client is in shared memory adjacent to ipc comms sync object
Expand All @@ -176,37 +206,45 @@ ControlClientChannelP ControlClientChannel::getControlClientChannel(osal::IpcCom
void* controlClientChannelPos = static_cast<void*>(std::next(sharedMemoryPtr, ipcCommSyncStartPtr));

// coverity[cert_mem56_cpp_violation:INTENTIONAL] Pointer is only owned by one shared pointer.
result =
ControlClientChannelP(static_cast<ControlClientChannel*>(controlClientChannelPos), [](ControlClientChannel*){});
result = ControlClientChannelP(static_cast<ControlClientChannel*>(controlClientChannelPos),
[](ControlClientChannel*) {});

result->ipc_parent_ = sync;
LM_LOG_DEBUG() << "ControlClientChannel obtained from sync.";
} else {
}
else
{
LM_LOG_ERROR() << "Invalid comms type in getControlClientChannel.";
}

return result;
}


void ControlClientChannel::nudgeControlClientHandler() {
if (nudgeControlClientHandler_) {
void ControlClientChannel::nudgeControlClientHandler()
{
if (nudgeControlClientHandler_)
{
nudgeControlClientHandler_->post();
LM_LOG_DEBUG() << "Control Client handler nudged";
}
}

void ControlClientChannel::nudgeLMHandler() {
void ControlClientChannel::nudgeLMHandler()
{
nudge_LM_Handler_.post();
}

void ControlClientChannel::releaseParentMapping() {
void ControlClientChannel::releaseParentMapping()
{
ipc_parent_.reset();
}

const char* ControlClientChannel::toString(ControlClientCode code) {
for (const auto& mapping : stateArray) {
if (mapping.code == code) {
const char* ControlClientChannel::toString(ControlClientCode code)
{
for (const auto& mapping : stateArray)
{
if (mapping.code == code)
{
return mapping.description;
}
}
Expand All @@ -219,8 +257,8 @@ bool ControlClientChannel::is_initialized_ = false;
std::condition_variable ControlClientChannel::init_cv_{};
std::mutex ControlClientChannel::init_mutex_{};

} // namespace lcm

} // namespace internal

} // namespace lcm

} // namespace score
Loading
Loading