res_timing_timerfd.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2008, Digium, Inc.
  5. *
  6. * Mark Michelson <mmichelson@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*!
  19. * \file
  20. * \author Mark Michelson <mmichelson@digium.com>
  21. *
  22. * \brief timerfd timing interface
  23. */
  24. /*** MODULEINFO
  25. <depend>timerfd</depend>
  26. <support_level>core</support_level>
  27. ***/
  28. #include "asterisk.h"
  29. #include <sys/timerfd.h>
  30. #include "asterisk/module.h"
  31. #include "asterisk/astobj2.h"
  32. #include "asterisk/timing.h"
  33. #include "asterisk/logger.h"
  34. #include "asterisk/utils.h"
  35. #include "asterisk/time.h"
  36. static void *timing_funcs_handle;
  37. static void *timerfd_timer_open(void);
  38. static void timerfd_timer_close(void *data);
  39. static int timerfd_timer_set_rate(void *data, unsigned int rate);
  40. static int timerfd_timer_ack(void *data, unsigned int quantity);
  41. static int timerfd_timer_enable_continuous(void *data);
  42. static int timerfd_timer_disable_continuous(void *data);
  43. static enum ast_timer_event timerfd_timer_get_event(void *data);
  44. static unsigned int timerfd_timer_get_max_rate(void *data);
  45. static int timerfd_timer_fd(void *data);
  46. static struct ast_timing_interface timerfd_timing = {
  47. .name = "timerfd",
  48. .priority = 200,
  49. .timer_open = timerfd_timer_open,
  50. .timer_close = timerfd_timer_close,
  51. .timer_set_rate = timerfd_timer_set_rate,
  52. .timer_ack = timerfd_timer_ack,
  53. .timer_enable_continuous = timerfd_timer_enable_continuous,
  54. .timer_disable_continuous = timerfd_timer_disable_continuous,
  55. .timer_get_event = timerfd_timer_get_event,
  56. .timer_get_max_rate = timerfd_timer_get_max_rate,
  57. .timer_fd = timerfd_timer_fd,
  58. };
  59. #define TIMERFD_MAX_RATE 1000
  60. struct timerfd_timer {
  61. int fd;
  62. struct itimerspec saved_timer;
  63. unsigned int is_continuous:1;
  64. };
  65. static void timer_destroy(void *obj)
  66. {
  67. struct timerfd_timer *timer = obj;
  68. close(timer->fd);
  69. }
  70. static void *timerfd_timer_open(void)
  71. {
  72. struct timerfd_timer *timer;
  73. if (!(timer = ao2_alloc(sizeof(*timer), timer_destroy))) {
  74. ast_log(LOG_ERROR, "Could not allocate memory for timerfd_timer structure\n");
  75. return NULL;
  76. }
  77. if ((timer->fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
  78. ast_log(LOG_ERROR, "Failed to create timerfd timer: %s\n", strerror(errno));
  79. ao2_ref(timer, -1);
  80. return NULL;
  81. }
  82. return timer;
  83. }
  84. static void timerfd_timer_close(void *data)
  85. {
  86. ao2_ref(data, -1);
  87. }
  88. static int timerfd_timer_set_rate(void *data, unsigned int rate)
  89. {
  90. struct timerfd_timer *timer = data;
  91. int res = 0;
  92. ao2_lock(timer);
  93. timer->saved_timer.it_value.tv_sec = 0;
  94. timer->saved_timer.it_value.tv_nsec = rate ? (long) (1000000000 / rate) : 0L;
  95. timer->saved_timer.it_interval.tv_sec = timer->saved_timer.it_value.tv_sec;
  96. timer->saved_timer.it_interval.tv_nsec = timer->saved_timer.it_value.tv_nsec;
  97. if (!timer->is_continuous) {
  98. res = timerfd_settime(timer->fd, 0, &timer->saved_timer, NULL);
  99. }
  100. ao2_unlock(timer);
  101. return res;
  102. }
  103. static int timerfd_timer_ack(void *data, unsigned int quantity)
  104. {
  105. struct timerfd_timer *timer = data;
  106. uint64_t expirations;
  107. int read_result = 0;
  108. int res = 0;
  109. ao2_lock(timer);
  110. do {
  111. struct itimerspec timer_status;
  112. if (timerfd_gettime(timer->fd, &timer_status)) {
  113. ast_log(LOG_ERROR, "Call to timerfd_gettime() using handle %d error: %s\n", timer->fd, strerror(errno));
  114. expirations = 0;
  115. res = -1;
  116. break;
  117. }
  118. if (timer_status.it_value.tv_sec == 0 && timer_status.it_value.tv_nsec == 0) {
  119. ast_debug(1, "Avoiding read on disarmed timerfd %d\n", timer->fd);
  120. expirations = 0;
  121. break;
  122. }
  123. read_result = read(timer->fd, &expirations, sizeof(expirations));
  124. if (read_result == -1) {
  125. if (errno == EINTR || errno == EAGAIN) {
  126. continue;
  127. } else {
  128. ast_log(LOG_ERROR, "Read error: %s\n", strerror(errno));
  129. res = -1;
  130. break;
  131. }
  132. }
  133. } while (read_result != sizeof(expirations));
  134. ao2_unlock(timer);
  135. if (expirations != quantity) {
  136. ast_debug(2, "Expected to acknowledge %u ticks but got %llu instead\n", quantity, (unsigned long long) expirations);
  137. }
  138. return res;
  139. }
  140. static int timerfd_timer_enable_continuous(void *data)
  141. {
  142. struct timerfd_timer *timer = data;
  143. int res;
  144. static const struct itimerspec continuous_timer = {
  145. .it_value.tv_nsec = 1L,
  146. };
  147. ao2_lock(timer);
  148. if (timer->is_continuous) {
  149. /*It's already in continous mode, no need to do
  150. * anything further
  151. */
  152. ao2_unlock(timer);
  153. return 0;
  154. }
  155. res = timerfd_settime(timer->fd, 0, &continuous_timer, &timer->saved_timer);
  156. timer->is_continuous = 1;
  157. ao2_unlock(timer);
  158. return res;
  159. }
  160. static int timerfd_timer_disable_continuous(void *data)
  161. {
  162. struct timerfd_timer *timer = data;
  163. int res;
  164. ao2_lock(timer);
  165. if (!timer->is_continuous) {
  166. /* No reason to do anything if we're not
  167. * in continuous mode
  168. */
  169. ao2_unlock(timer);
  170. return 0;
  171. }
  172. res = timerfd_settime(timer->fd, 0, &timer->saved_timer, NULL);
  173. timer->is_continuous = 0;
  174. memset(&timer->saved_timer, 0, sizeof(timer->saved_timer));
  175. ao2_unlock(timer);
  176. return res;
  177. }
  178. static enum ast_timer_event timerfd_timer_get_event(void *data)
  179. {
  180. struct timerfd_timer *timer = data;
  181. enum ast_timer_event res;
  182. ao2_lock(timer);
  183. if (timer->is_continuous) {
  184. res = AST_TIMING_EVENT_CONTINUOUS;
  185. } else {
  186. res = AST_TIMING_EVENT_EXPIRED;
  187. }
  188. ao2_unlock(timer);
  189. return res;
  190. }
  191. static unsigned int timerfd_timer_get_max_rate(void *data)
  192. {
  193. return TIMERFD_MAX_RATE;
  194. }
  195. static int timerfd_timer_fd(void *data)
  196. {
  197. struct timerfd_timer *timer = data;
  198. return timer->fd;
  199. }
  200. static int load_module(void)
  201. {
  202. int fd;
  203. /* Make sure we support the necessary clock type */
  204. if ((fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
  205. ast_log(LOG_ERROR, "timerfd_create() not supported by the kernel. Not loading.\n");
  206. return AST_MODULE_LOAD_DECLINE;
  207. }
  208. close(fd);
  209. if (!(timing_funcs_handle = ast_register_timing_interface(&timerfd_timing))) {
  210. return AST_MODULE_LOAD_DECLINE;
  211. }
  212. return AST_MODULE_LOAD_SUCCESS;
  213. }
  214. static int unload_module(void)
  215. {
  216. return ast_unregister_timing_interface(timing_funcs_handle);
  217. }
  218. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Timerfd Timing Interface",
  219. .support_level = AST_MODULE_SUPPORT_CORE,
  220. .load = load_module,
  221. .unload = unload_module,
  222. .load_pri = AST_MODPRI_TIMING,
  223. );