timing.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2008 - 2009, Digium, Inc.
  5. *
  6. * Kevin P. Fleming <kpfleming@digium.com>
  7. * Russell Bryant <russell@digium.com>
  8. *
  9. * See http://www.asterisk.org for more information about
  10. * the Asterisk project. Please do not directly contact
  11. * any of the maintainers of this project for assistance;
  12. * the project provides a web site, mailing lists and IRC
  13. * channels for your use.
  14. *
  15. * This program is free software, distributed under the terms of
  16. * the GNU General Public License Version 2. See the LICENSE file
  17. * at the top of the source tree.
  18. */
  19. /*! \file
  20. *
  21. * \brief Timing source management
  22. *
  23. * \author Kevin P. Fleming <kpfleming@digium.com>
  24. * \author Russell Bryant <russell@digium.com>
  25. */
  26. /*** MODULEINFO
  27. <support_level>core</support_level>
  28. ***/
  29. #include "asterisk.h"
  30. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  31. #include "asterisk/_private.h"
  32. #include "asterisk/timing.h"
  33. #include "asterisk/lock.h"
  34. #include "asterisk/cli.h"
  35. #include "asterisk/utils.h"
  36. #include "asterisk/time.h"
  37. #include "asterisk/heap.h"
  38. #include "asterisk/module.h"
  39. #include "asterisk/poll-compat.h"
  40. struct timing_holder {
  41. /*! Do _not_ move this from the beginning of the struct. */
  42. ssize_t __heap_index;
  43. struct ast_module *mod;
  44. struct ast_timing_interface *iface;
  45. };
  46. static struct ast_heap *timing_interfaces;
  47. struct ast_timer {
  48. void *data;
  49. struct timing_holder *holder;
  50. };
  51. static int timing_holder_cmp(void *_h1, void *_h2)
  52. {
  53. struct timing_holder *h1 = _h1;
  54. struct timing_holder *h2 = _h2;
  55. if (h1->iface->priority > h2->iface->priority) {
  56. return 1;
  57. } else if (h1->iface->priority == h2->iface->priority) {
  58. return 0;
  59. } else {
  60. return -1;
  61. }
  62. }
  63. void *_ast_register_timing_interface(struct ast_timing_interface *funcs,
  64. struct ast_module *mod)
  65. {
  66. struct timing_holder *h;
  67. if (!funcs->timer_open ||
  68. !funcs->timer_close ||
  69. !funcs->timer_set_rate ||
  70. !funcs->timer_ack ||
  71. !funcs->timer_get_event ||
  72. !funcs->timer_get_max_rate ||
  73. !funcs->timer_enable_continuous ||
  74. !funcs->timer_disable_continuous ||
  75. !funcs->timer_fd) {
  76. return NULL;
  77. }
  78. if (!(h = ast_calloc(1, sizeof(*h)))) {
  79. return NULL;
  80. }
  81. h->iface = funcs;
  82. h->mod = mod;
  83. ast_heap_wrlock(timing_interfaces);
  84. ast_heap_push(timing_interfaces, h);
  85. ast_heap_unlock(timing_interfaces);
  86. return h;
  87. }
  88. int ast_unregister_timing_interface(void *handle)
  89. {
  90. struct timing_holder *h = handle;
  91. int res = -1;
  92. ast_heap_wrlock(timing_interfaces);
  93. h = ast_heap_remove(timing_interfaces, h);
  94. ast_heap_unlock(timing_interfaces);
  95. if (h) {
  96. ast_free(h);
  97. h = NULL;
  98. res = 0;
  99. }
  100. return res;
  101. }
  102. struct ast_timer *ast_timer_open(void)
  103. {
  104. void *data = NULL;
  105. struct timing_holder *h;
  106. struct ast_timer *t = NULL;
  107. ast_heap_rdlock(timing_interfaces);
  108. if ((h = ast_heap_peek(timing_interfaces, 1))) {
  109. data = h->iface->timer_open();
  110. ast_module_ref(h->mod);
  111. }
  112. if (data) {
  113. if (!(t = ast_calloc(1, sizeof(*t)))) {
  114. h->iface->timer_close(data);
  115. } else {
  116. t->data = data;
  117. t->holder = h;
  118. }
  119. }
  120. ast_heap_unlock(timing_interfaces);
  121. return t;
  122. }
  123. void ast_timer_close(struct ast_timer *handle)
  124. {
  125. handle->holder->iface->timer_close(handle->data);
  126. ast_module_unref(handle->holder->mod);
  127. ast_free(handle);
  128. }
  129. int ast_timer_fd(const struct ast_timer *handle)
  130. {
  131. return handle->holder->iface->timer_fd(handle->data);
  132. }
  133. int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
  134. {
  135. return handle->holder->iface->timer_set_rate(handle->data, rate);
  136. }
  137. int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
  138. {
  139. return handle->holder->iface->timer_ack(handle->data, quantity);
  140. }
  141. int ast_timer_enable_continuous(const struct ast_timer *handle)
  142. {
  143. return handle->holder->iface->timer_enable_continuous(handle->data);
  144. }
  145. int ast_timer_disable_continuous(const struct ast_timer *handle)
  146. {
  147. return handle->holder->iface->timer_disable_continuous(handle->data);
  148. }
  149. enum ast_timer_event ast_timer_get_event(const struct ast_timer *handle)
  150. {
  151. return handle->holder->iface->timer_get_event(handle->data);
  152. }
  153. unsigned int ast_timer_get_max_rate(const struct ast_timer *handle)
  154. {
  155. return handle->holder->iface->timer_get_max_rate(handle->data);
  156. }
  157. const char *ast_timer_get_name(const struct ast_timer *handle)
  158. {
  159. return handle->holder->iface->name;
  160. }
  161. static char *timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  162. {
  163. struct ast_timer *timer;
  164. int count = 0;
  165. struct timeval start, end;
  166. unsigned int test_rate = 50;
  167. switch (cmd) {
  168. case CLI_INIT:
  169. e->command = "timing test";
  170. e->usage = "Usage: timing test <rate>\n"
  171. " Test a timer with a specified rate, 50/sec by default.\n"
  172. "";
  173. return NULL;
  174. case CLI_GENERATE:
  175. return NULL;
  176. }
  177. if (a->argc != 2 && a->argc != 3) {
  178. return CLI_SHOWUSAGE;
  179. }
  180. if (a->argc == 3) {
  181. unsigned int rate;
  182. if (sscanf(a->argv[2], "%30u", &rate) == 1) {
  183. test_rate = rate;
  184. } else {
  185. ast_cli(a->fd, "Invalid rate '%s', using default of %u\n", a->argv[2], test_rate);
  186. }
  187. }
  188. ast_cli(a->fd, "Attempting to test a timer with %u ticks per second.\n", test_rate);
  189. if (!(timer = ast_timer_open())) {
  190. ast_cli(a->fd, "Failed to open timing fd\n");
  191. return CLI_FAILURE;
  192. }
  193. ast_cli(a->fd, "Using the '%s' timing module for this test.\n", timer->holder->iface->name);
  194. start = ast_tvnow();
  195. ast_timer_set_rate(timer, test_rate);
  196. while (ast_tvdiff_ms((end = ast_tvnow()), start) < 1000) {
  197. int res;
  198. struct pollfd pfd = {
  199. .fd = ast_timer_fd(timer),
  200. .events = POLLIN | POLLPRI,
  201. };
  202. res = ast_poll(&pfd, 1, 100);
  203. if (res == 1) {
  204. count++;
  205. if (ast_timer_ack(timer, 1) < 0) {
  206. ast_cli(a->fd, "Timer failed to acknowledge.\n");
  207. ast_timer_close(timer);
  208. return CLI_FAILURE;
  209. }
  210. } else if (!res) {
  211. ast_cli(a->fd, "poll() timed out! This is bad.\n");
  212. } else if (errno != EAGAIN && errno != EINTR) {
  213. ast_cli(a->fd, "poll() returned error: %s\n", strerror(errno));
  214. }
  215. }
  216. ast_timer_close(timer);
  217. timer = NULL;
  218. ast_cli(a->fd, "It has been %" PRIi64 " milliseconds, and we got %d timer ticks\n",
  219. ast_tvdiff_ms(end, start), count);
  220. return CLI_SUCCESS;
  221. }
  222. static struct ast_cli_entry cli_timing[] = {
  223. AST_CLI_DEFINE(timing_test, "Run a timing test"),
  224. };
  225. static void timing_shutdown(void)
  226. {
  227. ast_cli_unregister_multiple(cli_timing, ARRAY_LEN(cli_timing));
  228. ast_heap_destroy(timing_interfaces);
  229. timing_interfaces = NULL;
  230. }
  231. int ast_timing_init(void)
  232. {
  233. if (!(timing_interfaces = ast_heap_create(2, timing_holder_cmp, 0))) {
  234. return -1;
  235. }
  236. ast_register_cleanup(timing_shutdown);
  237. return ast_cli_register_multiple(cli_timing, ARRAY_LEN(cli_timing));
  238. }