// reference: http://man7.org/linux/man-pages/man2/timer_create.2.html #include #include #include #include #include #include #include #include #include "software_watchdog.h" #define CLOCKID CLOCK_REALTIME #define SIG SIGRTMIN void printHelloWorld() { printf("HelloWorld\n"); } void subTime(struct timespec *t1, struct timespec *subtrahend) { // get the time difference between now and latestKick t1->tv_sec -= subtrahend->tv_sec; if (t1->tv_nsec < subtrahend->tv_nsec) { // e.g. t1 = 5s.10000ns, subtrahend = 3s.90000ns t1->tv_nsec = 1000000000 - (subtrahend->tv_nsec - t1->tv_nsec); t1->tv_sec += 1; } else { // e.g. t1 = 5s.50000ns, subtrahend = 3s.30000ns t1->tv_nsec -= subtrahend->tv_nsec; } } int compareTime(struct timespec* t1, struct timespec* t2) { if(t1->tv_sec < t2->tv_sec) return -1; if(t1->tv_sec > t2->tv_sec) return 1; if(t1->tv_nsec < t2->tv_nsec) return -1; if(t1->tv_nsec > t2->tv_nsec) return 1; return 0; // equal } void *timer (void *data) { SoftwareWatchdog* watchdog = data; pthread_mutex_lock(&(watchdog->mutex)); struct timespec now, diff, remaining_sleeptime; remaining_sleeptime = watchdog->timeout; pthread_mutex_unlock(&(watchdog->mutex)); while (watchdog->isEnabled) { // printf ("%s: remaining_sleeptime: %ds,%dns", watchdog->name, remaining_sleeptime); fflush(stdout); // printf ("%s: sleep start\n", watchdog->name); fflush(stdout); nanosleep(&remaining_sleeptime, &remaining_sleeptime); // printf ("%s: sleep end\n", watchdog->name); fflush(stdout); // get the current time clock_gettime(CLOCK_REALTIME, &(now)); // get the time difference between now and latestKick pthread_mutex_lock(&(watchdog->mutex)); diff = now; subTime(&diff, &(watchdog->latestKick)); pthread_mutex_unlock(&(watchdog->mutex)); if (watchdog->isEnabled && compareTime(&diff, &(watchdog->timeout)) > 0) { // the deadline has been missed // printf ("%s: calling timeout_cb\n", watchdog->name); fflush(stdout); watchdog->timeout_cb(watchdog); remaining_sleeptime = watchdog->timeout; } else { // printf ("%s: no need to call timeout_cb\n", watchdog->name); fflush(stdout); remaining_sleeptime = watchdog->timeout; subTime(&remaining_sleeptime, &diff); } } } int swd_setup(SoftwareWatchdog* watchdog, char *name, timeout_cb_t timeout_cb, struct timespec timeout, void *userData){ // TODO: check input parameters watchdog->name = strdup(name); watchdog->timeout_cb = timeout_cb; watchdog->timeout = timeout; watchdog->userData = userData; watchdog->isEnabled = false; pthread_mutex_init(&(watchdog->mutex), NULL); } int swd_enable(SoftwareWatchdog* watchdog) { if (watchdog->isEnabled) { // That's really bad and should not happen return -1; } // create and detach the timer swd_kick(watchdog); // kick it, to initialize the watchdog->latestKick watchdog->isEnabled = true; pthread_create(&(watchdog->thread_id), NULL, timer, (void*)watchdog); pthread_detach(watchdog->thread_id); // printf("%s: threadid: %d\n", watchdog->name, watchdog->thread_id); fflush(stdout); return 0; } void swd_disable(SoftwareWatchdog* watchdog) { watchdog->isEnabled = false; } void swd_kick(SoftwareWatchdog* watchdog) { pthread_mutex_lock(&(watchdog->mutex)); clock_gettime(CLOCK_REALTIME, &(watchdog->latestKick)); pthread_mutex_unlock(&(watchdog->mutex)); }