/* * SPDX license identifier: MPL-2.0 * * Copyright (C) 2011-2015, BMW AG * * This file is part of GENIVI Project DLT - Diagnostic Log and Trace. * * This Source Code Form is subject to the terms of the * Mozilla Public License (MPL), v. 2.0. * If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. * * For further information see http://www.genivi.org/. */ /*! * \author * Lassi Marttala * Alexander Wenzel * Markus Klein * Mikko Rapeli * * \copyright Copyright © 2011-2015 BMW AG. \n * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/. * * \file dlt-system-watchdog.c */ #if defined(DLT_SYSTEMD_WATCHDOG_ENABLE) #include #include #include #include #include "dlt.h" #include "dlt-system.h" #include #include DLT_DECLARE_CONTEXT(watchdogContext) DLT_IMPORT_CONTEXT(dltsystem) int calculate_period(struct itimerspec *itval) { unsigned int ns; unsigned int sec; char str[512]; char *watchdogUSec; unsigned int watchdogTimeoutSeconds; unsigned int notifiyPeriodNSec; watchdogUSec = getenv("WATCHDOG_USEC"); if (watchdogUSec == NULL) { DLT_LOG(watchdogContext, DLT_LOG_ERROR, DLT_STRING("systemd watchdog timeout (WATCHDOG_USEC) is null\n")); return -1; } DLT_LOG(watchdogContext, DLT_LOG_DEBUG, DLT_STRING("watchdogusec: "), DLT_STRING(watchdogUSec)); watchdogTimeoutSeconds = atoi(watchdogUSec); if (watchdogTimeoutSeconds <= 0) { snprintf(str, 512, "systemd watchdog timeout incorrect: %u\n", watchdogTimeoutSeconds); DLT_LOG(watchdogContext, DLT_LOG_ERROR, DLT_STRING(str)); return -1; } /* Calculate half of WATCHDOG_USEC in ns for timer tick */ notifiyPeriodNSec = watchdogTimeoutSeconds / 2; snprintf(str, 512, "systemd watchdog timeout: %u nsec - timer will be initialized: %u nsec\n", watchdogTimeoutSeconds, notifiyPeriodNSec); DLT_LOG(watchdogContext, DLT_LOG_DEBUG, DLT_STRING(str)); /* Make the timer periodic */ sec = notifiyPeriodNSec / 1000000; ns = (notifiyPeriodNSec - (sec * 1000000)) * 1000; itval->it_interval.tv_sec = sec; itval->it_interval.tv_nsec = ns; itval->it_value.tv_sec = sec; itval->it_value.tv_nsec = ns; return 0; } int register_watchdog_fd(struct pollfd *pollfd, int fdcnt) { DLT_REGISTER_CONTEXT(watchdogContext, "DOG", "dlt system watchdog context."); struct itimerspec timerValue; if (calculate_period(&timerValue) != 0) return -1; int timerfd = timerfd_create(CLOCK_MONOTONIC, 0); if (timerfd < 0) { DLT_LOG(dltsystem, DLT_LOG_ERROR, DLT_STRING("Failed to create timer fd\n")); return -1; } pollfd[fdcnt].fd = timerfd; pollfd[fdcnt].events = POLLIN; if (timerfd_settime(timerfd, 0, &timerValue, NULL) < 0) { DLT_LOG(dltsystem, DLT_LOG_ERROR, DLT_STRING("Could not start timer\n")); return -1; } return 0; } void watchdog_fd_handler(int fd) { uint64_t timersElapsed = 0ULL; int r = read(fd, &timersElapsed, 8U); // only needed to reset fd event if(r < 0) DLT_LOG(watchdogContext, DLT_LOG_ERROR, DLT_STRING("Could not reset systemd watchdog. Exit with: "), DLT_STRING(strerror(r))); if (sd_notify(0, "WATCHDOG=1") < 0) DLT_LOG(watchdogContext, DLT_LOG_ERROR, DLT_STRING("Could not reset systemd watchdog\n")); DLT_LOG(watchdogContext, DLT_LOG_DEBUG, DLT_STRING("systemd watchdog waited periodic\n")); } #endif