/** * Kick the watchdog. * * After kicking, it's guaranteed that the callback will not be triggering * before the configured period. */ void wd_kick(watchdog_t *wd) { watchdog_check(wd); wd->last_kick = tm_time(); }
/** * Free watchdog. */ static void wd_free(watchdog_t *wd) { watchdog_check(wd); wd_sleep(wd); atom_str_free_null(&wd->name); WFREE(wd); }
/** * Start watchdog timer. */ static void wd_start(watchdog_t *wd) { watchdog_check(wd); /* watchdog period given in seconds */ wd->last_kick = 0; wd->ev = cq_main_insert(wd->period * 1000, wd_expired, wd); }
/** * Put the watchdog to sleep. * * @return TRUE if we stopped the watchdog, FALSE if it was already aslept. */ bool wd_sleep(watchdog_t *wd) { watchdog_check(wd); if (NULL == wd->ev) return FALSE; cq_cancel(&wd->ev); return TRUE; }
/** * Wakeup the watchdog, initiating the timer at the configured period. * If no call to wd_kick() are made within the period, the callback will * fire. * * @return TRUE if we woken up the watchdog, FALSE if it was already awake. */ bool wd_wakeup(watchdog_t *wd) { watchdog_check(wd); if (wd->ev) return FALSE; wd_start(wd); return TRUE; }
/** * Create a new watchdog. * * @param name the watchdog name, for logging purposes * @param period the period after which it triggers, in seconds * @param trigger the callback to invoke if no kicking during period * @param arg the user-supplied argument given to callback * @param start whether to start immediately, or put in sleep state * * @return the created watchdog object. */ watchdog_t * wd_make(const char *name, int period, wd_trigger_t trigger, void *arg, bool start) { watchdog_t *wd; WALLOC0(wd); wd->magic = WATCHDOG_MAGIC; wd->name = atom_str_get(name); wd->period = period; wd->trigger = trigger; wd->arg = arg; if (start) wd_start(wd); watchdog_check(wd); return wd; }
/** * Trigger callback and then put the watchdog to sleep, ignoring any desire * from the callback to re-arm the watchdog. * * @return TRUE if we stopped the watchdog, FALSE if it was already aslept, * in which case the trigger was not invoked. */ bool wd_expire(watchdog_t *wd) { watchdog_check(wd); if (NULL == wd->ev) return FALSE; cq_cancel(&wd->ev); (*wd->trigger)(wd, wd->arg); if (wd->ev != NULL) { g_critical("%s(): " "watchdog \"%s\" re-armed within %s() callback, turning it off", G_STRFUNC, wd_name(wd), stacktrace_function_name(wd->trigger)); } return TRUE; }
/** * Watchdog timer has expired. */ static void wd_expired(cqueue_t *cq, void *arg) { watchdog_t *wd = arg; watchdog_check(wd); wd->ev = NULL; /* * If no kicks have happened, fire the registered callback. Otherwise, * reset the callout queue event, so that the sliding window is starting * when the last tick happened. */ if (0 == wd->last_kick) { wd_trigger(wd); } else { time_t now = tm_time(); time_delta_t elapsed = delta_time(now, wd->last_kick); /* * If for some reason the callout queue heartbeat got delayed, more * than ``period'' seconds may have elapsed since the last kick, in * which case we also need to trigger the callback. * * Note that watchdog ``period'' is expressed in seconds. */ if (elapsed >= wd->period) { wd_trigger(wd); } else { time_delta_t delay = wd->period - elapsed; wd->ev = cq_insert(cq, delay * 1000, wd_expired, wd); } } }
/* * this routine serves two purposes: * 1. report progress * 2. check for deadlocks */ void *reporter(void *arg) { int status; int end = 0; struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = USEC_TO_NSEC(report_interval); tsnorm(&ts); if (duration >= 0) end = duration + time(NULL); /* sleep initially to let everything get up and running */ status = clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); if (status) { error("from clock_nanosleep: %s\n", strerror(status)); return NULL; } debug("reporter: starting report loop\n"); info("Press Control-C to stop test\nCurrent Inversions: \n"); for (;;) { pthread_mutex_lock(&shutdown_mtx); if (shutdown) { pthread_mutex_unlock(&shutdown_mtx); break; } pthread_mutex_unlock(&shutdown_mtx); /* wait for our reporting interval */ status = clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); if (status) { error("from clock_nanosleep: %s\n", strerror(status)); break; } /* check for signaled shutdown */ if (!quiet) { pthread_mutex_lock(&shutdown_mtx); if (shutdown == 0) { fputs(UP_ONE, stdout); printf("Current Inversions: %lu\n", total_inversions()); } } pthread_mutex_unlock(&shutdown_mtx); /* if we specified a duration, see if it has expired */ if (end && time(NULL) > end) { info("duration reached (%d seconds)\n", duration); set_shutdown_flag(); continue; } /* check for a pending SIGINT */ if (pending_interrupt()) { info("Keyboard Interrupt!\n"); break; } /* check watchdog stuff */ if ((watchdog_check())) { error("reporter stopping due to watchdog event\n"); set_shutdown_flag(); break; } /* clear watchdog counters */ watchdog_clear(); } debug("reporter: finished\n"); set_shutdown_flag(); return NULL; }