Skip to content

Commit

Permalink
Split signal handler process in dedicated file
Browse files Browse the repository at this point in the history
  • Loading branch information
sjanel committed Aug 28, 2024
1 parent cb4092e commit 4e1d72e
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 22 deletions.
25 changes: 3 additions & 22 deletions src/engine/src/coincenter-commands-processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

#include <algorithm>
#include <array>
#include <csignal>
#include <span>
#include <thread>
#include <utility>
Expand All @@ -29,6 +28,7 @@
#include "queryresultprinter.hpp"
#include "queryresulttypes.hpp"
#include "replay-options.hpp"
#include "signal-handler.hpp"
#include "timedef.hpp"
#include "transferablecommandresult.hpp"

Expand All @@ -51,30 +51,11 @@ void FillConversionTransferableCommandResults(const MonetaryAmountPerExchange &m
}
}

volatile sig_atomic_t g_signalStatus = 0;

} // namespace

// According to the standard, 'SignalHandler' function should have C linkage:
// https://en.cppreference.com/w/cpp/utility/program/signal
// Thus it's not possible to use a lambda and pass some
// objects to it. This is why for this rare occasion we will rely on a static variable. This solution has been inspired
// by: https://wiki.sei.cmu.edu/confluence/display/cplusplus/MSC54-CPP.+A+signal+handler+must+be+a+plain+old+function
extern "C" void SignalHandler(int sigNum) {
log::warn("Signal {} received, will stop after current request", sigNum);
g_signalStatus = sigNum;

// Revert to standard signal handler (to allow for standard kill in case program does not react)
std::signal(sigNum, SIG_DFL);
}

CoincenterCommandsProcessor::CoincenterCommandsProcessor(Coincenter &coincenter)
: _coincenter(coincenter),
_queryResultPrinter(coincenter.coincenterInfo().apiOutputType(), coincenter.coincenterInfo().loggingInfo()) {
// Register the signal handler to gracefully shutdown the main loop for repeated requests.
std::signal(SIGINT, SignalHandler);
std::signal(SIGTERM, SignalHandler);
}
_queryResultPrinter(coincenter.coincenterInfo().apiOutputType(), coincenter.coincenterInfo().loggingInfo()) {}

int CoincenterCommandsProcessor::process(const CoincenterCommands &coincenterCommands) {
const auto commands = coincenterCommands.commands();
Expand All @@ -83,7 +64,7 @@ int CoincenterCommandsProcessor::process(const CoincenterCommands &coincenterCom

int nbCommandsProcessed{};
TimePoint lastCommandTime;
for (int repeatPos{}; repeatPos != nbRepeats && g_signalStatus == 0; ++repeatPos) {
for (int repeatPos{}; repeatPos != nbRepeats && !IsStopRequested(); ++repeatPos) {
const auto earliestTimeNextCommand = lastCommandTime + repeatTime;
const bool doLog = nbRepeats != 1 && (repeatPos < 100 || repeatPos % 100 == 0);

Expand Down
8 changes: 8 additions & 0 deletions src/tech/include/signal-handler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

namespace cct {

// Tells whether a stop signal has been requested through a signal (Ctrl+C for instance)
bool IsStopRequested();

} // namespace cct
42 changes: 42 additions & 0 deletions src/tech/src/signal-handler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "signal-handler.hpp"

#include <csignal>

#include "cct_log.hpp"

namespace {

extern "C" void SignalHandler(int sigNum);

sig_atomic_t InitializeSignalStatus() {
// Register the signal handler to gracefully shutdown the main loop for repeated requests.
std::signal(SIGINT, SignalHandler);
std::signal(SIGTERM, SignalHandler);
std::signal(SIGQUIT, SignalHandler);

return 0;
}

volatile sig_atomic_t g_signalStatus = InitializeSignalStatus();

} // namespace

// According to the standard, 'SignalHandler' function should have C linkage:
// https://en.cppreference.com/w/cpp/utility/program/signal
// Thus it's not possible to use a lambda and pass some
// objects to it. This is why for this rare occasion we will rely on a static variable. This solution has been inspired
// by: https://wiki.sei.cmu.edu/confluence/display/cplusplus/MSC54-CPP.+A+signal+handler+must+be+a+plain+old+function
extern "C" void SignalHandler(int sigNum) {
cct::log::warn("Signal {} received, will stop after current command", sigNum);

g_signalStatus = sigNum;

// Revert to standard signal handler (to allow for standard kill in case program does not react)
std::signal(sigNum, SIG_DFL);
}

namespace cct {

bool IsStopRequested() { return g_signalStatus != 0; }

} // namespace cct

0 comments on commit 4e1d72e

Please sign in to comment.