watchdog: add support for systemd watchdog

Add interfaces and handling for systemd watchdog petting.

Systemd service files can specify a watchdog timeout and systemd will
expect the application to periodically poke a software watchdog, or
else the service will be restarted.  This is enabled with the
'WatchdogSec=' service file directive.  Add primitives for
interacting with the watchdog APIs.

Enable automatic support in the `async::context` for this watchdog
handling, such that if the watchdog is required (by checking
sd_watchdog_enabled) the daemon will automatically pet at the
appropriate rate, assuming that the `async::context` is functioning
correctly.

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I68caf7b2c7166ca402b07ecee3db65f75365aa72
diff --git a/src/async/context.cpp b/src/async/context.cpp
index 3381cb3..d4ec5e9 100644
--- a/src/async/context.cpp
+++ b/src/async/context.cpp
@@ -1,6 +1,8 @@
 #include <systemd/sd-bus.h>
 
 #include <sdbusplus/async/context.hpp>
+#include <sdbusplus/async/task.hpp>
+#include <sdbusplus/async/timer.hpp>
 
 #include <chrono>
 
@@ -146,8 +148,29 @@
     }
 }
 
+static auto watchdog_loop(sdbusplus::async::context& ctx) -> task<>
+{
+    auto watchdog_time =
+        std::chrono::microseconds(ctx.get_bus().watchdog_enabled());
+    if (watchdog_time.count() == 0)
+    {
+        co_return;
+    }
+
+    // Recommended interval is half of WATCHDOG_USEC
+    watchdog_time /= 2;
+
+    while (!ctx.stop_requested())
+    {
+        ctx.get_bus().watchdog_pet();
+        co_await sleep_for(ctx, watchdog_time);
+    }
+}
+
 void context::worker_run()
 {
+    internal_tasks.spawn(watchdog_loop(*this));
+
     // Start the sdbus 'wait/process' loop; treat it as an internal task.
     internal_tasks.spawn(details::wait_process_completion::loop(*this));