--- /dev/null
+/*
+ * tvheadend, systemd watchdog support
+ * Copyright (C) 2017-2018 Erkki Seppälä
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "watchdog.h"
+#include "tvheadend.h"
+
+#include <systemd/sd-daemon.h>
+
+static pthread_t watchdog_tid;
+static pthread_mutex_t watchdog_exiting_mutex;
+static tvh_cond_t watchdog_exiting_cond;
+static int watchdog_exiting; /* 1 if exit has been requested */
+static int watchdog_enabled; /* 1 if watchdog was enabled for the systemd unit */
+static uint64_t watchdog_interval_usec; /* value from .service divided by 2 */
+
+static void* watchdog_thread(void* aux)
+{
+ int exiting = 0;
+ (void) aux; /* ignore */
+ sd_notify(0, "READY=1");
+ pthread_mutex_lock(&watchdog_exiting_mutex);
+ while (!exiting) {
+ if (!watchdog_exiting) {
+ /*
+ * Just keep ticking regardless the return value; its intention is
+ * to pace the loop down, and let us exit fast when the time comes
+ */
+ tvh_cond_timedwait(&watchdog_exiting_cond, &watchdog_exiting_mutex, mclk() + watchdog_interval_usec);
+ if (!watchdog_exiting) {
+ pthread_mutex_lock(&global_lock);
+ pthread_mutex_unlock(&global_lock);
+ sd_notify(0, "WATCHDOG=1");
+ }
+ }
+ exiting = watchdog_exiting;
+ }
+ pthread_mutex_unlock(&watchdog_exiting_mutex);
+
+ return NULL;
+}
+
+void watchdog_init(void)
+{
+ /*
+ * I doubt MONOCLOCK_RESOLUTION is going to change, but if it does,
+ * let's break this
+ */
+#if MONOCLOCK_RESOLUTION != 1000000LL
+#error "Watchdog assumes MONOCLOCK_RESOLUTION == 1000000LL"
+#endif
+
+ watchdog_enabled = sd_watchdog_enabled(0, &watchdog_interval_usec) > 0;
+ if (watchdog_enabled) {
+ /* suggested by sd_watchdog_enabled documentation: */
+ watchdog_interval_usec /= 2;
+
+ watchdog_exiting = 0;
+ tvh_cond_init(&watchdog_exiting_cond);
+ pthread_mutex_init(&watchdog_exiting_mutex, NULL);
+
+ tvhthread_create(&watchdog_tid, NULL, watchdog_thread, NULL, "systemd watchdog");
+ }
+}
+
+void watchdog_done(void)
+{
+ if (watchdog_enabled) {
+ pthread_mutex_lock(&watchdog_exiting_mutex);
+ watchdog_exiting = 1;
+ tvh_cond_signal(&watchdog_exiting_cond, 0);
+ pthread_mutex_unlock(&watchdog_exiting_mutex);
+
+ pthread_join(watchdog_tid, NULL);
+
+ tvh_cond_destroy(&watchdog_exiting_cond);
+ pthread_mutex_destroy(&watchdog_exiting_mutex);
+ }
+}
--- /dev/null
+/*
+ * tvheadend, systemd watchdog support
+ * Copyright (C) 2017-2018 Erkki Seppälä
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef WATCHDOG_H_
+#define WATCHDOG_H_
+
+#include "config.h"
+
+#if ENABLE_LIBSYSTEMD_DAEMON
+
+void watchdog_init(void);
+void watchdog_done(void);
+
+#else /* #if ENABLE_LIBSYSTEMD_DAEMON */
+
+static inline void watchdog_init(void) { }
+static inline void watchdog_done(void) { }
+
+#endif /* #if else ENABLE_LIBSYSTEMD_DAEMON */
+
+
+#endif /* WATCHDOG_H_ */