res_timing_kqueue.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2010, Digium, Inc.
  5. *
  6. * Tilghman Lesher <tlesher AT digium DOT 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 Tilghman Lesher \verbatim <tlesher AT digium DOT com> \endverbatim
  21. *
  22. * \brief kqueue timing interface
  23. *
  24. * \ingroup resource
  25. */
  26. /*** MODULEINFO
  27. <depend>kqueue</depend>
  28. <conflict>launchd</conflict>
  29. <support_level>extended</support_level>
  30. ***/
  31. #include "asterisk.h"
  32. #include <sys/types.h>
  33. #include <sys/event.h>
  34. #include <sys/time.h>
  35. #include "asterisk/module.h"
  36. #include "asterisk/astobj2.h"
  37. #include "asterisk/timing.h"
  38. #include "asterisk/logger.h"
  39. #include "asterisk/utils.h"
  40. #include "asterisk/time.h"
  41. #include "asterisk/test.h"
  42. #include "asterisk/poll-compat.h" /* for ast_poll() */
  43. static void *timing_funcs_handle;
  44. static void *kqueue_timer_open(void);
  45. static void kqueue_timer_close(void *data);
  46. static int kqueue_timer_set_rate(void *data, unsigned int rate);
  47. static int kqueue_timer_ack(void *data, unsigned int quantity);
  48. static int kqueue_timer_enable_continuous(void *data);
  49. static int kqueue_timer_disable_continuous(void *data);
  50. static enum ast_timer_event kqueue_timer_get_event(void *data);
  51. static unsigned int kqueue_timer_get_max_rate(void *data);
  52. static int kqueue_timer_fd(void *data);
  53. static struct ast_timing_interface kqueue_timing = {
  54. .name = "kqueue",
  55. .priority = 150,
  56. .timer_open = kqueue_timer_open,
  57. .timer_close = kqueue_timer_close,
  58. .timer_set_rate = kqueue_timer_set_rate,
  59. .timer_ack = kqueue_timer_ack,
  60. .timer_enable_continuous = kqueue_timer_enable_continuous,
  61. .timer_disable_continuous = kqueue_timer_disable_continuous,
  62. .timer_get_event = kqueue_timer_get_event,
  63. .timer_get_max_rate = kqueue_timer_get_max_rate,
  64. .timer_fd = kqueue_timer_fd,
  65. };
  66. struct kqueue_timer {
  67. intptr_t period;
  68. int handle;
  69. #ifndef EVFILT_USER
  70. int continuous_fd;
  71. unsigned int continuous_fd_valid:1;
  72. #endif
  73. unsigned int is_continuous:1;
  74. };
  75. #ifdef EVFILT_USER
  76. #define CONTINUOUS_EVFILT_TYPE EVFILT_USER
  77. static int kqueue_timer_init_continuous_event(struct kqueue_timer *timer)
  78. {
  79. return 0;
  80. }
  81. static int kqueue_timer_enable_continuous_event(struct kqueue_timer *timer)
  82. {
  83. struct kevent kev[2];
  84. EV_SET(&kev[0], (uintptr_t)timer, EVFILT_USER, EV_ADD | EV_ENABLE,
  85. 0, 0, NULL);
  86. EV_SET(&kev[1], (uintptr_t)timer, EVFILT_USER, 0, NOTE_TRIGGER,
  87. 0, NULL);
  88. return kevent(timer->handle, kev, 2, NULL, 0, NULL);
  89. }
  90. static int kqueue_timer_disable_continuous_event(struct kqueue_timer *timer)
  91. {
  92. struct kevent kev;
  93. EV_SET(&kev, (uintptr_t)timer, EVFILT_USER, EV_DELETE, 0, 0, NULL);
  94. return kevent(timer->handle, &kev, 1, NULL, 0, NULL);
  95. }
  96. static void kqueue_timer_fini_continuous_event(struct kqueue_timer *timer)
  97. {
  98. }
  99. #else /* EVFILT_USER */
  100. #define CONTINUOUS_EVFILT_TYPE EVFILT_READ
  101. static int kqueue_timer_init_continuous_event(struct kqueue_timer *timer)
  102. {
  103. int pipefds[2];
  104. int retval;
  105. retval = pipe(pipefds);
  106. if (retval == 0) {
  107. timer->continuous_fd = pipefds[0];
  108. timer->continuous_fd_valid = 1;
  109. close(pipefds[1]);
  110. }
  111. return retval;
  112. }
  113. static void kqueue_timer_fini_continuous_event(struct kqueue_timer *timer)
  114. {
  115. if (timer->continuous_fd_valid) {
  116. close(timer->continuous_fd);
  117. }
  118. }
  119. static int kqueue_timer_enable_continuous_event(struct kqueue_timer *timer)
  120. {
  121. struct kevent kev;
  122. EV_SET(&kev, timer->continuous_fd, EVFILT_READ, EV_ADD | EV_ENABLE,
  123. 0, 0, NULL);
  124. return kevent(timer->handle, &kev, 1, NULL, 0, NULL);
  125. }
  126. static int kqueue_timer_disable_continuous_event(struct kqueue_timer *timer)
  127. {
  128. struct kevent kev;
  129. EV_SET(&kev, timer->continuous_fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
  130. return kevent(timer->handle, &kev, 1, NULL, 0, NULL);
  131. }
  132. #endif
  133. static void timer_destroy(void *obj)
  134. {
  135. struct kqueue_timer *timer = obj;
  136. ast_debug(5, "[%d]: Timer Destroy\n", timer->handle);
  137. kqueue_timer_fini_continuous_event(timer);
  138. if (timer->handle > -1) {
  139. close(timer->handle);
  140. }
  141. }
  142. static void *kqueue_timer_open(void)
  143. {
  144. struct kqueue_timer *timer;
  145. if (!(timer = ao2_alloc(sizeof(*timer), timer_destroy))) {
  146. ast_log(LOG_ERROR, "Alloc failed for kqueue_timer structure\n");
  147. return NULL;
  148. }
  149. if ((timer->handle = kqueue()) < 0) {
  150. ast_log(LOG_ERROR, "Failed to create kqueue fd: %s\n",
  151. strerror(errno));
  152. ao2_ref(timer, -1);
  153. return NULL;
  154. }
  155. if (kqueue_timer_init_continuous_event(timer) != 0) {
  156. ast_log(LOG_ERROR, "Failed to create continuous event: %s\n",
  157. strerror(errno));
  158. ao2_ref(timer, -1);
  159. return NULL;
  160. }
  161. ast_debug(5, "[%d]: Create timer\n", timer->handle);
  162. return timer;
  163. }
  164. static void kqueue_timer_close(void *data)
  165. {
  166. struct kqueue_timer *timer = data;
  167. ast_debug(5, "[%d]: Timer Close\n", timer->handle);
  168. ao2_ref(timer, -1);
  169. }
  170. /*
  171. * Use the highest precision available that does not overflow
  172. * the datatype kevent is using for time.
  173. */
  174. static intptr_t kqueue_scale_period(unsigned int period_ns, int *units)
  175. {
  176. uint64_t period = period_ns;
  177. *units = 0;
  178. #ifdef NOTE_NSECONDS
  179. if (period < INTPTR_MAX) {
  180. *units = NOTE_NSECONDS;
  181. } else {
  182. #ifdef NOTE_USECONDS
  183. period /= 1000;
  184. if (period < INTPTR_MAX) {
  185. *units = NOTE_USECONDS;
  186. } else {
  187. period /= 1000;
  188. #ifdef NOTE_MSECONDS
  189. *units = NOTE_MSECONDS;
  190. #endif /* NOTE_MSECONDS */
  191. }
  192. #else /* NOTE_USECONDS */
  193. period /= 1000000;
  194. #ifdef NOTE_MSECONDS
  195. *units = NOTE_MSECONDS;
  196. #endif /* NOTE_MSECONDS */
  197. #endif /* NOTE_USECONDS */
  198. }
  199. #else /* NOTE_NSECONDS */
  200. period /= 1000000;
  201. #endif
  202. if (period > INTPTR_MAX) {
  203. period = INTPTR_MAX;
  204. }
  205. return period;
  206. }
  207. static int kqueue_timer_set_rate(void *data, unsigned int rate)
  208. {
  209. struct kevent kev;
  210. struct kqueue_timer *timer = data;
  211. uint64_t period_ns;
  212. int flags;
  213. int units;
  214. int retval;
  215. ao2_lock(timer);
  216. if (rate == 0) {
  217. if (timer->period == 0) {
  218. ao2_unlock(timer);
  219. return (0);
  220. }
  221. flags = EV_DELETE;
  222. timer->period = 0;
  223. units = 0;
  224. } else {
  225. flags = EV_ADD | EV_ENABLE;
  226. period_ns = (uint64_t)1000000000 / rate;
  227. timer->period = kqueue_scale_period(period_ns, &units);
  228. }
  229. ast_debug(5, "[%d]: Set rate %u:%ju\n",
  230. timer->handle, units, (uintmax_t)timer->period);
  231. EV_SET(&kev, timer->handle, EVFILT_TIMER, flags, units,
  232. timer->period, NULL);
  233. retval = kevent(timer->handle, &kev, 1, NULL, 0, NULL);
  234. if (retval == -1) {
  235. ast_log(LOG_ERROR, "[%d]: Error queing timer: %s\n",
  236. timer->handle, strerror(errno));
  237. }
  238. ao2_unlock(timer);
  239. return 0;
  240. }
  241. static int kqueue_timer_ack(void *data, unsigned int quantity)
  242. {
  243. static struct timespec ts_nowait = { 0, 0 };
  244. struct kqueue_timer *timer = data;
  245. struct kevent kev[2];
  246. int i, retval;
  247. ao2_lock(timer);
  248. retval = kevent(timer->handle, NULL, 0, kev, 2, &ts_nowait);
  249. if (retval == -1) {
  250. ast_log(LOG_ERROR, "[%d]: Error sampling kqueue: %s\n",
  251. timer->handle, strerror(errno));
  252. ao2_unlock(timer);
  253. return -1;
  254. }
  255. for (i = 0; i < retval; i++) {
  256. switch (kev[i].filter) {
  257. case EVFILT_TIMER:
  258. if (kev[i].data > quantity) {
  259. ast_log(LOG_ERROR, "[%d]: Missed %ju\n",
  260. timer->handle,
  261. (uintmax_t)kev[i].data - quantity);
  262. }
  263. break;
  264. case CONTINUOUS_EVFILT_TYPE:
  265. if (!timer->is_continuous) {
  266. ast_log(LOG_ERROR,
  267. "[%d]: Spurious user event\n",
  268. timer->handle);
  269. }
  270. break;
  271. default:
  272. ast_log(LOG_ERROR, "[%d]: Spurious kevent type %d.\n",
  273. timer->handle, kev[i].filter);
  274. }
  275. }
  276. ao2_unlock(timer);
  277. return 0;
  278. }
  279. static int kqueue_timer_enable_continuous(void *data)
  280. {
  281. struct kqueue_timer *timer = data;
  282. int retval;
  283. ao2_lock(timer);
  284. if (!timer->is_continuous) {
  285. ast_debug(5, "[%d]: Enable Continuous\n", timer->handle);
  286. retval = kqueue_timer_enable_continuous_event(timer);
  287. if (retval == -1) {
  288. ast_log(LOG_ERROR,
  289. "[%d]: Error signaling continuous event: %s\n",
  290. timer->handle, strerror(errno));
  291. }
  292. timer->is_continuous = 1;
  293. }
  294. ao2_unlock(timer);
  295. return 0;
  296. }
  297. static int kqueue_timer_disable_continuous(void *data)
  298. {
  299. struct kqueue_timer *timer = data;
  300. int retval;
  301. ao2_lock(timer);
  302. if (timer->is_continuous) {
  303. ast_debug(5, "[%d]: Disable Continuous\n", timer->handle);
  304. retval = kqueue_timer_disable_continuous_event(timer);
  305. if (retval == -1) {
  306. ast_log(LOG_ERROR,
  307. "[%d]: Error clearing continuous event: %s\n",
  308. timer->handle, strerror(errno));
  309. }
  310. timer->is_continuous = 0;
  311. }
  312. ao2_unlock(timer);
  313. return 0;
  314. }
  315. static enum ast_timer_event kqueue_timer_get_event(void *data)
  316. {
  317. struct kqueue_timer *timer = data;
  318. enum ast_timer_event res;
  319. if (timer->is_continuous) {
  320. res = AST_TIMING_EVENT_CONTINUOUS;
  321. } else {
  322. res = AST_TIMING_EVENT_EXPIRED;
  323. }
  324. return res;
  325. }
  326. static unsigned int kqueue_timer_get_max_rate(void *data)
  327. {
  328. return INTPTR_MAX > UINT_MAX ? UINT_MAX : INTPTR_MAX;
  329. }
  330. static int kqueue_timer_fd(void *data)
  331. {
  332. struct kqueue_timer *timer = data;
  333. return timer->handle;
  334. }
  335. #ifdef TEST_FRAMEWORK
  336. AST_TEST_DEFINE(test_kqueue_timing)
  337. {
  338. int res = AST_TEST_PASS, i;
  339. uint64_t diff;
  340. struct pollfd pfd = { 0, POLLIN, 0 };
  341. struct kqueue_timer *kt;
  342. struct timeval start;
  343. switch (cmd) {
  344. case TEST_INIT:
  345. info->name = "test_kqueue_timing";
  346. info->category = "/res/res_timing_kqueue/";
  347. info->summary = "Test KQueue timing interface";
  348. info->description = "Verify that the KQueue timing interface correctly generates timing events";
  349. return AST_TEST_NOT_RUN;
  350. case TEST_EXECUTE:
  351. break;
  352. }
  353. if (!(kt = kqueue_timer_open())) {
  354. ast_test_status_update(test, "Cannot open timer!\n");
  355. return AST_TEST_FAIL;
  356. }
  357. do {
  358. pfd.fd = kqueue_timer_fd(kt);
  359. if (kqueue_timer_set_rate(kt, 1000)) {
  360. ast_test_status_update(test, "Cannot set timer rate to 1000/s\n");
  361. res = AST_TEST_FAIL;
  362. break;
  363. }
  364. if (ast_poll(&pfd, 1, 1000) < 1) {
  365. ast_test_status_update(test, "Polling on a kqueue doesn't work\n");
  366. res = AST_TEST_FAIL;
  367. break;
  368. }
  369. if (pfd.revents != POLLIN) {
  370. ast_test_status_update(test, "poll() should have returned POLLIN, but instead returned %hd\n", pfd.revents);
  371. res = AST_TEST_FAIL;
  372. break;
  373. }
  374. if (kqueue_timer_get_event(kt) <= 0) {
  375. ast_test_status_update(test, "No events generated after a poll returned successfully?!!\n");
  376. res = AST_TEST_FAIL;
  377. break;
  378. }
  379. if (kqueue_timer_ack(kt, 1) != 0) {
  380. ast_test_status_update(test, "Acking event failed.\n");
  381. res = AST_TEST_FAIL;
  382. break;
  383. }
  384. kqueue_timer_enable_continuous(kt);
  385. start = ast_tvnow();
  386. for (i = 0; i < 100; i++) {
  387. if (ast_poll(&pfd, 1, 1000) < 1) {
  388. ast_test_status_update(test, "Polling on a kqueue doesn't work\n");
  389. res = AST_TEST_FAIL;
  390. break;
  391. }
  392. if (kqueue_timer_get_event(kt) <= 0) {
  393. ast_test_status_update(test, "No events generated in continuous mode after 1 microsecond?!!\n");
  394. res = AST_TEST_FAIL;
  395. break;
  396. }
  397. if (kqueue_timer_ack(kt, 1) != 0) {
  398. ast_test_status_update(test, "Acking event failed.\n");
  399. res = AST_TEST_FAIL;
  400. break;
  401. }
  402. }
  403. diff = ast_tvdiff_us(ast_tvnow(), start);
  404. ast_test_status_update(test, "diff is %llu\n", diff);
  405. } while (0);
  406. kqueue_timer_close(kt);
  407. return res;
  408. }
  409. #endif
  410. /*!
  411. * \brief Load the module
  412. *
  413. * Module loading including tests for configuration or dependencies.
  414. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
  415. * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
  416. * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
  417. * configuration file or other non-critical problem return
  418. * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
  419. */
  420. static int load_module(void)
  421. {
  422. if (!(timing_funcs_handle = ast_register_timing_interface(&kqueue_timing))) {
  423. return AST_MODULE_LOAD_DECLINE;
  424. }
  425. AST_TEST_REGISTER(test_kqueue_timing);
  426. return AST_MODULE_LOAD_SUCCESS;
  427. }
  428. static int unload_module(void)
  429. {
  430. AST_TEST_UNREGISTER(test_kqueue_timing);
  431. return ast_unregister_timing_interface(timing_funcs_handle);
  432. }
  433. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "KQueue Timing Interface",
  434. .support_level = AST_MODULE_SUPPORT_EXTENDED,
  435. .load = load_module,
  436. .unload = unload_module,
  437. .load_pri = AST_MODPRI_CHANNEL_DEPEND,
  438. );