software_watchdog.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // reference: http://man7.org/linux/man-pages/man2/timer_create.2.html
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <time.h>
  5. #include <signal.h>
  6. #include <stdlib.h>
  7. #include <pthread.h>
  8. #include <unistd.h>
  9. #include <stdbool.h>
  10. #include "software_watchdog.h"
  11. #define CLOCKID CLOCK_REALTIME
  12. #define SIG SIGRTMIN
  13. void printHelloWorld() {
  14. printf("HelloWorld\n");
  15. }
  16. void subTime(struct timespec *t1, struct timespec *subtrahend) {
  17. // get the time difference between now and latestKick
  18. t1->tv_sec -= subtrahend->tv_sec;
  19. if (t1->tv_nsec < subtrahend->tv_nsec) {
  20. // e.g. t1 = 5s.10000ns, subtrahend = 3s.90000ns
  21. t1->tv_nsec = 1000000000 - (subtrahend->tv_nsec - t1->tv_nsec);
  22. t1->tv_sec += 1;
  23. }
  24. else {
  25. // e.g. t1 = 5s.50000ns, subtrahend = 3s.30000ns
  26. t1->tv_nsec -= subtrahend->tv_nsec;
  27. }
  28. }
  29. int compareTime(struct timespec* t1, struct timespec* t2) {
  30. if(t1->tv_sec < t2->tv_sec)
  31. return -1;
  32. if(t1->tv_sec > t2->tv_sec)
  33. return 1;
  34. if(t1->tv_nsec < t2->tv_nsec)
  35. return -1;
  36. if(t1->tv_nsec > t2->tv_nsec)
  37. return 1;
  38. return 0; // equal
  39. }
  40. void *timer (void *data) {
  41. SoftwareWatchdog* watchdog = data;
  42. pthread_mutex_lock(&(watchdog->mutex));
  43. struct timespec now, diff, remaining_sleeptime;
  44. remaining_sleeptime = watchdog->timeout;
  45. pthread_mutex_unlock(&(watchdog->mutex));
  46. while (watchdog->isEnabled) {
  47. // printf ("%s: remaining_sleeptime: %ds,%dns", watchdog->name, remaining_sleeptime); fflush(stdout);
  48. // printf ("%s: sleep start\n", watchdog->name); fflush(stdout);
  49. nanosleep(&remaining_sleeptime, &remaining_sleeptime);
  50. // printf ("%s: sleep end\n", watchdog->name); fflush(stdout);
  51. // get the current time
  52. clock_gettime(CLOCK_REALTIME, &(now));
  53. // get the time difference between now and latestKick
  54. pthread_mutex_lock(&(watchdog->mutex));
  55. diff = now;
  56. subTime(&diff, &(watchdog->latestKick));
  57. pthread_mutex_unlock(&(watchdog->mutex));
  58. if (watchdog->isEnabled && compareTime(&diff, &(watchdog->timeout)) > 0) { // the deadline has been missed
  59. // printf ("%s: calling timeout_cb\n", watchdog->name); fflush(stdout);
  60. watchdog->timeout_cb(watchdog);
  61. remaining_sleeptime = watchdog->timeout;
  62. }
  63. else {
  64. // printf ("%s: no need to call timeout_cb\n", watchdog->name); fflush(stdout);
  65. remaining_sleeptime = watchdog->timeout;
  66. subTime(&remaining_sleeptime, &diff);
  67. }
  68. }
  69. }
  70. int swd_setup(SoftwareWatchdog* watchdog, char *name, timeout_cb_t timeout_cb, struct timespec timeout, void *userData){
  71. // TODO: check input parameters
  72. watchdog->name = strdup(name);
  73. watchdog->timeout_cb = timeout_cb;
  74. watchdog->timeout = timeout;
  75. watchdog->userData = userData;
  76. watchdog->isEnabled = false;
  77. pthread_mutex_init(&(watchdog->mutex), NULL);
  78. }
  79. int swd_enable(SoftwareWatchdog* watchdog) {
  80. if (watchdog->isEnabled) {
  81. // That's really bad and should not happen
  82. return -1;
  83. }
  84. // create and detach the timer
  85. swd_kick(watchdog); // kick it, to initialize the watchdog->latestKick
  86. watchdog->isEnabled = true;
  87. pthread_create(&(watchdog->thread_id), NULL, timer, (void*)watchdog);
  88. pthread_detach(watchdog->thread_id);
  89. // printf("%s: threadid: %d\n", watchdog->name, watchdog->thread_id); fflush(stdout);
  90. return 0;
  91. }
  92. void swd_disable(SoftwareWatchdog* watchdog) {
  93. watchdog->isEnabled = false;
  94. }
  95. void swd_kick(SoftwareWatchdog* watchdog) {
  96. pthread_mutex_lock(&(watchdog->mutex));
  97. clock_gettime(CLOCK_REALTIME, &(watchdog->latestKick));
  98. pthread_mutex_unlock(&(watchdog->mutex));
  99. }