Skip to content

src/application/impl/app_state_manager_impl.cpp

Namespaces

Name
sgns
sgns::application

Source code

#include "application/impl/app_state_manager_impl.hpp"

#include <csignal>
#include <functional>

namespace sgns::application {

  std::weak_ptr<AppStateManager> AppStateManagerImpl::wp_to_myself;

  void AppStateManagerImpl::shuttingDownSignalsHandler(int) {
    if (auto self = wp_to_myself.lock()) {
      self->shutdown();
    }
  }

  AppStateManagerImpl::AppStateManagerImpl()
      : logger_(base::createLogger("Application")) {
        /*
    struct sigaction act {};
    memset(&act, 0, sizeof(act));
    act.sa_handler = shuttingDownSignalsHandler;  // NOLINT
    sigset_t set; // NOLINT
    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    sigaddset(&set, SIGTERM);
    sigaddset(&set, SIGQUIT);
    act.sa_mask = set;
    sigaction(SIGINT, &act, nullptr);
    sigaction(SIGTERM, &act, nullptr);
    sigaction(SIGQUIT, &act, nullptr);
    sigprocmask(SIG_UNBLOCK, &act.sa_mask, nullptr);
    */
  }

  AppStateManagerImpl::~AppStateManagerImpl() {
    /*
    struct sigaction act {};
    memset(&act, 0, sizeof(act));
    act.sa_handler = SIG_DFL;  // NOLINT
    sigset_t set; // NOLINT
    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    sigaddset(&set, SIGTERM);
    sigaddset(&set, SIGQUIT);
    act.sa_mask = set;
    sigaction(SIGINT, &act, nullptr);
    sigaction(SIGTERM, &act, nullptr);
    sigaction(SIGQUIT, &act, nullptr);
    */
  }

  void AppStateManagerImpl::reset() {
    std::lock_guard lg(mutex_);
    while ( !prepare_.empty() )
    {
        prepare_.pop();
    }
    while ( !launch_.empty() )
    {
        launch_.pop();
    }
    while ( !shutdown_.empty() )
    {
        shutdown_.pop();
    }
    state_ = State::Init;
    shutdown_requested_ = false;
  }

  void AppStateManagerImpl::atPrepare(OnPrepare &&cb) {
    std::lock_guard lg(mutex_);
    if (state_ > State::Init) {
      throw AppStateException("adding callback for stage 'prepare'");
    }
    prepare_.emplace(std::move(cb));
  }

  void AppStateManagerImpl::atLaunch(OnLaunch &&cb) {
    std::lock_guard lg(mutex_);
    if (state_ > State::ReadyToStart) {
      throw AppStateException("adding callback for stage 'launch'");
    }
    launch_.emplace(std::move(cb));
  }

  void AppStateManagerImpl::atShutdown(OnShutdown &&cb) {
    std::lock_guard lg(mutex_);
    if (state_ > State::Works) {
      throw AppStateException("adding callback for stage 'shutdown'");
    }
    shutdown_.emplace(std::move(cb));
  }

  void AppStateManagerImpl::doPrepare() {
    std::lock_guard lg(mutex_);
    if (state_ != State::Init) {
      throw AppStateException("running stage 'prepare'");
    }
    state_ = State::Prepare;

    while (!prepare_.empty()) {
      auto &cb = prepare_.front();
      if (state_ == State::Prepare) {
        auto success = cb();
        if (! success) {
          state_ = State::ShuttingDown;
        }
      }
      prepare_.pop();
    }

    if (state_ == State::Prepare) {
      state_ = State::ReadyToStart;
    } else {
      shutdown();
    }
  }

  void AppStateManagerImpl::doLaunch() {
    std::lock_guard lg(mutex_);
    if (state_ != State::ReadyToStart) {
      throw AppStateException("running stage 'launch'");
    }
    state_ = State::Starting;

    while (!launch_.empty()) {
      auto &cb = launch_.front();
      if (state_ == State::Starting) {
        auto success = cb();
        if (! success) {
          state_ = State::ShuttingDown;
        }
      }
      launch_.pop();
    }

    if (state_ == State::Starting) {
      state_ = State::Works;
    } else {
      shutdown();
    }
  }

  void AppStateManagerImpl::doShutdown() {
    std::lock_guard lg(mutex_);
    if (state_ == State::ReadyToStop) {
      return;
    }

    while ( !prepare_.empty() )
    {
        prepare_.pop();
    }

    while ( !launch_.empty() )
    {
        launch_.pop();
    }

    state_ = State::ShuttingDown;

    while (!shutdown_.empty()) {
      auto &cb = shutdown_.front();
      cb();
      shutdown_.pop();
    }

    state_ = State::ReadyToStop;
  }

  void AppStateManagerImpl::run() {
    wp_to_myself = weak_from_this();
    if (wp_to_myself.expired()) {
      throw std::logic_error(
          "AppStateManager must be instantiated on shared pointer before run");
    }

    doPrepare();

    if (state_ == State::ReadyToStart) {
      doLaunch();
    }

    std::unique_lock lock(cv_mutex_);
    cv_.wait(lock, [&] { return shutdown_requested_.load(); });

    doShutdown();
  }

  void AppStateManagerImpl::shutdown() {
    shutdown_requested_ = true;
    std::lock_guard lg(cv_mutex_);
    cv_.notify_one();
  }
}  // namespace sgns::application

Updated on 2026-03-04 at 13:10:44 -0800