timer.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /*
  2. * timer.cpp
  3. *
  4. * Created on: Nov 9, 2015
  5. * Author: Philipp Hinz
  6. * Source: http://man7.org/linux/man-pages/man2/timer_create.2.html
  7. * http://www.informit.com/articles/article.aspx?p=23618&seqNum=14
  8. */
  9. #include <csignal>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <stdint.h>
  14. //#include <sys/time.h>
  15. #include <time.h>
  16. #include <pthread.h>
  17. #include <errno.h>
  18. //#include <unistd.h>
  19. #include "global.h"
  20. #include "timer.h"
  21. #include "logger.h"
  22. int counter = 0;
  23. int timercnt = 10;
  24. timer *firstTimer = NULL;
  25. timer *lastTimer = NULL;
  26. /**
  27. * Timer constructor
  28. * Depending on the call of the constructor the handler will be called as thread or not
  29. * @param *handler target pointer to the method
  30. */
  31. timer::timer(void (*handler)(void)) {
  32. this->active = false;
  33. this->divider = 0;
  34. this->handler = handler;
  35. this->thandler = NULL;
  36. this->next = firstTimer;
  37. this->asThread = false;
  38. this->id = timercnt++;
  39. this->thread = pthread_t();
  40. firstTimer = this;
  41. }
  42. timer::timer(void *(*handler)(void *)) {
  43. this->active = false;
  44. this->divider = 0;
  45. this->thandler = handler;
  46. this->handler = NULL;
  47. this->next = firstTimer;
  48. this->thread = pthread_t();
  49. this->id = timercnt++;
  50. // Now calling a dummy thread, to allow later the check of the thread state
  51. int rc = pthread_create(&this->thread, NULL, nullThread, (void *) this->id);
  52. if (rc) {
  53. logger_error("Error: unable to create thread in timer, %d\n", rc);
  54. exit(-1);
  55. }
  56. this->asThread = true;
  57. firstTimer = this;
  58. }
  59. /**
  60. * Calls the timer handler if enabled
  61. */
  62. // void *MainLoop(void *threadid)
  63. void timer::call() {
  64. int rc, ret = 0;
  65. if (this->asThread) {
  66. if (this->thread)
  67. ret = pthread_kill(this->thread, 0);
  68. if (ret == ESRCH) { // Thread clear
  69. pthread_detach(this->thread); // Important! Freeing the resources of the previous thread
  70. rc = pthread_create(&this->thread, NULL, this->thandler,
  71. (void *) this->id);
  72. if (rc) {
  73. logger_error(
  74. "Error: unable to create thread in timer, %s (%d)\n",
  75. strerror(rc), rc);
  76. exit(-1);
  77. }
  78. }
  79. } else
  80. this->handler();
  81. }
  82. /**
  83. * enables the timer
  84. */
  85. void timer::start() {
  86. this->active = true;
  87. }
  88. /**
  89. * disables the timer
  90. */
  91. void timer::stop() {
  92. this->active = false;
  93. }
  94. /**
  95. * sets the divider for this timer (based on system timer)
  96. * @param divider integer timer divider
  97. */
  98. void timer::setDivider(unsigned int divider) {
  99. this->divider = divider;
  100. }
  101. /**
  102. * reads the timer divider
  103. * @return timer divider
  104. */
  105. int timer::getDivider() {
  106. return this->divider;
  107. }
  108. /**
  109. * Returns the timers active state
  110. * @return true if active
  111. */
  112. bool timer::isActive() {
  113. return this->active;
  114. }
  115. /**
  116. * this method is called by the system timer and handles the other timers
  117. */
  118. void timer_handler(int sig, siginfo_t *si, void *uc) {
  119. timer *t = firstTimer;
  120. if (++counter >= TIMER_DELAY_US)
  121. counter = 0;
  122. while (t != NULL) {
  123. if (t->isActive() && t->getDivider() > 0
  124. && (counter % t->getDivider()) == 0)
  125. t->call();
  126. t = t->next;
  127. }
  128. }
  129. /**
  130. * inits the system timer based on signals
  131. */
  132. void initTimers(void) {
  133. /*struct sigaction sa;
  134. struct itimerval timer;
  135. * Install timer_handler as the signal handler for SIGVTALRM.
  136. memset(&sa, 0, sizeof(sa));
  137. sa.sa_handler = &timer_handler;
  138. sigaction(SIGVTALRM, &sa, NULL);*/
  139. timer_t timerid;
  140. struct sigevent sev;
  141. struct itimerspec its;
  142. //sigset_t mask;
  143. struct sigaction sa;
  144. /* Establish handler for timer signal */
  145. logger(V_BASIC, "timer.cpp: Establishing handler for signal %d\n", SIG);
  146. sa.sa_flags = SA_SIGINFO;
  147. sa.sa_sigaction = &timer_handler;
  148. sigemptyset(&sa.sa_mask);
  149. if (sigaction(SIG, &sa, NULL) == -1)
  150. errExit("sigaction");
  151. /* Block timer signal temporarily
  152. printf("Blocking signal %d\n", SIG);
  153. sigemptyset(&mask);
  154. sigaddset(&mask, SIG);
  155. if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1)
  156. errExit("sigprocmask"); */
  157. /* Create the timer */
  158. sev.sigev_notify = SIGEV_SIGNAL;
  159. sev.sigev_signo = SIG;
  160. sev.sigev_value.sival_ptr = &timerid;
  161. if (timer_create(CLOCKID, &sev, &timerid) == -1)
  162. errExit("timer_create");
  163. logger(V_BASIC, "timer ID is 0x%lx\n", (long) timerid);
  164. /* Configure the timer to expire after x msec... */
  165. its.it_value.tv_sec = TIMER_DELAY_US / 1000000;
  166. its.it_value.tv_nsec = TIMER_DELAY_US * 1000;
  167. /* ... and every x msec after that. */
  168. its.it_interval.tv_sec = its.it_value.tv_sec;
  169. its.it_interval.tv_nsec = its.it_value.tv_nsec;
  170. /* Start a virtual timer. It counts down whenever this process is
  171. executing. */
  172. //setitimer(ITIMER_VIRTUAL, &timer, NULL);
  173. if (timer_settime(timerid, 0, &its, NULL) == -1)
  174. errExit("timer_settime");
  175. counter = 0;
  176. }
  177. /**
  178. * Calculates the divider corresponding to the given period.
  179. * If the given period does not match exactly to a divider, the
  180. * next higher is returned!
  181. */
  182. uint32_t ms2Divider(uint64_t millisec) {
  183. uint32_t divider = (millisec * 1000) / (uint64_t) TIMER_DELAY_US;
  184. if (((uint64_t) divider * TIMER_DELAY_US) < (millisec * 1000)) return ++divider;
  185. else return divider;
  186. }
  187. /**
  188. * Stops all existing timers
  189. */
  190. void stopTimers(void) {
  191. timer *t = firstTimer;
  192. while (t != NULL) {
  193. t->stop();
  194. t = t->next;
  195. }
  196. logger(V_BASIC, "Stopped all timers.\n");
  197. }
  198. /**
  199. * This is a dummy thread
  200. * @param *threadid Thread ID
  201. */
  202. void *nullThread(void *threadid) {
  203. pthread_exit(NULL);
  204. }