software_watchdog.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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 <stdbool.h>
  8. #include "software_watchdog.h"
  9. #ifdef _WIN32
  10. #define CLOCK_REALTIME 0
  11. #define NOMINMAX
  12. #define WIN32_LEAN_AND_MEAN
  13. #include <windows.h>
  14. int nanosleep(const struct timespec* req, struct timespec* rem) {
  15. double ms;
  16. ms = req->tv_sec * 1000.0 + req->tv_nsec / 1000000;
  17. Sleep(ms);
  18. return 0;
  19. }
  20. LARGE_INTEGER
  21. getFILETIMEoffset()
  22. {
  23. SYSTEMTIME s;
  24. FILETIME f;
  25. LARGE_INTEGER t;
  26. s.wYear = 1970;
  27. s.wMonth = 1;
  28. s.wDay = 1;
  29. s.wHour = 0;
  30. s.wMinute = 0;
  31. s.wSecond = 0;
  32. s.wMilliseconds = 0;
  33. SystemTimeToFileTime(&s, &f);
  34. t.QuadPart = f.dwHighDateTime;
  35. t.QuadPart <<= 32;
  36. t.QuadPart |= f.dwLowDateTime;
  37. return (t);
  38. }
  39. int
  40. clock_gettime(int X, struct timeval *tv)
  41. {
  42. LARGE_INTEGER t;
  43. FILETIME f;
  44. double microseconds;
  45. static LARGE_INTEGER offset;
  46. static double frequencyToMicroseconds;
  47. static int initialized = 0;
  48. static BOOL usePerformanceCounter = 0;
  49. if (!initialized) {
  50. LARGE_INTEGER performanceFrequency;
  51. initialized = 1;
  52. usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);
  53. if (usePerformanceCounter) {
  54. QueryPerformanceCounter(&offset);
  55. frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.;
  56. } else {
  57. offset = getFILETIMEoffset();
  58. frequencyToMicroseconds = 10.;
  59. }
  60. }
  61. if (usePerformanceCounter) QueryPerformanceCounter(&t);
  62. else {
  63. GetSystemTimeAsFileTime(&f);
  64. t.QuadPart = f.dwHighDateTime;
  65. t.QuadPart <<= 32;
  66. t.QuadPart |= f.dwLowDateTime;
  67. }
  68. t.QuadPart -= offset.QuadPart;
  69. microseconds = (double)t.QuadPart / frequencyToMicroseconds;
  70. t.QuadPart = microseconds;
  71. tv->tv_sec = t.QuadPart / 1000000;
  72. tv->tv_usec = t.QuadPart % 1000000;
  73. return (0);
  74. }
  75. #else
  76. #include <pthread.h>
  77. #include <unistd.h>
  78. #endif
  79. #define CLOCKID CLOCK_REALTIME
  80. #define SIG SIGRTMIN
  81. void printHelloWorld() {
  82. printf("HelloWorld\n");
  83. }
  84. void subTime(struct timespec *t1, struct timespec *subtrahend) {
  85. // get the time difference between now and latestKick
  86. t1->tv_sec -= subtrahend->tv_sec;
  87. if (t1->tv_nsec < subtrahend->tv_nsec) {
  88. // e.g. t1 = 5s.10000ns, subtrahend = 3s.90000ns
  89. t1->tv_nsec = 1000000000 - (subtrahend->tv_nsec - t1->tv_nsec);
  90. t1->tv_sec += 1;
  91. }
  92. else {
  93. // e.g. t1 = 5s.50000ns, subtrahend = 3s.30000ns
  94. t1->tv_nsec -= subtrahend->tv_nsec;
  95. }
  96. }
  97. int compareTime(struct timespec* t1, struct timespec* t2) {
  98. if(t1->tv_sec < t2->tv_sec)
  99. return -1;
  100. if(t1->tv_sec > t2->tv_sec)
  101. return 1;
  102. if(t1->tv_nsec < t2->tv_nsec)
  103. return -1;
  104. if(t1->tv_nsec > t2->tv_nsec)
  105. return 1;
  106. return 0; // equal
  107. }
  108. void *timer (void *data) {
  109. SoftwareWatchdog* watchdog = data;
  110. pthread_mutex_lock(&(watchdog->mutex));
  111. struct timespec now, diff, remaining_sleeptime;
  112. remaining_sleeptime = watchdog->timeout;
  113. pthread_mutex_unlock(&(watchdog->mutex));
  114. while (watchdog->isEnabled) {
  115. // printf ("%s: remaining_sleeptime: %ds,%dns", watchdog->name, remaining_sleeptime); fflush(stdout);
  116. // printf ("%s: sleep start\n", watchdog->name); fflush(stdout);
  117. nanosleep(&remaining_sleeptime, &remaining_sleeptime);
  118. // printf ("%s: sleep end\n", watchdog->name); fflush(stdout);
  119. // get the current time
  120. clock_gettime(CLOCK_REALTIME, &(now));
  121. // get the time difference between now and latestKick
  122. pthread_mutex_lock(&(watchdog->mutex));
  123. diff = now;
  124. subTime(&diff, &(watchdog->latestKick));
  125. pthread_mutex_unlock(&(watchdog->mutex));
  126. if (watchdog->isEnabled && compareTime(&diff, &(watchdog->timeout)) > 0) { // the deadline has been missed
  127. // printf ("%s: calling timeout_cb\n", watchdog->name); fflush(stdout);
  128. watchdog->timeout_cb(watchdog);
  129. remaining_sleeptime = watchdog->timeout;
  130. }
  131. else {
  132. // printf ("%s: no need to call timeout_cb\n", watchdog->name); fflush(stdout);
  133. remaining_sleeptime = watchdog->timeout;
  134. subTime(&remaining_sleeptime, &diff);
  135. }
  136. }
  137. }
  138. int swd_setup(SoftwareWatchdog* watchdog, const char *name, timeout_cb_t timeout_cb, struct timespec timeout, void *userData){
  139. // TODO: check input parameters
  140. watchdog->name = strdup(name);
  141. watchdog->timeout_cb = timeout_cb;
  142. watchdog->timeout = timeout;
  143. watchdog->userData = userData;
  144. watchdog->isEnabled = false;
  145. pthread_mutex_init(&(watchdog->mutex), NULL);
  146. }
  147. int swd_enable(SoftwareWatchdog* watchdog) {
  148. if (watchdog->isEnabled) {
  149. // That's really bad and should not happen
  150. return -1;
  151. }
  152. // create and detach the timer
  153. swd_kick(watchdog); // kick it, to initialize the watchdog->latestKick
  154. watchdog->isEnabled = true;
  155. pthread_create(&(watchdog->thread_id), NULL, timer, (void*)watchdog);
  156. pthread_detach(watchdog->thread_id);
  157. // printf("%s: threadid: %d\n", watchdog->name, watchdog->thread_id); fflush(stdout);
  158. return 0;
  159. }
  160. void swd_disable(SoftwareWatchdog* watchdog) {
  161. watchdog->isEnabled = false;
  162. }
  163. void swd_kick(SoftwareWatchdog* watchdog) {
  164. pthread_mutex_lock(&(watchdog->mutex));
  165. clock_gettime(CLOCK_REALTIME, &(watchdog->latestKick));
  166. pthread_mutex_unlock(&(watchdog->mutex));
  167. }