The watchdog API is typically used to monitor the progress of an application. In the following example, a thread is dedicated to the watchdog.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <assert.h> #include <util/chKnTimeVal.h> #include <sched/chSched.h> #include <exec/chExec.h> #include <sync/chSem.h> #include <cx/wdt.h> #define WDT_RUNS 10 /* number of times the test is run */ #define WDT_PAT_TIMES 3 /* number of times the timer * is patted at each interval */ #define WDT_PAT_INC 10 /* timeout interval increment */ #define WDT_PAT_MIN 5 /* initial, minimum timeout interval */ #define WDT_STACKSIZE 1000 /* worker thread stack size */ #define WDT_THREAD_PRIO 3 /* worker thread (very high) priority */ #define WDT_EXTRA_SLEEP 10 /* extra delay to check that the timer * is truly disarmed */ wdt_handle_t wdt_handle = 0; /* watchdog timer handle */ /* * sleep for 'secs' seconds, displaying a symbol at each elapsed second */ void wdt_sleep(int secs) { KnTimeVal tv = { 1, 0 }; int i; putchar('['); for (i = 0; i < secs; i++) { threadDelay(&tv); if (i && (i % 60 == 59)) putchar('#'); else if (i && (i % 10 == 9)) putchar('|'); else putchar('.'); fflush(stdout); } printf("]\n"); } /* * check the return value of a system call */ void wdt_check(char* fn, int res) { printf("%s: ", fn); if (res < 0) printf("ERROR: res = %d, errno = %d (%s)\n", res, errno, strerror(errno)); else printf("SUCCESS: res = %d\n", res); } /* * arm, pat, then disarm the watchdog timer */ int wdt_arm_pat_disarm(int min, int max, int inc, int times, int armed) { timespec_t tv; int res, intv, wait, pats; intv = min; while (intv < max) { tv.tv_sec = intv; tv.tv_nsec = 0; /* timer already armed? */ if (!armed) { printf("\nsetting interval to %d s...\n", intv); res = wdt_set_interval(wdt_handle, &tv); wdt_check("wdt_set_interval()", res); if (res < 0) return res; printf("arming...\n"); res = wdt_arm(wdt_handle); wdt_check("wdt_arm()", res); if (res < 0) return res; } printf("patting...\n"); for (pats = 0; pats < times; pats++) { /* pat 1 sec before the timer expires */ wait = intv - 1; printf("sleeping for %d s\n", wait); wdt_sleep(wait); res = wdt_pat(wdt_handle); wdt_check("wdt_pat()", res); if (res < 0) return res; } printf("disarming...\n"); res = wdt_disarm(wdt_handle); wdt_check("wdt_disarm()", res); if (res < 0) return res; armed = 0; /* wait 'WDT_EXTRA_SLEEP' secs more than last configured interval */ wait = intv + WDT_EXTRA_SLEEP; printf("checking that the watchdog timer is stopped...\n"); printf("sleeping for %d s...\n", wait); wdt_sleep(wait); intv += inc; } return 0; } static KnSem wdt_sem; /* * worker thread */ void wdt_thread() { timespec_t max; int armed, i, res, min; for (i = 0; i < WDT_RUNS; i++) { /* Allocate watchdog timer. If timer is already allocated (busy), a previous instance of the actor was killed. In this case, reallocate timer and, if it is armed, continue the test without disarming it */ res = wdt_alloc(&wdt_handle); wdt_check("wdt_alloc()", res); if (res < 0 && errno == EBUSY) { printf("watchdog timer busy -> reallocating it\n"); /* Reallocate timer, using the magic handle (as we have no knowledge of the actual handle previously allocated). this call also pats the timer if it is armed */ wdt_handle = WDT_MAGIC_HANDLE; res = wdt_realloc(&wdt_handle); wdt_check("wdt_realloc()", res); } printf("--> watchdog handle = %d\n", wdt_handle); if (res < 0) break; /* the timer may be already armed when we reallocate it */ res = armed = wdt_is_armed(wdt_handle); wdt_check("wdt_is_armed()", res); if (res < 0) break; printf("--> the watchdog timer is currently%s armed\n", armed ? "" : " NOT"); /* ok, get current timeout interval of the armed timer */ if (armed) { timespec_t intv; res = wdt_get_interval(wdt_handle, &intv); wdt_check("wdt_get_interval()", res); if (res < 0) break; printf("--> current interval = %d.%09d s\n", intv.tv_sec, intv.tv_nsec); /* continue test at point where preceding actor was killed */ min = intv.tv_sec; } else { min = WDT_PAT_MIN; } /* then get the maximum allowed timeout interval */ res = wdt_get_maxinterval(wdt_handle, &max); wdt_check("wdt_get_maxinterval()", res); printf( "--> max interval = %d.%09d s\n", max.tv_sec, max.tv_nsec); if (res < 0) break; res = wdt_arm_pat_disarm(min, max.tv_sec - WDT_EXTRA_SLEEP, WDT_PAT_INC, WDT_PAT_TIMES, armed); if (res < 0) break; res = wdt_free(wdt_handle); wdt_check("wdt_free()", res); if (res < 0) break; } /* test completed */ semV(&wdt_sem); threadDelete(K_MYACTOR, K_MYSELF); } static long wdt_stack[WDT_STACKSIZE]; /* watchdog thread stack */ int main() { KnThreadLid childLid; KnThreadDefaultSched schedParam; KnDefaultStartInfo_f startInfo; KnActorPrivilege actorPriv; int res; semInit(&wdt_sem, 0); actorPrivilege(K_MYACTOR, &actorPriv, NULL); startInfo.dsPrivilege = (actorPriv == K_SUPACTOR) ? K_SUPTHREAD : K_USERTHREAD; startInfo.dsType = K_DEFAULT_START_INFO; startInfo.dsSystemStackSize = K_DEFAULT_STACK_SIZE; startInfo.dsUserStackPointer = &wdt_stack[WDT_STACKSIZE]; startInfo.dsEntry = (KnPc) wdt_thread; /* heavily increase the priority of the worker thread to ensure that it will not be later delayed by other applicative threads (if any) */ schedParam.tdClass = K_SCHED_DEFAULT; schedParam.tdPriority = WDT_THREAD_PRIO; /* create the worker thread */ res = threadCreate(K_MYACTOR, &childLid, K_ACTIVE, &schedParam, &startInfo); assert(res == 0); /* then wait for the completion of the test */ semP(&wdt_sem, K_NOTIMEOUT); return 0; }