timer.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. * Copyright (C) 2010-2011 Michael Buesch <m@bues.ch>
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include "timer.h"
  15. #include "main.h"
  16. #include "log.h"
  17. #include "conf.h"
  18. #include <time.h>
  19. #include <unistd.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <errno.h>
  23. #include <string.h>
  24. #include <assert.h>
  25. #include <sys/prctl.h>
  26. static LIST_HEAD(timer_list);
  27. static timer_id_t id_counter;
  28. static inline void timer_lock(void)
  29. {
  30. block_signals();
  31. }
  32. static inline void timer_unlock(void)
  33. {
  34. unblock_signals();
  35. }
  36. static void timespec_add_msec(struct timespec *ts, unsigned int msec)
  37. {
  38. unsigned int seconds, nsec;
  39. seconds = msec / 1000;
  40. msec = msec % 1000;
  41. nsec = msec * 1000000;
  42. ts->tv_nsec += nsec;
  43. while (ts->tv_nsec >= 1000000000) {
  44. ts->tv_sec++;
  45. ts->tv_nsec -= 1000000000;
  46. }
  47. ts->tv_sec += seconds;
  48. }
  49. static int timespec_bigger(const struct timespec *a, const struct timespec *b)
  50. {
  51. if (a->tv_sec > b->tv_sec)
  52. return 1;
  53. if ((a->tv_sec == b->tv_sec) && (a->tv_nsec > b->tv_nsec))
  54. return 1;
  55. return 0;
  56. }
  57. static inline int timespec_after(const struct timespec *a, const struct timespec *b)
  58. {
  59. return timespec_bigger(a, b);
  60. }
  61. void sleeptimer_init(struct sleeptimer *timer,
  62. const char *name,
  63. sleeptimer_callback_t callback)
  64. {
  65. memset(timer, 0, sizeof(*timer));
  66. timer->name = name;
  67. timer->callback = callback;
  68. INIT_LIST_HEAD(&timer->list);
  69. logverbose("timer: %s registered\n", name);
  70. }
  71. void sleeptimer_set_timeout_relative(struct sleeptimer *timer,
  72. unsigned int msecs)
  73. {
  74. int err;
  75. err = clock_gettime(CLOCK_MONOTONIC, &timer->timeout);
  76. if (err) {
  77. logerr("WARNING: clock_gettime() failed: %s\n",
  78. strerror(errno));
  79. return;
  80. }
  81. timespec_add_msec(&timer->timeout, msecs);
  82. }
  83. static void do_sleeptimer_dequeue(struct sleeptimer *timer)
  84. {
  85. list_del_init(&timer->list);
  86. }
  87. void sleeptimer_enqueue(struct sleeptimer *timer)
  88. {
  89. struct sleeptimer *i;
  90. int inserted = 0;
  91. timer_lock();
  92. if (!list_empty(&timer->list))
  93. do_sleeptimer_dequeue(timer);
  94. list_for_each_entry(i, &timer_list, list) {
  95. if (timespec_after(&i->timeout, &timer->timeout)) {
  96. list_add_tail(&timer->list, &i->list);
  97. inserted = 1;
  98. break;
  99. }
  100. }
  101. if (!inserted)
  102. list_add_tail(&timer->list, &timer_list);
  103. timer->id = id_counter++;
  104. timer_unlock();
  105. }
  106. void sleeptimer_dequeue(struct sleeptimer *timer)
  107. {
  108. timer_lock();
  109. do_sleeptimer_dequeue(timer);
  110. timer_unlock();
  111. }
  112. int sleeptimer_system_init(void)
  113. {
  114. #ifdef PR_SET_TIMERSLACK
  115. unsigned long slack;
  116. slack = config_get_int(backend.config, "SYSTEM", "event_slack", 1010);
  117. slack *= 1000000ul; /* To nanoseconds */
  118. if (prctl(PR_SET_TIMERSLACK, slack, 0, 0, 0))
  119. logerr("Failed to set timerslack to %lu ns. Ignoring.\n", slack);
  120. #else
  121. # warning "PR_SET_TIMERSLACK not available. Ignoring."
  122. #endif
  123. return 0;
  124. }
  125. int sleeptimer_wait_next(void)
  126. {
  127. struct timespec timeout;
  128. struct sleeptimer *timer = NULL;
  129. timer_id_t timer_id = 0;
  130. int err;
  131. timer_lock();
  132. if (!list_empty(&timer_list)) {
  133. timer = list_first_entry(&timer_list, struct sleeptimer, list);
  134. timeout = timer->timeout;
  135. timer_id = timer->id;
  136. }
  137. timer_unlock();
  138. if (!timer)
  139. return -ENOENT;
  140. while (1) {
  141. err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
  142. &timeout, NULL);
  143. if (!err)
  144. break;
  145. if (err == EAGAIN)
  146. continue;
  147. if (err != EINTR) {
  148. logerr("WARNING: clock_nanosleep() failed: %s\n",
  149. strerror(err));
  150. break;
  151. }
  152. }
  153. timer_lock();
  154. list_for_each_entry(timer, &timer_list, list) {
  155. if (timer->id == timer_id) {
  156. do_sleeptimer_dequeue(timer);
  157. timer->callback(timer);
  158. break;
  159. }
  160. }
  161. timer_unlock();
  162. return 0;
  163. }