diff --git a/examples/cpp_lifecycle_app/BUILD b/examples/cpp_lifecycle_app/BUILD index 40f35d03..436b38cc 100644 --- a/examples/cpp_lifecycle_app/BUILD +++ b/examples/cpp_lifecycle_app/BUILD @@ -27,6 +27,6 @@ cc_binary( }), visibility = ["//visibility:public"], deps = [ - "//src/launch_manager_daemon/lifecycle_client_lib:lifecycle_client", + "//src/lifecycle_client_lib", ], ) diff --git a/examples/cpp_lifecycle_app/main.cpp b/examples/cpp_lifecycle_app/main.cpp index 408c1c44..56e78aae 100644 --- a/examples/cpp_lifecycle_app/main.cpp +++ b/examples/cpp_lifecycle_app/main.cpp @@ -15,17 +15,19 @@ #include #include #include -#include #include #include #include +#include +#include #ifdef __linux__ #include #include #endif -#include "score/lcm/lifecycle_client.h" +#include "src/lifecycle_client_lib/include/application.h" +#include "src/lifecycle_client_lib/include/runapplication.h" /// @brief CLI configuration options for the not_supervised_application process struct Config @@ -53,18 +55,15 @@ std::optional parseOptions(int argc, char *const *argv) noexcept switch (static_cast(c)) { case 'r': - // response time config.responseTimeInMs = std::stoi(optarg); break; case 'c': - // crash time config.crashRequested = true; config.crashTimeInMs = std::stoi(optarg); break; case 's': - // start-up failure config.failToStart = true; break; @@ -95,86 +94,131 @@ void signalHandler(int) exitRequested = true; } -void set_process_name() { +void set_process_name() +{ const char* identifier = getenv("PROCESSIDENTIFIER"); - if(identifier != nullptr) { + if (identifier != nullptr) + { #ifdef __QNXNTO__ - if (pthread_setname_np(pthread_self(), identifier) != 0) { - std::cerr << "Failed to set QNX thread name" << std::endl; - } + if (pthread_setname_np(pthread_self(), identifier) != 0) + { + std::cerr << "Failed to set QNX thread name" << std::endl; + } #elif defined(__linux__) - if (prctl(PR_SET_NAME, identifier) < 0) { - std::cerr << "Failed to set process name to " << identifier << std::endl; - } + if (prctl(PR_SET_NAME, identifier) < 0) + { + std::cerr << "Failed to set process name to " << identifier << std::endl; + } #endif } } -int main(int argc, char **argv) +class LifecycleApp final : public score::mw::lifecycle::Application { - set_process_name(); +public: + std::int32_t Initialize(const score::mw::lifecycle::ApplicationContext& appCtx) override + { + set_process_name(); - signal(SIGINT, signalHandler); - signal(SIGTERM, signalHandler); + signal(SIGINT, signalHandler); + signal(SIGTERM, signalHandler); - const auto config = parseOptions(argc, argv); - if (!config) - { - return EXIT_FAILURE; - } + // Build a classic argv for getopt() from ApplicationContext arguments + const auto& args = appCtx.get_arguments(); + m_argvStorage.clear(); + m_argvStorage.reserve(args.size() + 2); - std::chrono::time_point startTime = std::chrono::steady_clock::now(); - std::chrono::duration runTime; + // Ensure argv[0] exists (getopt expects it) + if (args.empty()) + { + m_argvStorage.push_back(const_cast("LifecycleApp")); + } + else + { + for (const auto& s : args) + { + // NOTE: relies on the underlying storage staying alive during Initialize(). + m_argvStorage.push_back(const_cast(s.data())); + } + } - if (true == config->failToStart) - { - return EXIT_FAILURE; - } + m_argvStorage.push_back(nullptr); - score::lcm::LifecycleClient{}.ReportExecutionState(score::lcm::ExecutionState::kRunning); + optind = 1; - timespec req{ - static_cast(config->responseTimeInMs / 1000), - static_cast((config->responseTimeInMs % 1000) * 1000000L) - }; - auto timeLastVerboseLog = std::chrono::steady_clock::now(); - while (!exitRequested) - { - if (true == config->crashRequested) + const int argcLocal = static_cast(m_argvStorage.size() - 1); + const auto config = parseOptions(argcLocal, m_argvStorage.data()); + if (!config) + { + return EXIT_FAILURE; + } + + m_config = *config; + + if (true == m_config.failToStart) { - runTime = std::chrono::steady_clock::now() - startTime; + return EXIT_FAILURE; + } - int timeTillCrash = static_cast(config->crashTimeInMs - runTime.count()); + return 0; + } - if (timeTillCrash < config->responseTimeInMs) + std::int32_t Run(const score::cpp::stop_token& stopToken) override + { + std::chrono::time_point startTime = std::chrono::steady_clock::now(); + std::chrono::duration runTime; + + timespec req{ + static_cast(m_config.responseTimeInMs / 1000), + static_cast((m_config.responseTimeInMs % 1000) * 1000000L) + }; + + auto timeLastVerboseLog = std::chrono::steady_clock::now(); + + while (!exitRequested && !stopToken.stop_requested()) + { + if (true == m_config.crashRequested) { - // OK we need a shorter sleep now - if (timeTillCrash > 0) + runTime = std::chrono::steady_clock::now() - startTime; + int timeTillCrash = static_cast(m_config.crashTimeInMs - runTime.count()); + + if (timeTillCrash < m_config.responseTimeInMs) { - timespec crash_req{ - static_cast(timeTillCrash / 1000), - static_cast((timeTillCrash % 1000) * 1000000L) - }; - nanosleep(&crash_req, nullptr); + if (timeTillCrash > 0) + { + timespec crash_req{ + static_cast(timeTillCrash / 1000), + static_cast((timeTillCrash % 1000) * 1000000L) + }; + nanosleep(&crash_req, nullptr); + } + + std::abort(); } - - // let's crash... - std::abort(); } - } - - if(config->verbose) { - const auto now = std::chrono::steady_clock::now(); - if(now - timeLastVerboseLog >= std::chrono::seconds(1)) { - std::cout << "LifecycleApp: " << "Running in verbose mode" << std::endl; - timeLastVerboseLog = now; + if (m_config.verbose) + { + const auto now = std::chrono::steady_clock::now(); + if (now - timeLastVerboseLog >= std::chrono::seconds(1)) + { + std::cout << "LifecycleApp: Running in verbose mode" << std::endl; + timeLastVerboseLog = now; + } } + + nanosleep(&req, nullptr); } - nanosleep(&req, nullptr); + return EXIT_SUCCESS; } - // normal exit - return EXIT_SUCCESS; +private: + Config m_config{}; + std::vector m_argvStorage{}; +}; + +int main(int argc, char** argv) +{ + return score::mw::lifecycle::run_application(argc, argv); } diff --git a/src/lifecycle_client_lib/BUILD b/src/lifecycle_client_lib/BUILD index 9e312a89..5dc05134 100644 --- a/src/lifecycle_client_lib/BUILD +++ b/src/lifecycle_client_lib/BUILD @@ -46,6 +46,7 @@ cc_library( }), visibility = ["//visibility:public"], deps = [ + "//src/launch_manager_daemon/lifecycle_client_lib:lifecycle_client", "@score_baselibs//score/language/futurecpp", "@score_baselibs//score/memory:string_literal", "@score_baselibs//score/mw/log", @@ -117,6 +118,7 @@ cc_library( tags = ["FUSA"], deps = [ ":application", + "//src/launch_manager_daemon/lifecycle_client_lib:lifecycle_client", "@score_baselibs//score/mw/log", "@score_baselibs//score/os:stdlib", "@score_baselibs//score/os/utils:signal", diff --git a/src/lifecycle_client_lib/include/lifecyclemanager.h b/src/lifecycle_client_lib/include/lifecyclemanager.h index 79ec414e..8215c619 100644 --- a/src/lifecycle_client_lib/include/lifecyclemanager.h +++ b/src/lifecycle_client_lib/include/lifecyclemanager.h @@ -83,7 +83,7 @@ class LifeCycleManager /** * \brief Hook function for reporting running state. */ - virtual void report_running() noexcept {}; + virtual void report_running() noexcept ; /** * \brief Hook function for reporting shutdown state. */ diff --git a/src/lifecycle_client_lib/include/runapplication.h b/src/lifecycle_client_lib/include/runapplication.h index 7b3b4711..1d8b78f2 100644 --- a/src/lifecycle_client_lib/include/runapplication.h +++ b/src/lifecycle_client_lib/include/runapplication.h @@ -68,7 +68,8 @@ template /* NOLINTNEXTLINE(modernize-avoid-c-arrays): array tolerated for command line arguments */ std::int32_t run_application(const std::int32_t argc, const score::StringLiteral argv[], Args&&... args) { - return 0; + score::mw::lifecycle::Run runner(argc, argv); + return runner.AsPosixProcess(std::forward(args)...); } } // namespace lifecycle diff --git a/src/lifecycle_client_lib/src/lifecyclemanager.cpp b/src/lifecycle_client_lib/src/lifecyclemanager.cpp index eb66e682..97e156ec 100644 --- a/src/lifecycle_client_lib/src/lifecyclemanager.cpp +++ b/src/lifecycle_client_lib/src/lifecyclemanager.cpp @@ -15,7 +15,7 @@ #include "score/os/errno.h" #include - +#include "score/lcm/lifecycle_client.h" #include "score/mw/log/logging.h" #include "score/os/stdlib_impl.h" @@ -163,3 +163,13 @@ void score::mw::lifecycle::LifeCycleManager::handle_signal() /* KW_SUPPRESS_END:MISRA.STDLIB.ABORT,MISRA.USE.EXPANSION */ } } + +void score::mw::lifecycle::LifeCycleManager::report_running() noexcept +{ + mw::log::LogInfo() << "Reporting kRunning to Launch Manager"; + const auto result = score::lcm::LifecycleClient{}.ReportExecutionState(score::lcm::ExecutionState::kRunning); + if (!result.has_value()) + { + mw::log::LogError() << "Failed to report kRunning to Launch Manager: " << result.error().Message(); + } +}