timer.cpp 4.6 KB

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