res_timing_timerfd.c 6.5 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. if (timer->fd > -1) {
  69. close(timer->fd);
  70. }
  71. }
  72. static void *timerfd_timer_open(void)
  73. {
  74. struct timerfd_timer *timer;
  75. if (!(timer = ao2_alloc(sizeof(*timer), timer_destroy))) {
  76. ast_log(LOG_ERROR, "Could not allocate memory for timerfd_timer structure\n");
  77. return NULL;
  78. }
  79. if ((timer->fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
  80. ast_log(LOG_ERROR, "Failed to create timerfd timer: %s\n", strerror(errno));
  81. ao2_ref(timer, -1);
  82. return NULL;
  83. }
  84. return timer;
  85. }
  86. static void timerfd_timer_close(void *data)
  87. {
  88. ao2_ref(data, -1);
  89. }
  90. static int timerfd_timer_set_rate(void *data, unsigned int rate)
  91. {
  92. struct timerfd_timer *timer = data;
  93. int res = 0;
  94. ao2_lock(timer);
  95. timer->saved_timer.it_value.tv_sec = 0;
  96. timer->saved_timer.it_value.tv_nsec = rate ? (long) (1000000000 / rate) : 0L;
  97. timer->saved_timer.it_interval.tv_sec = timer->saved_timer.it_value.tv_sec;
  98. timer->saved_timer.it_interval.tv_nsec = timer->saved_timer.it_value.tv_nsec;
  99. if (!timer->is_continuous) {
  100. res = timerfd_settime(timer->fd, 0, &timer->saved_timer, NULL);
  101. }
  102. ao2_unlock(timer);
  103. return res;
  104. }
  105. static int timerfd_timer_ack(void *data, unsigned int quantity)
  106. {
  107. struct timerfd_timer *timer = data;
  108. uint64_t expirations;
  109. int read_result = 0;
  110. int res = 0;
  111. ao2_lock(timer);
  112. do {
  113. struct itimerspec timer_status;
  114. if (timerfd_gettime(timer->fd, &timer_status)) {
  115. ast_log(LOG_ERROR, "Call to timerfd_gettime() using handle %d error: %s\n", timer->fd, strerror(errno));
  116. expirations = 0;
  117. res = -1;
  118. break;
  119. }
  120. if (timer_status.it_value.tv_sec == 0 && timer_status.it_value.tv_nsec == 0) {
  121. ast_debug(1, "Avoiding read on disarmed timerfd %d\n", timer->fd);
  122. expirations = 0;
  123. break;
  124. }
  125. read_result = read(timer->fd, &expirations, sizeof(expirations));
  126. if (read_result == -1) {
  127. if (errno == EINTR || errno == EAGAIN) {
  128. continue;
  129. } else {
  130. ast_log(LOG_ERROR, "Read error: %s\n", strerror(errno));
  131. res = -1;
  132. break;
  133. }
  134. }
  135. } while (read_result != sizeof(expirations));
  136. ao2_unlock(timer);
  137. if (expirations != quantity) {
  138. ast_debug(2, "Expected to acknowledge %u ticks but got %llu instead\n", quantity, (unsigned long long) expirations);
  139. }
  140. return res;
  141. }
  142. static int timerfd_timer_enable_continuous(void *data)
  143. {
  144. struct timerfd_timer *timer = data;
  145. int res;
  146. static const struct itimerspec continuous_timer = {
  147. .it_value.tv_nsec = 1L,
  148. };
  149. ao2_lock(timer);
  150. if (timer->is_continuous) {
  151. /*It's already in continous mode, no need to do
  152. * anything further
  153. */
  154. ao2_unlock(timer);
  155. return 0;
  156. }
  157. res = timerfd_settime(timer->fd, 0, &continuous_timer, &timer->saved_timer);
  158. timer->is_continuous = 1;
  159. ao2_unlock(timer);
  160. return res;
  161. }
  162. static int timerfd_timer_disable_continuous(void *data)
  163. {
  164. struct timerfd_timer *timer = data;
  165. int res;
  166. ao2_lock(timer);
  167. if (!timer->is_continuous) {
  168. /* No reason to do anything if we're not
  169. * in continuous mode
  170. */
  171. ao2_unlock(timer);
  172. return 0;
  173. }
  174. res = timerfd_settime(timer->fd, 0, &timer->saved_timer, NULL);
  175. timer->is_continuous = 0;
  176. memset(&timer->saved_timer, 0, sizeof(timer->saved_timer));
  177. ao2_unlock(timer);
  178. return res;
  179. }
  180. static enum ast_timer_event timerfd_timer_get_event(void *data)
  181. {
  182. struct timerfd_timer *timer = data;
  183. enum ast_timer_event res;
  184. ao2_lock(timer);
  185. if (timer->is_continuous) {
  186. res = AST_TIMING_EVENT_CONTINUOUS;
  187. } else {
  188. res = AST_TIMING_EVENT_EXPIRED;
  189. }
  190. ao2_unlock(timer);
  191. return res;
  192. }
  193. static unsigned int timerfd_timer_get_max_rate(void *data)
  194. {
  195. return TIMERFD_MAX_RATE;
  196. }
  197. static int timerfd_timer_fd(void *data)
  198. {
  199. struct timerfd_timer *timer = data;
  200. return timer->fd;
  201. }
  202. static int load_module(void)
  203. {
  204. int fd;
  205. /* Make sure we support the necessary clock type */
  206. if ((fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
  207. ast_log(LOG_ERROR, "timerfd_create() not supported by the kernel. Not loading.\n");
  208. return AST_MODULE_LOAD_DECLINE;
  209. }
  210. close(fd);
  211. if (!(timing_funcs_handle = ast_register_timing_interface(&timerfd_timing))) {
  212. return AST_MODULE_LOAD_DECLINE;
  213. }
  214. return AST_MODULE_LOAD_SUCCESS;
  215. }
  216. static int unload_module(void)
  217. {
  218. return ast_unregister_timing_interface(timing_funcs_handle);
  219. }
  220. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Timerfd Timing Interface",
  221. .support_level = AST_MODULE_SUPPORT_CORE,
  222. .load = load_module,
  223. .unload = unload_module,
  224. .load_pri = AST_MODPRI_TIMING,
  225. );