Skip to content

Commit

Permalink
iox-eclipse-iceoryx#2330 Refactor systemd handling into a dedicated c…
Browse files Browse the repository at this point in the history
…lass

Extracted systemd-related functionality into a new Systemd_service_handler class. This refactor improves modularity and simplifies the main RouDi code by encapsulating systemd-specific logic, making it easier to maintain and extend in the future.
  • Loading branch information
khromenokroman committed Aug 23, 2024
1 parent 952e91f commit 7abf543
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 80 deletions.
135 changes: 130 additions & 5 deletions iceoryx_posh/include/iceoryx_posh/internal/roudi/roudi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,136 @@ namespace roudi
{
using namespace iox::units::duration_literals;

namespace systemd
{
class I_systemd
{
public:
virtual ~I_systemd() = default;
I_systemd(I_systemd const& other) = delete;
I_systemd(I_systemd&& other) = default;
I_systemd& operator=(I_systemd const& other) = delete;
I_systemd& operator=(I_systemd&& other) = default;

virtual void process_notify() = 0;

protected:
I_systemd() = default;
};

#ifdef USE_SYSTEMD
class Systemd_service_handler final : public I_systemd
{
public:
Systemd_service_handler() = default;
Systemd_service_handler(Systemd_service_handler const& other) = delete;
Systemd_service_handler(Systemd_service_handler&& other) = default;
Systemd_service_handler& operator=(Systemd_service_handler const& other) = delete;
Systemd_service_handler& operator=(Systemd_service_handler&& other) = default;
static constexpr uint16_t SIZE_STRING = 4096;

~Systemd_service_handler() final
{
/*
* This is necessary to prevent the main thread from exiting before
* the 'listen_thread_watchdog' has finished, hence ensuring a
* proper termination of the entire application.
*/
if (m_listen_thread_watchdog.joinable())
{
m_listen_thread_watchdog.join();
}
}
void process_notify() final
{
/*
* We get information about how they are running. If as a unit, then we launch
* watchdog and send a notification about the launch, otherwise we do nothing
*/
iox::string<SIZE_STRING> invocation_id_str;
auto const* const ENV_VAR = "INVOCATION_ID";
invocation_id_str.unsafe_raw_access([&](auto* buffer, auto const info) {
size_t actual_size_with_null{0};
auto result = IOX_POSIX_CALL(iox_getenv_s)(&actual_size_with_null, buffer, info.total_size, ENV_VAR)
.failureReturnValue(-1)
.evaluate();

if (result.has_error() && result.error().errnum == ERANGE)
{
IOX_LOG(ERROR, "Invalid value for 'INVOCATION_ID' environment variable!");
}

size_t actual_size{0};
constexpr size_t NULL_TERMINATOR_SIZE{1};
if (actual_size_with_null > 0)
{
actual_size = actual_size_with_null - NULL_TERMINATOR_SIZE;
}
buffer[actual_size] = 0;
return actual_size;
});

if (!invocation_id_str.empty())
{
IOX_LOG(WARN, "Run APP in unit(systemd)");
m_listen_thread_watchdog = std::thread([this] {
bool status_change_name = iox::setThreadName("watchdog");
if (!status_change_name)
{
IOX_LOG(ERROR, "Can not set name for thread watchdog");
return;
}
auto result_ready = IOX_POSIX_CALL(sd_notify)(0, "READY=1").successReturnValue(1).evaluate();
if (result_ready.has_error())
{
IOX_LOG(ERROR,
"Failed to send READY=1 signal. Error: "
+ result_ready.get_error().getHumanReadableErrnum());
return;
}
IOX_LOG(DEBUG, "WatchDog READY=1");

IOX_LOG(INFO, "Start watchdog");
while (true)
{
auto result_watchdog = IOX_POSIX_CALL(sd_notify)(0, "WATCHDOG=1").successReturnValue(1).evaluate();
if (result_watchdog.has_error())
{
IOX_LOG(ERROR,
"Failed to send WATCHDOG=1 signal. Error: "
+ result_watchdog.get_error().getHumanReadableErrnum());
return;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
});
}
}

private:
std::thread m_listen_thread_watchdog; // 8
};
#else
class Systemd_service_handler final : public I_systemd
{
public:
Systemd_service_handler() = default;
Systemd_service_handler(Systemd_service_handler const& other) = delete;
Systemd_service_handler(Systemd_service_handler&& other) = default;
Systemd_service_handler& operator=(Systemd_service_handler const& other) = delete;
Systemd_service_handler& operator=(Systemd_service_handler&& other) = default;

~Systemd_service_handler() final
{
}
void process_notify() final
{
// empty implementation
}
}
#endif
} // namespace systemd

class RouDi
{
public:
Expand All @@ -54,8 +184,6 @@ class RouDi
PortManager& portManager,
const config::RouDiConfig& roudiConfig) noexcept;

static constexpr uint16_t SIZE_STRING = 4096;

virtual ~RouDi() noexcept;

/// @brief Triggers the discovery loop to run immediately instead of waiting for the next tick interval
Expand Down Expand Up @@ -134,9 +262,6 @@ class RouDi
private:
std::thread m_monitoringAndDiscoveryThread;
std::thread m_handleRuntimeMessageThread;
#ifdef USE_SYSTEMD
std::thread m_listen_thread_watchdog; // 8
#endif

protected:
ProcessIntrospectionType m_processIntrospection;
Expand Down
77 changes: 2 additions & 75 deletions iceoryx_posh/source/roudi/roudi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,18 +161,6 @@ void RouDi::shutdown() noexcept
// Postpone the IpcChannelThread in order to receive TERMINATION
m_runHandleRuntimeMessageThread = false;

#ifdef USE_SYSTEMD
/*
* This is necessary to prevent the main thread from exiting before
* the 'listen_thread_watchdog' has finished, hence ensuring a
* proper termination of the entire application.
*/
if (m_listen_thread_watchdog.joinable())
{
m_listen_thread_watchdog.join();
}
#endif

if (m_handleRuntimeMessageThread.joinable())
{
IOX_LOG(DEBUG, "Joining 'IPC-msg-process' thread...");
Expand Down Expand Up @@ -266,69 +254,8 @@ void RouDi::processRuntimeMessages(runtime::IpcInterfaceCreator&& roudiIpcInterf
IOX_LOG(INFO, "RouDi is ready for clients");
fflush(stdout); // explicitly flush 'stdout' for 'launch_testing'

#ifdef USE_SYSTEMD
/*
* We get information about how they are running. If as a unit, then we launch
* watchdog and send a notification about the launch, otherwise we do nothing
*/
iox::string<SIZE_STRING> invocation_id_str;
auto const* const ENV_VAR = "INVOCATION_ID";
invocation_id_str.unsafe_raw_access([&](auto* buffer, auto const info) {
size_t actual_size_with_null{0};
auto result = IOX_POSIX_CALL(iox_getenv_s)(&actual_size_with_null, buffer, info.total_size, ENV_VAR)
.failureReturnValue(-1)
.evaluate();

if (result.has_error() && result.error().errnum == ERANGE)
{
IOX_LOG(ERROR, "Invalid value for 'INVOCATION_ID' environment variable!");
}

size_t actual_size{0};
constexpr size_t NULL_TERMINATOR_SIZE{1};
if (actual_size_with_null > 0)
{
actual_size = actual_size_with_null - NULL_TERMINATOR_SIZE;
}
buffer[actual_size] = 0;
return actual_size;
});

if (!invocation_id_str.empty())
{
IOX_LOG(WARN, "Run APP in unit(systemd)");
m_listen_thread_watchdog = std::thread([this] {
bool status_change_name = iox::setThreadName("watchdog");
if (!status_change_name)
{
IOX_LOG(ERROR, "Can not set name for thread watchdog");
return;
}
auto result_ready = IOX_POSIX_CALL(sd_notify)(0, "READY=1").successReturnValue(1).evaluate();
if (result_ready.has_error())
{
IOX_LOG(ERROR,
"Failed to send READY=1 signal. Error: " + result_ready.get_error().getHumanReadableErrnum());
return;
}
IOX_LOG(DEBUG, "WatchDog READY=1");

IOX_LOG(INFO, "Start watchdog");
while (m_runHandleRuntimeMessageThread.load())
{
auto result_watchdog = IOX_POSIX_CALL(sd_notify)(0, "WATCHDOG=1").successReturnValue(1).evaluate();
if (result_watchdog.has_error())
{
IOX_LOG(ERROR,
"Failed to send WATCHDOG=1 signal. Error: "
+ result_watchdog.get_error().getHumanReadableErrnum());
return;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
});
}
#endif
iox::roudi::systemd::Systemd_service_handler roudi_systemd;
roudi_systemd.process_notify();

while (m_runHandleRuntimeMessageThread)
{
Expand Down

0 comments on commit 7abf543

Please sign in to comment.