diff options
Diffstat (limited to 'src/signals.cc')
| -rw-r--r-- | src/signals.cc | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/src/signals.cc b/src/signals.cc new file mode 100644 index 0000000..9f8bff7 --- /dev/null +++ b/src/signals.cc @@ -0,0 +1,89 @@ +#include "signals.hh" + +#include "looper.hh" +#include "unique_pipe.hh" + +#include <cerrno> +#include <csignal> +#include <cstdint> +#include <functional> +#include <memory> +#include <unistd.h> +#include <unordered_map> +#include <utility> + +namespace signals { + +namespace { + +std::unordered_map<int, int> g_fds; + +int signum(Signal signal) { + switch (signal) { + case Signal::INT: + return SIGINT; + case Signal::TERM: + return SIGTERM; + } + std::unreachable(); +} + +void signal_handler(int signum) { + auto it = g_fds.find(signum); + if (it != g_fds.end()) { + char c = 1; + while (true) { + auto ret = write(it->second, &c, 1); + if (ret < 0 && errno == EINTR) + continue; + break; + } + } +} + +class HandlerImpl : public Handler { + public: + HandlerImpl(looper::Looper& looper, Signal signal, + std::function<void()> callback) + : looper_(looper), + signal_(signum(signal)), + callback_(std::move(callback)) { + looper_.add(pipe_.reader(), looper::EVENT_READ, + [this](auto event) { call(event); }); + g_fds[signal_] = pipe_.writer(); + + ::signal(signal_, signal_handler); + } + + ~HandlerImpl() override { + ::signal(signal_, SIG_DFL); + looper_.remove(pipe_.reader()); + g_fds.erase(signal_); + } + + private: + void call(uint8_t /* event */) { + char buf[10]; + while (true) { + auto ret = read(pipe_.reader(), buf, 10); + if (ret < 0 && errno == EINTR) + continue; + break; + } + callback_(); + } + + unique_pipe pipe_; + looper::Looper& looper_; + int signal_; + std::function<void()> callback_; +}; + +} // namespace + +std::unique_ptr<Handler> Handler::create(looper::Looper& looper, Signal signal, + std::function<void()> callback) { + return std::make_unique<HandlerImpl>(looper, signal, std::move(callback)); +} + +} // namespace signals |
