summaryrefslogtreecommitdiff
path: root/src/signals.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/signals.cc')
-rw-r--r--src/signals.cc89
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