1313
1414#include < optional>
1515#include < unistd.h>
16- #include < csignal>
17- #include < atomic>
18- #include < thread>
1916#include < iostream>
2017#include < ctime>
2118#include < string>
19+ #include < chrono>
20+ #include < vector>
2221
2322#ifdef __linux__
2423 #include < linux/prctl.h>
2524 #include < sys/prctl.h>
2625#endif
2726
28- #include " score/lcm/lifecycle_client.h"
27+ #include " src/lifecycle_client_lib/include/application.h"
28+ #include " src/lifecycle_client_lib/include/runapplication.h"
2929
3030// / @brief CLI configuration options for the not_supervised_application process
3131struct Config
@@ -53,18 +53,15 @@ std::optional<Config> parseOptions(int argc, char *const *argv) noexcept
5353 switch (static_cast <char >(c))
5454 {
5555 case ' r' :
56- // response time
5756 config.responseTimeInMs = std::stoi (optarg);
5857 break ;
5958
6059 case ' c' :
61- // crash time
6260 config.crashRequested = true ;
6361 config.crashTimeInMs = std::stoi (optarg);
6462 break ;
6563
6664 case ' s' :
67- // start-up failure
6865 config.failToStart = true ;
6966 break ;
7067
@@ -88,93 +85,128 @@ std::optional<Config> parseOptions(int argc, char *const *argv) noexcept
8885 return config;
8986}
9087
91- std::atomic<bool > exitRequested{false };
92-
93- void signalHandler (int )
88+ void set_process_name ()
9489{
95- exitRequested = true ;
96- }
97-
98- void set_process_name () {
9990 const char * identifier = getenv (" PROCESSIDENTIFIER" );
100- if (identifier != nullptr ) {
91+ if (identifier != nullptr )
92+ {
10193 #ifdef __QNXNTO__
102- if (pthread_setname_np (pthread_self (), identifier) != 0 ) {
103- std::cerr << " Failed to set QNX thread name" << std::endl;
104- }
94+ if (pthread_setname_np (pthread_self (), identifier) != 0 )
95+ {
96+ std::cerr << " Failed to set QNX thread name" << std::endl;
97+ }
10598 #elif defined(__linux__)
106- if (prctl (PR_SET_NAME , identifier) < 0 ) {
107- std::cerr << " Failed to set process name to " << identifier << std::endl;
108- }
99+ if (prctl (PR_SET_NAME , identifier) < 0 )
100+ {
101+ std::cerr << " Failed to set process name to " << identifier << std::endl;
102+ }
109103 #endif
110104 }
111105}
112106
113- int main ( int argc, char **argv)
107+ class LifecycleApp final : public score::mw::lifecycle::Application
114108{
115- set_process_name ();
109+ public:
110+ std::int32_t Initialize (const score::mw::lifecycle::ApplicationContext& appCtx) override
111+ {
112+ set_process_name ();
116113
117- signal (SIGINT , signalHandler);
118- signal (SIGTERM , signalHandler);
114+ // Build a classic argv for getopt() from ApplicationContext arguments
115+ const auto & args = appCtx.get_arguments ();
116+ m_argvStorage.clear ();
117+ m_argvStorage.reserve (args.size () + 2 );
119118
120- const auto config = parseOptions (argc, argv);
121- if (!config)
122- {
123- return EXIT_FAILURE ;
124- }
119+ // Ensure argv[0] exists (getopt expects it)
120+ if (args.empty ())
121+ {
122+ m_argvStorage.push_back (const_cast <char *>(" LifecycleApp" ));
123+ }
124+ else
125+ {
126+ for (const auto & s : args)
127+ {
128+ // NOTE: relies on the underlying storage staying alive during Initialize().
129+ m_argvStorage.push_back (const_cast <char *>(s.data ()));
130+ }
131+ }
125132
126- std::chrono::time_point<std::chrono::steady_clock> startTime = std::chrono::steady_clock::now ();
127- std::chrono::duration<double , std::milli> runTime;
133+ m_argvStorage.push_back (nullptr );
128134
129- if (true == config->failToStart )
130- {
131- return EXIT_FAILURE ;
132- }
135+ optind = 1 ;
133136
134- score::lcm::LifecycleClient{}.ReportExecutionState (score::lcm::ExecutionState::kRunning );
137+ const int argcLocal = static_cast <int >(m_argvStorage.size () - 1 );
138+ const auto config = parseOptions (argcLocal, m_argvStorage.data ());
139+ if (!config)
140+ {
141+ return EXIT_FAILURE ;
142+ }
135143
136- timespec req{
137- static_cast <time_t >(config->responseTimeInMs / 1000 ),
138- static_cast <long >((config->responseTimeInMs % 1000 ) * 1000000L )
139- };
140- auto timeLastVerboseLog = std::chrono::steady_clock::now ();
141- while (!exitRequested)
142- {
143- if (true == config->crashRequested )
144+ m_config = *config;
145+
146+ if (true == m_config.failToStart )
144147 {
145- runTime = std::chrono::steady_clock::now () - startTime;
148+ return EXIT_FAILURE ;
149+ }
146150
147- int timeTillCrash = static_cast <int >(config->crashTimeInMs - runTime.count ());
151+ return 0 ;
152+ }
148153
149- if (timeTillCrash < config->responseTimeInMs )
154+ std::int32_t Run (const score::cpp::stop_token& stopToken) override
155+ {
156+ std::chrono::time_point<std::chrono::steady_clock> startTime = std::chrono::steady_clock::now ();
157+ std::chrono::duration<double , std::milli> runTime;
158+
159+ timespec req{
160+ static_cast <time_t >(m_config.responseTimeInMs / 1000 ),
161+ static_cast <long >((m_config.responseTimeInMs % 1000 ) * 1000000L )
162+ };
163+
164+ auto timeLastVerboseLog = std::chrono::steady_clock::now ();
165+
166+ while (!stopToken.stop_requested ())
167+ {
168+ if (true == m_config.crashRequested )
150169 {
151- // OK we need a shorter sleep now
152- if (timeTillCrash > 0 )
170+ runTime = std::chrono::steady_clock::now () - startTime;
171+ int timeTillCrash = static_cast <int >(m_config.crashTimeInMs - runTime.count ());
172+
173+ if (timeTillCrash < m_config.responseTimeInMs )
153174 {
154- timespec crash_req{
155- static_cast <time_t >(timeTillCrash / 1000 ),
156- static_cast <long >((timeTillCrash % 1000 ) * 1000000L )
157- };
158- nanosleep (&crash_req, nullptr );
175+ if (timeTillCrash > 0 )
176+ {
177+ timespec crash_req{
178+ static_cast <time_t >(timeTillCrash / 1000 ),
179+ static_cast <long >((timeTillCrash % 1000 ) * 1000000L )
180+ };
181+ nanosleep (&crash_req, nullptr );
182+ }
183+
184+ std::abort ();
159185 }
160-
161- // let's crash...
162- std::abort ();
163186 }
164- }
165-
166187
167- if (config->verbose ) {
168- const auto now = std::chrono::steady_clock::now ();
169- if (now - timeLastVerboseLog >= std::chrono::seconds (1 )) {
170- std::cout << " LifecycleApp: " << " Running in verbose mode" << std::endl;
171- timeLastVerboseLog = now;
188+ if (m_config.verbose )
189+ {
190+ const auto now = std::chrono::steady_clock::now ();
191+ if (now - timeLastVerboseLog >= std::chrono::seconds (1 ))
192+ {
193+ std::cout << " LifecycleApp: Running in verbose mode" << std::endl;
194+ timeLastVerboseLog = now;
195+ }
172196 }
197+
198+ nanosleep (&req, nullptr );
173199 }
174200
175- nanosleep (&req, nullptr ) ;
201+ return EXIT_SUCCESS ;
176202 }
177203
178- // normal exit
179- return EXIT_SUCCESS ;
204+ private:
205+ Config m_config{};
206+ std::vector<char *> m_argvStorage{};
207+ };
208+
209+ int main (int argc, char ** argv)
210+ {
211+ return score::mw::lifecycle::run_application<LifecycleApp>(argc, argv);
180212}
0 commit comments