From c82a2ce215beb12dc5a8ff2c0d39ef6a3f3a3352 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Thu, 28 Dec 2017 20:24:32 +0100 Subject: [PATCH] Built-in watchdog: on SIGPWR, exit main loop and prepare for SIGTERM When Finit enters shutdown/reboot we need to advise any watchdogd that we are going down *before* we unmount any file systems. This to let the user save any state, e.g. reboot counters, to disk. Right before we call reboot() in Finit we send SIGTERM to the watchdogd to give it the chance to use the WDT to reboot the system. The WDT cricuitry on embedded systems is often connected to the RESETn logic of all relevant board compoents, whereas reboot() only reboots the SoC with the CPU. Hence, a WDT reboot is more efficient and more like a regular power cycle, which users of embedded systems often want. Signed-off-by: Joachim Nilsson --- src/watchdog.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/watchdog.c b/src/watchdog.c index e7f070e7..85b49940 100644 --- a/src/watchdog.c +++ b/src/watchdog.c @@ -31,15 +31,19 @@ int running = 1; int handover = 0; +int shutdown = 0; static void sighandler(int signo) { if (signo == SIGTERM) handover = 1; + if (signo == SIGPWR) + shutdown = 1; + running = 0; } -static int init(char *progname, char *devnode, int timeout) +static int init(char *progname, char *devnode) { int fd; @@ -51,20 +55,28 @@ static int init(char *progname, char *devnode, int timeout) if (fd == -1) return -1; - ioctl(fd, WDIOC_SETTIMEOUT, &timeout); - return fd; } -static int loop(int fd, int period) +static int loop(int fd, int timeout) { int dummy = 0; + int period = timeout / 2; + + ioctl(fd, WDIOC_SETTIMEOUT, &timeout); while (running) { ioctl(fd, WDIOC_KEEPALIVE, &dummy); sleep(period); } + /* System is going down, prepare to reboot system on TERM */ + if (shutdown) { + timeout /= 3; + ioctl(fd, WDIOC_SETTIMEOUT, &timeout); + } + + /* External watchdogd wants to take over ... */ if (handover) { ioctl(fd, WDIOC_KEEPALIVE, &dummy); return !write(fd, "V", 1); @@ -81,13 +93,20 @@ int watchdog(char *progname) if (pid == 0) { int fd, ret; - fd = init(progname, WDT_DEVNODE, WDT_TIMEOUT); + fd = init(progname, WDT_DEVNODE); if (fd == -1) { _pe("Failed connecting to watchdog %s", WDT_DEVNODE); _exit(1); } - ret = loop(fd, WDT_TIMEOUT / 2); + ret = loop(fd, WDT_TIMEOUT); + while (!handover) { + /* Waiting for SIGTERM ... */ + sleep(1); + + /* Set lowest possible timeout on SIGTERM */ + ioctl(fd, WDIOC_SETTIMEOUT, &shutdown); + } close(fd); _exit(ret);