2#ifndef _CONSOLIX_CONSOLE_APPLICATION_HPP_INCLUDED
3#define _CONSOLIX_CONSOLE_APPLICATION_HPP_INCLUDED
13#if !defined(_WIN32) && !defined(_WIN64)
40 template <
typename Component,
typename... Args>
41 std::shared_ptr<Component>
add(Args&&... args) {
42 return m_manager.add<Component>(std::forward<Args>(args)...);
47 void add(std::shared_ptr<IAppComponent> component) {
56 std::this_thread::sleep_for(std::chrono::milliseconds(1));
59 }
catch (
const std::exception& e) {
67 template <
typename InitAction>
68 void init(InitAction init_action) {
71 std::this_thread::sleep_for(std::chrono::milliseconds(1));
76 }
catch (
const std::exception& e) {
93 template <
typename IterationAction>
94 void run(IterationAction iteration_action) {
123# if defined(_WIN32) || defined(_WIN64)
124 SetConsoleCtrlHandler(console_handler, TRUE);
128 struct sigaction action = {};
130 sigemptyset(&action.sa_mask);
131 sigaddset(&action.sa_mask, SIGINT);
132 sigaddset(&action.sa_mask, SIGTERM);
135 sigaction(SIGINT, &action,
nullptr);
136 sigaction(SIGTERM, &action,
nullptr);
144 void cleanup(
int exit_code,
bool wait_for_press =
false) {
145 bool expected =
false;
146 if (!
m_cleanup.compare_exchange_strong(expected,
true))
return;
150# if !defined(_WIN32) && !defined(_WIN64)
154# if CONSOLIX_USE_LOGIT == 1
155 LOGIT_PRINT_INFO(
"Cleaning up application for exit code: ", exit_code);
158 }
catch (
const std::exception& e) {
163 }
catch (
const std::exception& e) {
175 if (wait_for_press) {
179 std::exit(exit_code);
185# if CONSOLIX_USE_LOGIT == 1
186 LOGIT_PRINT_FATAL(
"Unhandled exception: ", e.what());
194 template <
typename IterationAction>
202 }
catch (
const std::exception& e) {
214 }
catch (
const std::exception& e) {
224# if defined(_WIN32) || defined(_WIN64)
229 static BOOL WINAPI console_handler(DWORD win_event) {
232 log_event(
"CTRL_C_EVENT");
234 case CTRL_CLOSE_EVENT:
235 log_event(
"CTRL_CLOSE_EVENT");
237 case CTRL_LOGOFF_EVENT:
238 log_event(
"CTRL_LOGOFF_EVENT");
240 case CTRL_SHUTDOWN_EVENT:
241 log_event(
"CTRL_SHUTDOWN_EVENT");
244 log_event(
"UNKNOWN_EVENT");
253 static void log_event(
const char* event_name) {
254# if CONSOLIX_USE_LOGIT == 1
255 LOGIT_PRINT_INFO(
"Console event received: ", event_name);
262 static int event_to_exit_code(DWORD win_event) {
277 sigaddset(&
m_mask, SIGINT);
278 sigaddset(&
m_mask, SIGTERM);
287 sigprocmask(SIG_SETMASK, &
m_old_mask,
nullptr);
321 if (pending_exit_code != 0) {
322 return pending_exit_code;
324 return fallback_exit_code;
336 static volatile std::sig_atomic_t value = 0;
342 static volatile std::sig_atomic_t value = 0;
348# if defined(_WIN32) || defined(_WIN64)
354 return fallback_exit_code;
#define CONSOLIX_STREAM()
Fallback for general logging.
Manages a collection of application components with lifecycle support.
~PosixTerminationSignalMaskGuard()
PosixTerminationSignalMaskGuard()
std::shared_ptr< Component > add(Args &&... args)
Adds a new component to the application.
AppComponentManager m_manager
void add(std::shared_ptr< IAppComponent > component)
Adds an existing component to the application.
std::atomic< bool > m_stopping
std::atomic< bool > m_cleanup
ConsoleApplication(const ConsoleApplication &)=delete
void setup_signal_handlers()
Sets up signal handlers for graceful application termination.
ConsoleApplication & operator=(ConsoleApplication &&)=delete
std::atomic< bool > m_running
Flag indicating whether the loop is running.
static volatile std::sig_atomic_t & signal_stop_requested()
Storage for the POSIX stop-request flag.
bool stop_requested()
Checks whether a POSIX signal requested shutdown and synchronizes the runtime state.
ConsoleApplication()=default
void lifecycle_loop()
The main lifecycle loop.
void run()
Runs the application with the registered components.
void run(IterationAction iteration_action)
Runs the application with a custom loop action.
static ConsoleApplication & get_instance()
Retrieves the singleton instance of the application.
std::atomic< bool > m_init
static void signal_handler(int exit_code)
Handles a POSIX signal by recording a deferred shutdown request.
void cleanup_if_stopping()
Executes cleanup immediately if a stop request is already pending.
void lifecycle_loop(IterationAction iteration_action)
The main lifecycle loop with a custom action.
void cleanup(int exit_code, bool wait_for_press=false)
Cleans up the application and shuts down all components.
ConsoleApplication & operator=(const ConsoleApplication &)=delete
~ConsoleApplication()=default
void init(InitAction init_action)
Initializes the application with a custom action.
static void reset_signal_state()
Resets POSIX signal state before installing handlers.
ConsoleApplication(ConsoleApplication &&)=delete
static void on_exit_handler()
Called upon normal program termination.
void init()
Initializes the application and its components. This method initializes all components in the manager...
void stop()
Stops the application's main loop.
static volatile std::sig_atomic_t & pending_signal_code()
Storage for the last requested POSIX shutdown signal.
int resolve_stop_exit_code(int fallback_exit_code) const
Resolves the exit code for the active stop request.
void handle_fatal_exception(const std::exception &e)
Handles fatal exceptions by logging the error and terminating the application.
void shutdown(int signal)
static ServiceLocator & get_instance()
Retrieves the singleton instance of the ServiceLocator.
void clear_all()
Clears all registered resources.
#define CONSOLIX_WAIT_ON_ERROR
Enables or disables waiting for user input before exiting on a fatal error.
< Utility modules and helpers.