Skip to content

Instantly share code, notes, and snippets.

@palacaze
Last active November 2, 2023 21:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save palacaze/40ced0819b07906609641f6df9451097 to your computer and use it in GitHub Desktop.
Save palacaze/40ced0819b07906609641f6df9451097 to your computer and use it in GitHub Desktop.
C++ Interrupt handler using ASIO
#pragma once
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>
#include <asio.hpp>
#include <asio/signal_set.hpp>
namespace system {
/**
* A Signal interrupt handler object.
*
* One should not install signal handlers using signal(). At least one thread should
* leave the signals to be blocked unblocked.
*
* Beware of thread safety, the handler will get called from inside a worker thread.
*
*/
class InterruptHandler {
public:
/**
* Create an interrupt handler that will invoke a function when a signal is fired
*
* @tparam Handler the type of a callable that gets executed when a signal is fired.
* Handler = bool(*)(int sig);
* @param sig the signal that was fired
* @return true if we must stop interrupt handling
*
* @param handler the handler to execute
* @param sigs the signals to block
*/
template <typename Handler, typename... Ints>
explicit InterruptHandler(Handler handler, Ints ...sigs)
: m_ioc{}
, m_sigs(m_ioc)
, m_fun{std::move(handler)}
{
(static_cast<void>(m_sigs.add(sigs)), ...);
m_sigs.async_wait([this] (auto e, auto n) { handlerWrapper(e, n); });
m_thread = std::thread([this] {
m_ioc.run();
m_cv.notify_all();
});
}
~InterruptHandler()
{
cancel();
}
/// Cancel interrupt handling, this stops the backround thread
void cancel()
{
m_ioc.stop();
m_thread.join();
}
[[nodiscard]] bool isRunning() const
{
return !m_ioc.stopped();
}
/// Wait for interrupt handling to stop
void wait()
{
std::unique_lock<std::mutex> lck(m_mutex);
m_cv.wait(lck);
}
private:
void handlerWrapper(const std::error_code &error, int n)
{
if (error || m_fun(n)) {
return;
}
m_sigs.async_wait([this] (auto e, auto n) { handlerWrapper(e, n); });
}
private:
asio::io_context m_ioc;
asio::signal_set m_sigs;
std::function<bool(int)> m_fun;
std::thread m_thread;
std::condition_variable m_cv;
std::mutex m_mutex;
};
} // namespace system
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment