summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-06-22 09:00:56 +0200
committerDavid Härdeman <david@hardeman.nu>2020-06-22 09:00:56 +0200
commit49ae8b30a8f6ca89114af89b215b655de8ea66f8 (patch)
treea5e0eb122cf99756488bba5db59199a5ec6cadf1
parent94bbdce6b742ab2f62cfa9513e13f27a0f78973b (diff)
Improve signal handler to mimic signalfd better
-rw-r--r--main.c136
-rw-r--r--utils.h3
2 files changed, 69 insertions, 70 deletions
diff --git a/main.c b/main.c
index df1f958..66ed1b4 100644
--- a/main.c
+++ b/main.c
@@ -11,7 +11,6 @@
#include <stdbool.h>
#include <getopt.h>
#include <sys/signalfd.h>
-#include <sys/eventfd.h>
#include <signal.h>
#include <systemd/sd-daemon.h>
#include <cap-ng.h>
@@ -545,10 +544,11 @@ cfg_apply(struct cfg *cfg)
}
struct signalfd_ev {
- struct uring_task task;
//struct signalfd_siginfo buf;
struct cfg *cfg;
- uint64_t buf;
+ struct uring_task task;
+ struct uring_task_buf tbuf;
+ int pipe[2];
};
static void
@@ -591,25 +591,63 @@ dump_tree(struct cfg *cfg)
debug(DBG_REF, "\n\n");
}
-static struct dns_async *hack_dns = NULL;
-
static void
signalfd_read(struct cfg *cfg, struct uring_task *task, int res)
{
struct signalfd_ev *sev = container_of(task, struct signalfd_ev, task);
struct server *server, *stmp;
+ static unsigned count = 0;
+ siginfo_t *si;
assert_return(cfg && task);
assert_task_alive(DBG_SIG, task);
- if (res != sizeof(sev->buf))
+ si = (siginfo_t *)task->tbuf->buf;
+ if (res != sizeof(*si))
die("error in signalfd (%i)", res);
- if (sev->buf < 1000) {
+ switch (si->si_signo) {
+ case SIGUSR1: {
+ struct dns_async *dns;
+
+ debug(DBG_SIG, "Got a SIGUSR1");
+ if (si->si_code != SI_ASYNCNL || !si->si_ptr) {
+ error("SIGUSR1: unexpected values in siginfo");
+ goto out;
+ }
+
+ dns = si->si_ptr;
+ if (!dns->cb) {
+ error("DNS callback not set");
+ goto out;
+ }
+
+ debug(DBG_DNS, "DNS lookup complete, dns: %p, dns->cb: %p",
+ dns, dns->cb);
+ dns->cb(dns);
+ break;
+ }
+
+ case SIGUSR2:
+ debug(DBG_SIG, "got a SIGUSR2");
+ dump_tree(cfg);
+ break;
+
+ case SIGTERM:
+ debug(DBG_SIG, "Got a SIGINT/SIGHUP");
verbose("got a signal to quit");
sd_notifyf(0, "STOPPING=1\nSTATUS=Received signal, exiting");
exit(EXIT_SUCCESS);
- } else if (sev->buf < 10000) {
+ break;
+
+ case SIGINT:
+ case SIGHUP:
+ count++;
+ if (count > 5) {
+ dump_tree(cfghack);
+ exit(EXIT_FAILURE);
+ }
+
verbose("got a signal to dump tree");
sd_notifyf(0, "STOPPING=1\nSTATUS=Received signal, exiting");
dump_tree(cfg);
@@ -622,75 +660,32 @@ signalfd_read(struct cfg *cfg, struct uring_task *task, int res)
server_delete(cfg, server);
uring_delete(cfg);
return;
- } else {
- debug(DBG_DNS, "DNS lookup complete, dns: %p, dns->cb: %p",
- hack_dns,
- hack_dns ? hack_dns->cb : NULL);
- if (!hack_dns || !hack_dns->cb) {
- error("DNS callback not set");
- goto out;
- }
-
- hack_dns->cb(hack_dns);
+ default:
+ error("got an unknown signal: %i", si->si_signo);
+ break;
}
out:
- uring_read(cfg, &sev->task, &sev->buf, sizeof(sev->buf), signalfd_read);
+ uring_tbuf_read(cfg, &sev->task, signalfd_read);
}
-static int hack_efd = -1;
-
static void
-hack_handler(int signum, siginfo_t *info, void *ucontext)
+hack_signal_handler(int signum, siginfo_t *si, void *ucontext)
{
- uint64_t val;
- static unsigned count = 0;
+ ssize_t r;
- assert_return(signum > 0 && info);
+ assert_return(signum > 0 && si);
- count++;
- if (count > 5) {
- dump_tree(cfghack);
- exit(EXIT_FAILURE);
- }
+ r = write(cfghack->sev->pipe[PIPE_WR], si, sizeof(*si));
+ if (r != sizeof(*si))
+ error("write: %zi\n", r);
- switch (signum) {
- case SIGUSR1:
- debug(DBG_SIG, "Got a SIGUSR1");
- if (info->si_code != SI_ASYNCNL || info->si_signo != SIGUSR1 || !info->si_ptr) {
- debug(DBG_SIG, "unexpected values in siginfo");
- return;
- }
- debug(DBG_SIG, "SIGUSR1 struct dns_async: %p", info->si_ptr);
- hack_dns = info->si_ptr;
- val = 10000;
- break;
- case SIGINT:
- debug(DBG_SIG, "Got a SIGINT");
- val = 1000;
- break;
- case SIGHUP:
- debug(DBG_SIG, "Got a SIGHUP");
- val = 1000;
- break;
- case SIGTERM:
- debug(DBG_SIG, "Got a SIGTERM");
- val = 1;
- break;
- default:
- error("Got an unknown sig (%i)", signum);
- val = 1;
- break;
- }
-
- write(hack_efd, &val, sizeof(val));
}
static void
signalfd_init(struct cfg *cfg)
{
- int sfd;
//sigset_t mask;
struct signalfd_ev *sev;
@@ -700,6 +695,9 @@ signalfd_init(struct cfg *cfg)
if (!sev)
die("malloc: %m");
+ if (pipe2(sev->pipe, O_CLOEXEC) < 0)
+ die("pipe2: %m");
+
/*
sigfillset(&mask);
if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
@@ -712,29 +710,27 @@ signalfd_init(struct cfg *cfg)
struct sigaction action;
sigfillset(&action.sa_mask);
- action.sa_sigaction = hack_handler;
+ action.sa_sigaction = hack_signal_handler;
action.sa_flags = SA_SIGINFO;
sigaction(SIGINT, &action, NULL);
sigaction(SIGHUP, &action, NULL);
sigaction(SIGTERM, &action, NULL);
sigaction(SIGUSR1, &action, NULL);
+ sigaction(SIGUSR2, &action, NULL);
action.sa_handler = SIG_IGN;
action.sa_flags = 0;
sigaction(SIGPIPE, &action, NULL);
- sfd = eventfd(0, EFD_CLOEXEC);
- if (sfd < 0)
- die("eventfd: %m");
-
- debug(DBG_SIG, "using fd %i", sfd);
+ debug(DBG_SIG, "using pipe fds %i -> %i",
+ sev->pipe[PIPE_WR], sev->pipe[PIPE_RD]);
uring_task_init(cfg, &sev->task, "sev", uring_parent(cfg), signalfd_free);
- uring_task_set_fd(&sev->task, sfd);
+ uring_task_set_fd(&sev->task, sev->pipe[PIPE_RD]);
+ uring_task_set_buf(&sev->task, &sev->tbuf);
cfg->sev = sev;
sev->cfg = cfg;
- hack_efd = sfd;
- uring_read(cfg, &sev->task, &sev->buf, sizeof(sev->buf), signalfd_read);
+ uring_tbuf_read(cfg, &sev->task, signalfd_read);
}
int
diff --git a/utils.h b/utils.h
index a38602c..3e807bc 100644
--- a/utils.h
+++ b/utils.h
@@ -152,6 +152,9 @@ static inline bool list_empty(struct list_head *list)
return list->next == list;
}
+#define PIPE_RD 0
+#define PIPE_WR 1
+
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)