test_res_pjsip_scheduler.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2016, Fairview 5 Engineering, LLC
  5. *
  6. * George Joseph <george.joseph@fairview5.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. * \brief res_pjsip scheduler tests
  21. *
  22. * \author George Joseph <george.joseph@fairview5.com>
  23. *
  24. */
  25. /*** MODULEINFO
  26. <depend>TEST_FRAMEWORK</depend>
  27. <depend>pjproject</depend>
  28. <depend>res_pjsip</depend>
  29. <support_level>core</support_level>
  30. ***/
  31. #include "asterisk.h"
  32. ASTERISK_REGISTER_FILE()
  33. #include <pjsip.h>
  34. #include "asterisk/test.h"
  35. #include "asterisk/module.h"
  36. #include "asterisk/taskprocessor.h"
  37. #include "asterisk/res_pjsip.h"
  38. #include "asterisk/utils.h"
  39. #define CATEGORY "/res/res_pjsip/scheduler/"
  40. struct test_data {
  41. ast_mutex_t lock;
  42. ast_cond_t cond;
  43. pthread_t tid;
  44. struct timeval test_start;
  45. struct timeval task_start;
  46. struct timeval task_end;
  47. int is_servant;
  48. int interval;
  49. int sleep;
  50. int done;
  51. int no_clear_done;
  52. struct ast_test *test;
  53. };
  54. #define S2U(x) (long int)(x * 1000 * 1000)
  55. #define M2U(x) (long int)(x * 1000)
  56. static int task_1(void *data)
  57. {
  58. struct test_data *test = data;
  59. if (!test->no_clear_done) {
  60. test->done = 0;
  61. }
  62. test->task_start = ast_tvnow();
  63. test->tid = pthread_self();
  64. test->is_servant = ast_sip_thread_is_servant();
  65. usleep(M2U(test->sleep));
  66. test->task_end = ast_tvnow();
  67. ast_mutex_lock(&test->lock);
  68. test->done++;
  69. ast_mutex_unlock(&test->lock);
  70. ast_cond_signal(&test->cond);
  71. return test->interval;
  72. }
  73. static void data_cleanup(void *data)
  74. {
  75. struct test_data *test_data = data;
  76. ast_mutex_destroy(&test_data->lock);
  77. ast_cond_destroy(&test_data->cond);
  78. }
  79. #define waitfor(x) \
  80. { \
  81. ast_mutex_lock(&(x)->lock); \
  82. while (!(x)->done) { \
  83. ast_cond_wait(&(x)->cond, &(x)->lock); \
  84. } \
  85. (x)->done = 0; \
  86. ast_mutex_unlock(&(x)->lock); \
  87. }
  88. static int scheduler(struct ast_test *test, int serialized)
  89. {
  90. RAII_VAR(struct ast_taskprocessor *, tp1, NULL, ast_taskprocessor_unreference);
  91. RAII_VAR(struct test_data *, test_data1, ao2_alloc(sizeof(*test_data1), data_cleanup), ao2_cleanup);
  92. RAII_VAR(struct test_data *, test_data2, ao2_alloc(sizeof(*test_data2), data_cleanup), ao2_cleanup);
  93. RAII_VAR(struct ast_sip_sched_task *, task1, NULL, ao2_cleanup);
  94. RAII_VAR(struct ast_sip_sched_task *, task2, NULL, ao2_cleanup);
  95. int duration;
  96. int delay;
  97. struct timeval task1_start;
  98. ast_test_validate(test, test_data1 != NULL);
  99. ast_test_validate(test, test_data2 != NULL);
  100. test_data1->test = test;
  101. test_data1->test_start = ast_tvnow();
  102. test_data1->interval = 2000;
  103. test_data1->sleep = 1000;
  104. ast_mutex_init(&test_data1->lock);
  105. ast_cond_init(&test_data1->cond, NULL);
  106. test_data2->test = test;
  107. test_data2->test_start = ast_tvnow();
  108. test_data2->interval = 2000;
  109. test_data2->sleep = 1000;
  110. ast_mutex_init(&test_data2->lock);
  111. ast_cond_init(&test_data2->cond, NULL);
  112. if (serialized) {
  113. ast_test_status_update(test, "This test will take about %3.1f seconds\n",
  114. (test_data1->interval + test_data1->sleep + (MAX(test_data1->interval - test_data2->interval, 0)) + test_data2->sleep) / 1000.0);
  115. tp1 = ast_sip_create_serializer();
  116. ast_test_validate(test, (tp1 != NULL));
  117. } else {
  118. ast_test_status_update(test, "This test will take about %3.1f seconds\n",
  119. ((MAX(test_data1->interval, test_data2->interval) + MAX(test_data1->sleep, test_data2->sleep)) / 1000.0));
  120. }
  121. task1 = ast_sip_schedule_task(tp1, test_data1->interval, task_1, NULL, test_data1, AST_SIP_SCHED_TASK_FIXED);
  122. ast_test_validate(test, task1 != NULL);
  123. task2 = ast_sip_schedule_task(tp1, test_data2->interval, task_1, NULL, test_data2, AST_SIP_SCHED_TASK_FIXED);
  124. ast_test_validate(test, task2 != NULL);
  125. waitfor(test_data1);
  126. ast_sip_sched_task_cancel(task1);
  127. ast_test_validate(test, test_data1->is_servant);
  128. duration = ast_tvdiff_ms(test_data1->task_end, test_data1->test_start);
  129. ast_test_validate(test, (duration > ((test_data1->interval + test_data1->sleep) * 0.9))
  130. && (duration < ((test_data1->interval + test_data1->sleep) * 1.1)));
  131. ast_sip_sched_task_get_times(task1, NULL, &task1_start, NULL);
  132. delay = ast_tvdiff_ms(task1_start, test_data1->test_start);
  133. ast_test_validate(test, (delay > (test_data1->interval * 0.9)
  134. && (delay < (test_data1->interval * 1.1))));
  135. waitfor(test_data2);
  136. ast_sip_sched_task_cancel(task2);
  137. ast_test_validate(test, test_data2->is_servant);
  138. if (serialized) {
  139. ast_test_validate(test, test_data1->tid == test_data2->tid);
  140. ast_test_validate(test, ast_tvdiff_ms(test_data2->task_start, test_data1->task_end) >= 0);
  141. } else {
  142. ast_test_validate(test, test_data1->tid != test_data2->tid);
  143. }
  144. return AST_TEST_PASS;
  145. }
  146. AST_TEST_DEFINE(serialized_scheduler)
  147. {
  148. switch (cmd) {
  149. case TEST_INIT:
  150. info->name = __func__;
  151. info->category = CATEGORY;
  152. info->summary = "Test res_pjsip serialized scheduler";
  153. info->description = "Test res_pjsip serialized scheduler";
  154. return AST_TEST_NOT_RUN;
  155. case TEST_EXECUTE:
  156. break;
  157. }
  158. return scheduler(test, 1);
  159. }
  160. AST_TEST_DEFINE(unserialized_scheduler)
  161. {
  162. switch (cmd) {
  163. case TEST_INIT:
  164. info->name = __func__;
  165. info->category = CATEGORY;
  166. info->summary = "Test res_pjsip unserialized scheduler";
  167. info->description = "Test res_pjsip unserialized scheduler";
  168. return AST_TEST_NOT_RUN;
  169. case TEST_EXECUTE:
  170. break;
  171. }
  172. return scheduler(test, 0);
  173. }
  174. static int run_count;
  175. static int destruct_count;
  176. static int dummy_task(void *data)
  177. {
  178. int *sleep = data;
  179. usleep(M2U(*sleep));
  180. run_count++;
  181. return 0;
  182. }
  183. static void test_destructor(void *data)
  184. {
  185. destruct_count++;
  186. }
  187. AST_TEST_DEFINE(scheduler_cleanup)
  188. {
  189. RAII_VAR(int *, sleep, NULL, ao2_cleanup);
  190. RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup);
  191. int interval;
  192. int when;
  193. switch (cmd) {
  194. case TEST_INIT:
  195. info->name = __func__;
  196. info->category = CATEGORY;
  197. info->summary = "Test res_pjsip scheduler cleanup";
  198. info->description = "Test res_pjsip scheduler cleanup";
  199. return AST_TEST_NOT_RUN;
  200. case TEST_EXECUTE:
  201. break;
  202. }
  203. destruct_count = 0;
  204. interval = 1000;
  205. sleep = ao2_alloc(sizeof(*sleep), test_destructor);
  206. ast_test_validate(test, sleep != NULL);
  207. *sleep = 500;
  208. ast_test_status_update(test, "This test will take about %3.1f seconds\n",
  209. ((interval * 1.1) + *sleep) / 1000.0);
  210. task = ast_sip_schedule_task(NULL, interval, dummy_task, "dummy", sleep,
  211. AST_SIP_SCHED_TASK_DATA_AO2 | AST_SIP_SCHED_TASK_DATA_FREE);
  212. ast_test_validate(test, task != NULL);
  213. usleep(M2U(interval * 0.5));
  214. when = ast_sip_sched_task_get_next_run(task);
  215. ast_test_validate(test, (when > (interval * 0.4) && when < (interval * 0.6)));
  216. usleep(M2U(interval * 0.6));
  217. ast_test_validate(test, ast_sip_sched_is_task_running(task));
  218. usleep(M2U(*sleep));
  219. ast_test_validate(test, (ast_sip_sched_is_task_running(task) == 0));
  220. when = ast_sip_sched_task_get_next_run(task);
  221. ast_test_validate(test, (when < 0), res, error);
  222. ast_test_validate(test, (ao2_ref(task, 0) == 1));
  223. ao2_ref(task, -1);
  224. task = NULL;
  225. ast_test_validate(test, (destruct_count == 1));
  226. sleep = NULL;
  227. return AST_TEST_PASS;
  228. }
  229. AST_TEST_DEFINE(scheduler_cancel)
  230. {
  231. RAII_VAR(int *, sleep, NULL, ao2_cleanup);
  232. RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup);
  233. int interval;
  234. int when;
  235. switch (cmd) {
  236. case TEST_INIT:
  237. info->name = __func__;
  238. info->category = CATEGORY;
  239. info->summary = "Test res_pjsip scheduler cancel task";
  240. info->description = "Test res_pjsip scheduler cancel task";
  241. return AST_TEST_NOT_RUN;
  242. case TEST_EXECUTE:
  243. break;
  244. }
  245. destruct_count = 0;
  246. interval = 1000;
  247. sleep = ao2_alloc(sizeof(*sleep), test_destructor);
  248. ast_test_validate(test, sleep != NULL);
  249. *sleep = 500;
  250. ast_test_status_update(test, "This test will take about %3.1f seconds\n",
  251. (interval + *sleep) / 1000.0);
  252. task = ast_sip_schedule_task(NULL, interval, dummy_task, "dummy", sleep, AST_SIP_SCHED_TASK_DATA_NO_CLEANUP);
  253. ast_test_validate(test, task != NULL);
  254. usleep(M2U(interval * 0.5));
  255. when = ast_sip_sched_task_get_next_run_by_name("dummy");
  256. ast_test_validate(test, (when > (interval * 0.4) && when < (interval * 0.6)));
  257. ast_test_validate(test, !ast_sip_sched_is_task_running_by_name("dummy"));
  258. ast_test_validate(test, ao2_ref(task, 0) == 2);
  259. ast_sip_sched_task_cancel_by_name("dummy");
  260. when = ast_sip_sched_task_get_next_run(task);
  261. ast_test_validate(test, when < 0);
  262. usleep(M2U(interval));
  263. ast_test_validate(test, run_count == 0);
  264. ast_test_validate(test, destruct_count == 0);
  265. ast_test_validate(test, ao2_ref(task, 0) == 1);
  266. return AST_TEST_PASS;
  267. }
  268. AST_TEST_DEFINE(scheduler_policy)
  269. {
  270. RAII_VAR(struct test_data *, test_data1, ao2_alloc(sizeof(*test_data1), data_cleanup), ao2_cleanup);
  271. RAII_VAR(struct ast_sip_sched_task *, task, NULL, ao2_cleanup);
  272. int when;
  273. switch (cmd) {
  274. case TEST_INIT:
  275. info->name = __func__;
  276. info->category = CATEGORY;
  277. info->summary = "Test res_pjsip scheduler cancel task";
  278. info->description = "Test res_pjsip scheduler cancel task";
  279. return AST_TEST_NOT_RUN;
  280. case TEST_EXECUTE:
  281. break;
  282. }
  283. ast_test_validate(test, test_data1 != NULL);
  284. destruct_count = 0;
  285. run_count = 0;
  286. test_data1->test = test;
  287. test_data1->test_start = ast_tvnow();
  288. test_data1->interval = 1000;
  289. test_data1->sleep = 500;
  290. test_data1->no_clear_done = 1;
  291. ast_mutex_init(&test_data1->lock);
  292. ast_cond_init(&test_data1->cond, NULL);
  293. ast_test_status_update(test, "This test will take about %3.1f seconds\n",
  294. ((test_data1->interval * 4) + test_data1->sleep) / 1000.0);
  295. task = ast_sip_schedule_task(NULL, test_data1->interval, task_1, "test_1", test_data1,
  296. AST_SIP_SCHED_TASK_DATA_NO_CLEANUP | AST_SIP_SCHED_TASK_PERIODIC);
  297. ast_test_validate(test, task != NULL);
  298. waitfor(test_data1);
  299. when = ast_tvdiff_ms(test_data1->task_start, test_data1->test_start);
  300. ast_test_validate(test, when > test_data1->interval * 0.9 && when < test_data1->interval * 1.1);
  301. waitfor(test_data1);
  302. when = ast_tvdiff_ms(test_data1->task_start, test_data1->test_start);
  303. ast_test_validate(test, when > test_data1->interval * 2 * 0.9 && when < test_data1->interval * 2 * 1.1);
  304. waitfor(test_data1);
  305. when = ast_tvdiff_ms(test_data1->task_start, test_data1->test_start);
  306. ast_test_validate(test, when > test_data1->interval * 3 * 0.9 && when < test_data1->interval * 3 * 1.1);
  307. ast_sip_sched_task_cancel(task);
  308. /* Wait a full interval in case a 4th call to test_1 happened before the cancel */
  309. usleep(M2U(test_data1->interval));
  310. ast_mutex_lock(&test_data1->lock);
  311. if (test_data1->done) {
  312. int done = test_data1->done;
  313. test_data1->done = 0;
  314. ast_mutex_unlock(&test_data1->lock);
  315. ast_test_validate(test, done == 1);
  316. /* Wait two full intervals to be certain no further calls to test_1. */
  317. usleep(M2U(test_data1->interval * 2));
  318. ast_mutex_lock(&test_data1->lock);
  319. if (test_data1->done != 0) {
  320. ast_mutex_unlock(&test_data1->lock);
  321. /* The cancelation failed so we need to prevent cleanup of
  322. * test_data1 to prevent a crash from write-after-free. */
  323. test_data1 = NULL;
  324. ast_test_status_update(test, "Failed to cancel task");
  325. return AST_TEST_FAIL;
  326. }
  327. }
  328. ast_mutex_unlock(&test_data1->lock);
  329. return AST_TEST_PASS;
  330. }
  331. static int load_module(void)
  332. {
  333. CHECK_PJSIP_MODULE_LOADED();
  334. AST_TEST_REGISTER(serialized_scheduler);
  335. AST_TEST_REGISTER(unserialized_scheduler);
  336. AST_TEST_REGISTER(scheduler_cleanup);
  337. AST_TEST_REGISTER(scheduler_cancel);
  338. AST_TEST_REGISTER(scheduler_policy);
  339. return AST_MODULE_LOAD_SUCCESS;
  340. }
  341. static int unload_module(void)
  342. {
  343. AST_TEST_UNREGISTER(scheduler_cancel);
  344. AST_TEST_UNREGISTER(scheduler_cleanup);
  345. AST_TEST_UNREGISTER(unserialized_scheduler);
  346. AST_TEST_UNREGISTER(serialized_scheduler);
  347. AST_TEST_UNREGISTER(scheduler_policy);
  348. return 0;
  349. }
  350. AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "res_pjsip scheduler test module");