workqueue_tc.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. /*
  2. * Copyright (c) 2006-2024, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-02-06 tyx first commit
  9. * 2024-12-31 rbb666 Adding Test Cases
  10. */
  11. #include "rtthread.h"
  12. #include "rtdevice.h"
  13. #include "utest.h"
  14. #ifdef RT_USING_DEVICE_IPC
  15. static rt_uint8_t get_test_thread_priority(rt_int8_t pos)
  16. {
  17. rt_int16_t priority;
  18. priority = RT_SCHED_PRIV(rt_thread_self()).init_priority;
  19. if (pos == 0)
  20. {
  21. return priority;
  22. }
  23. else
  24. {
  25. priority += pos;
  26. }
  27. if (priority < 0)
  28. {
  29. return 0;
  30. }
  31. else if (priority >= RT_THREAD_PRIORITY_MAX)
  32. {
  33. return RT_THREAD_PRIORITY_MAX - 1;
  34. }
  35. else
  36. {
  37. return (rt_uint8_t)priority;
  38. }
  39. }
  40. static void do_work_test_fun(struct rt_work *work, void *work_data)
  41. {
  42. *((int *)work_data) = 1;
  43. }
  44. static void do_work_test(void)
  45. {
  46. struct rt_workqueue *queue;
  47. rt_uint8_t curr_priority;
  48. struct rt_work work;
  49. volatile int work_flag = 0;
  50. rt_err_t err;
  51. /* 1 higher priority than the current test thread */
  52. curr_priority = get_test_thread_priority(-1);
  53. queue = rt_workqueue_create("test", 2048, curr_priority);
  54. if (queue == RT_NULL)
  55. {
  56. LOG_E("queue create failed, L:%d", __LINE__);
  57. return;
  58. }
  59. rt_work_init(&work, do_work_test_fun, (void *)&work_flag);
  60. err = rt_workqueue_submit_work(queue, &work, 0);
  61. uassert_int_equal(err, RT_EOK);
  62. /* Delay 5 ticks to ensure that the task has been executed */
  63. rt_thread_delay(5);
  64. uassert_int_equal(work_flag, 1);
  65. rt_thread_delay(100);
  66. rt_workqueue_destroy(queue);
  67. }
  68. static void do_delay_work_test_fun(struct rt_work *work, void *work_data)
  69. {
  70. *((rt_tick_t *)work_data) = rt_tick_get();
  71. }
  72. static void do_delay_work_test(void)
  73. {
  74. struct rt_workqueue *queue;
  75. rt_uint8_t curr_priority;
  76. struct rt_work work;
  77. volatile rt_tick_t work_start = 0;
  78. volatile rt_tick_t work_end = 0;
  79. rt_err_t err;
  80. /* 1 higher priority than the current test thread */
  81. curr_priority = get_test_thread_priority(-1);
  82. queue = rt_workqueue_create("test", 2048, curr_priority);
  83. if (queue == RT_NULL)
  84. {
  85. LOG_E("queue create failed, L:%d", __LINE__);
  86. return;
  87. }
  88. rt_work_init(&work, do_delay_work_test_fun, (void *)&work_end);
  89. work_start = rt_tick_get();
  90. /* Normal delayed work submission test */
  91. err = rt_workqueue_submit_work(queue, &work, 10);
  92. uassert_int_equal(err, RT_EOK);
  93. /* Ensure that the delayed work has been executed */
  94. rt_thread_delay(15);
  95. /* Check if the delayed task is executed after 10 ticks */
  96. if (work_end < work_start || work_end - work_start < 10)
  97. {
  98. uassert_false(1);
  99. }
  100. rt_thread_delay(100);
  101. rt_workqueue_destroy(queue);
  102. }
  103. static void cancle_work_test01_fun(struct rt_work *work, void *work_data)
  104. {
  105. *((int *)work_data) = 1;
  106. }
  107. static void cancle_work_test01(void)
  108. {
  109. struct rt_workqueue *queue;
  110. rt_uint8_t curr_priority;
  111. struct rt_work work;
  112. volatile int work_flag = 0;
  113. rt_err_t err;
  114. /* 1 lower priority than the current test thread */
  115. curr_priority = get_test_thread_priority(1);
  116. queue = rt_workqueue_create("test", 2048, curr_priority);
  117. if (queue == RT_NULL)
  118. {
  119. LOG_E("queue create failed, L:%d", __LINE__);
  120. return;
  121. }
  122. work_flag = 0;
  123. rt_work_init(&work, cancle_work_test01_fun, (void *)&work_flag);
  124. /* Cancel the work before it is executed */
  125. err = rt_workqueue_submit_work(queue, &work, 0);
  126. uassert_int_equal(err, RT_EOK);
  127. /* Cancel Now */
  128. err = rt_workqueue_cancel_work(queue, &work);
  129. uassert_int_equal(err, RT_EOK);
  130. rt_thread_delay(5);
  131. uassert_int_equal(work_flag, 0);
  132. rt_thread_delay(100);
  133. rt_workqueue_destroy(queue);
  134. }
  135. static void cancle_work_test02_fun(struct rt_work *work, void *work_data)
  136. {
  137. rt_thread_delay(10);
  138. }
  139. static void cancle_work_test02(void)
  140. {
  141. struct rt_workqueue *queue;
  142. rt_uint8_t curr_priority;
  143. struct rt_work work;
  144. rt_err_t err;
  145. /* 1 higher priority than the current test thread */
  146. curr_priority = get_test_thread_priority(-1);
  147. queue = rt_workqueue_create("test", 2048, curr_priority);
  148. if (queue == RT_NULL)
  149. {
  150. LOG_E("queue create failed, L:%d", __LINE__);
  151. return;
  152. }
  153. rt_work_init(&work, cancle_work_test02_fun, RT_NULL);
  154. /* Cancel the work while it is in progress */
  155. err = rt_workqueue_submit_work(queue, &work, 0);
  156. uassert_int_equal(err, RT_EOK);
  157. rt_thread_delay(5);
  158. err = rt_workqueue_cancel_work(queue, &work);
  159. uassert_int_equal(err, -RT_EBUSY);
  160. rt_thread_delay(100);
  161. rt_workqueue_destroy(queue);
  162. }
  163. static void cancle_work_test03_fun(struct rt_work *work, void *work_data)
  164. {
  165. rt_thread_delay(5);
  166. }
  167. static void cancle_work_test03(void)
  168. {
  169. struct rt_workqueue *queue;
  170. rt_uint8_t curr_priority;
  171. struct rt_work work;
  172. rt_err_t err;
  173. /* 1 lower priority than the current test thread */
  174. curr_priority = get_test_thread_priority(1);
  175. queue = rt_workqueue_create("test", 2048, curr_priority);
  176. if (queue == RT_NULL)
  177. {
  178. LOG_E("queue create failed, L:%d", __LINE__);
  179. return;
  180. }
  181. rt_work_init(&work, cancle_work_test03_fun, RT_NULL);
  182. /* Canceling a work after it has been executed */
  183. err = rt_workqueue_submit_work(queue, &work, 0);
  184. uassert_int_equal(err, RT_EOK);
  185. rt_thread_delay(10);
  186. err = rt_workqueue_cancel_work(queue, &work);
  187. uassert_int_equal(err, RT_EOK);
  188. rt_thread_delay(100);
  189. rt_workqueue_destroy(queue);
  190. }
  191. static void cancle_work_test04_fun(struct rt_work *work, void *work_data)
  192. {
  193. rt_thread_delay(10);
  194. *((int *)work_data) = 1;
  195. }
  196. static void cancle_work_test04(void)
  197. {
  198. struct rt_workqueue *queue;
  199. rt_uint8_t curr_priority;
  200. struct rt_work work;
  201. volatile int work_flag = 0;
  202. rt_err_t err;
  203. /* 1 lower priority than the current test thread */
  204. curr_priority = get_test_thread_priority(1);
  205. queue = rt_workqueue_create("test", 2048, curr_priority);
  206. if (queue == RT_NULL)
  207. {
  208. LOG_E("queue create failed, L:%d", __LINE__);
  209. return;
  210. }
  211. rt_work_init(&work, cancle_work_test04_fun, (void *)&work_flag);
  212. err = rt_workqueue_submit_work(queue, &work, 0);
  213. uassert_int_equal(err, RT_EOK);
  214. rt_thread_delay(5);
  215. /* Synchronized cancellation work */
  216. err = rt_workqueue_cancel_work_sync(queue, &work);
  217. uassert_int_equal(err, RT_EOK);
  218. uassert_int_equal(work_flag, 1);
  219. rt_thread_delay(100);
  220. rt_workqueue_destroy(queue);
  221. }
  222. static void cancle_delay_work_test01_fun(struct rt_work *work, void *work_data)
  223. {
  224. *((int *)work_data) = 1;
  225. }
  226. static void cancle_delay_work_test01(void)
  227. {
  228. struct rt_workqueue *queue;
  229. rt_uint8_t curr_priority;
  230. struct rt_work work;
  231. volatile int work_flag = 0;
  232. rt_err_t err;
  233. /* 1 lower priority than the current test thread */
  234. curr_priority = get_test_thread_priority(1);
  235. queue = rt_workqueue_create("test", 2048, curr_priority);
  236. if (queue == RT_NULL)
  237. {
  238. LOG_E("queue create failed, L:%d", __LINE__);
  239. return;
  240. }
  241. work_flag = 0;
  242. rt_work_init(&work, cancle_delay_work_test01_fun, (void *)&work_flag);
  243. err = rt_workqueue_submit_work(queue, &work, 20);
  244. uassert_int_equal(err, RT_EOK);
  245. rt_thread_delay(10);
  246. /* Cancel work */
  247. err = rt_workqueue_cancel_work(queue, &work);
  248. uassert_int_equal(err, RT_EOK);
  249. rt_thread_delay(15);
  250. uassert_int_equal(work_flag, 0);
  251. rt_thread_delay(100);
  252. rt_workqueue_destroy(queue);
  253. }
  254. static void repeat_work_test01_fun(struct rt_work *work, void *work_data)
  255. {
  256. *((int *)work_data) += 1;
  257. }
  258. static void repeat_work_test01(void)
  259. {
  260. struct rt_workqueue *queue;
  261. rt_uint8_t curr_priority;
  262. struct rt_work work;
  263. volatile int work_flag = 0;
  264. rt_err_t err;
  265. /* 1 lower priority than the current test thread */
  266. curr_priority = get_test_thread_priority(1);
  267. queue = rt_workqueue_create("test01", 2048, curr_priority);
  268. if (queue == RT_NULL)
  269. {
  270. LOG_E("queue create failed, L:%d", __LINE__);
  271. return;
  272. }
  273. work_flag = 0;
  274. rt_work_init(&work, repeat_work_test01_fun, (void *)&work_flag);
  275. /* Multiple submissions of the same work */
  276. err = rt_workqueue_submit_work(queue, &work, 0);
  277. uassert_int_equal(err, RT_EOK);
  278. /* The same work, before it is executed, can be submitted repeatedly and executed only once */
  279. err = rt_workqueue_submit_work(queue, &work, 0);
  280. if (err != RT_EOK)
  281. {
  282. LOG_E("L:%d err. %d", __LINE__, err);
  283. }
  284. rt_thread_delay(10);
  285. /* Check if it was executed only once */
  286. uassert_int_equal(work_flag, 1);
  287. rt_thread_delay(100);
  288. rt_workqueue_destroy(queue);
  289. }
  290. static void repeat_work_test02_fun(struct rt_work *work, void *work_data)
  291. {
  292. rt_thread_delay(10);
  293. *((int *)work_data) += 1;
  294. }
  295. static void repeat_work_test02(void)
  296. {
  297. struct rt_workqueue *queue;
  298. rt_uint8_t curr_priority;
  299. struct rt_work work;
  300. volatile int work_flag = 0;
  301. rt_err_t err;
  302. /* 1 priority higher than current test thread */
  303. curr_priority = get_test_thread_priority(-1);
  304. queue = rt_workqueue_create("test02", 2048, curr_priority);
  305. if (queue == RT_NULL)
  306. {
  307. LOG_E("queue create failed, L:%d", __LINE__);
  308. return;
  309. }
  310. rt_work_init(&work, repeat_work_test02_fun, (void *)&work_flag);
  311. /* Submit work with high queue priority that will be executed immediately */
  312. err = rt_workqueue_submit_work(queue, &work, 0);
  313. uassert_int_equal(err, RT_EOK);
  314. rt_thread_delay(5);
  315. /* Re-submission of work in progress */
  316. err = rt_workqueue_submit_work(queue, &work, 0);
  317. if (err != RT_EOK)
  318. {
  319. LOG_E("L:%d err. %d", __LINE__, err);
  320. }
  321. rt_thread_delay(10);
  322. uassert_int_equal(work_flag, 1);
  323. rt_thread_delay(10);
  324. uassert_int_equal(work_flag, 2);
  325. rt_workqueue_destroy(queue);
  326. }
  327. static struct rt_workqueue *queue_3;
  328. static void repeat_work_test03_fun(struct rt_work *work, void *work_data)
  329. {
  330. int *work_flag = (int *)work_data;
  331. (*work_flag) += 1;
  332. rt_kprintf("work_flag:%d\n", *work_flag);
  333. if (*work_flag < 20)
  334. {
  335. rt_workqueue_submit_work(queue_3, work, 0);
  336. }
  337. }
  338. static void repeat_work_test03(void)
  339. {
  340. rt_uint8_t curr_priority;
  341. struct rt_work work;
  342. volatile int work_flag = 0;
  343. rt_err_t err;
  344. /* 1 priority higher than current test thread */
  345. curr_priority = get_test_thread_priority(-1);
  346. queue_3 = rt_workqueue_create("test03", 2048, curr_priority);
  347. if (queue_3 == RT_NULL)
  348. {
  349. LOG_E("queue create failed, L:%d", __LINE__);
  350. return;
  351. }
  352. rt_work_init(&work, repeat_work_test03_fun, (void *)&work_flag);
  353. /* Submit work with high queue priority that will be executed immediately */
  354. err = rt_workqueue_submit_work(queue_3, &work, 0);
  355. uassert_int_equal(err, RT_EOK);
  356. /* Wait for the work to be executed 20 times with a timeout */
  357. err = rt_workqueue_cancel_work_sync(queue_3, &work);
  358. uassert_int_equal(err, RT_EOK);
  359. /* Check if the work was executed 20 times */
  360. uassert_int_equal(work_flag, 20);
  361. rt_workqueue_destroy(queue_3);
  362. }
  363. static void repeat_delay_work_test01_fun(struct rt_work *work, void *work_data)
  364. {
  365. *((int *)work_data) += 1;
  366. }
  367. static void repeat_delay_work_test01(void)
  368. {
  369. struct rt_workqueue *queue;
  370. rt_uint8_t curr_priority;
  371. struct rt_work work;
  372. volatile int work_flag = 0;
  373. rt_err_t err;
  374. /* 1 lower priority than the current test thread */
  375. curr_priority = get_test_thread_priority(1);
  376. queue = rt_workqueue_create("test", 2048, curr_priority);
  377. if (queue == RT_NULL)
  378. {
  379. LOG_E("queue create failed, L:%d", __LINE__);
  380. return;
  381. }
  382. work_flag = 0;
  383. rt_work_init(&work, repeat_delay_work_test01_fun, (void *)&work_flag);
  384. err = rt_workqueue_submit_work(queue, &work, 20);
  385. uassert_int_equal(err, RT_EOK);
  386. /* At this point the delayed work has not been executed */
  387. rt_thread_delay(10);
  388. /* Re-submission of time-delayed work */
  389. err = rt_workqueue_submit_work(queue, &work, 20);
  390. uassert_int_equal(err, RT_EOK);
  391. rt_thread_delay(15);
  392. uassert_int_equal(work_flag, 0);
  393. /* Waiting for delayed task execution */
  394. rt_thread_delay(15);
  395. uassert_int_equal(work_flag, 1);
  396. rt_thread_delay(100);
  397. rt_workqueue_destroy(queue);
  398. }
  399. static void repeat_delay_work_test02_fun(struct rt_work *work, void *work_data)
  400. {
  401. rt_thread_delay(10);
  402. *((int *)work_data) += 1;
  403. }
  404. static void repeat_delay_work_test02(void)
  405. {
  406. struct rt_workqueue *queue;
  407. rt_uint8_t curr_priority;
  408. struct rt_work work;
  409. volatile int work_flag = 0;
  410. rt_err_t err;
  411. /* 1 lower priority than the current test thread */
  412. curr_priority = get_test_thread_priority(1);
  413. queue = rt_workqueue_create("test", 2048, curr_priority);
  414. if (queue == RT_NULL)
  415. {
  416. LOG_E("queue create failed, L:%d", __LINE__);
  417. return;
  418. }
  419. work_flag = 0;
  420. rt_work_init(&work, repeat_delay_work_test02_fun, (void *)&work_flag);
  421. err = rt_workqueue_submit_work(queue, &work, 20);
  422. uassert_int_equal(err, RT_EOK);
  423. /* Waiting for delayed work execution */
  424. rt_thread_delay(25);
  425. err = rt_workqueue_submit_work(queue, &work, 20);
  426. uassert_int_equal(err, RT_EOK);
  427. /* Check if the delayed work has been run only once */
  428. rt_thread_delay(10);
  429. uassert_int_equal(work_flag, 1);
  430. rt_thread_delay(25);
  431. /* Check if the delayed work is executed twice */
  432. uassert_int_equal(work_flag, 2);
  433. rt_thread_delay(100);
  434. rt_workqueue_destroy(queue);
  435. }
  436. static void cancel_all_work_test_fun(struct rt_work *work, void *work_data)
  437. {
  438. *((int *)work_data) += 1;
  439. }
  440. static void cancel_all_work_test(void)
  441. {
  442. struct rt_workqueue *queue;
  443. rt_uint8_t curr_priority;
  444. struct rt_work work1;
  445. struct rt_work work2;
  446. struct rt_work work3;
  447. struct rt_work work4;
  448. volatile int work_flag = 0;
  449. rt_err_t err;
  450. curr_priority = get_test_thread_priority(1);
  451. queue = rt_workqueue_create("test", 2048, curr_priority);
  452. if (queue == RT_NULL)
  453. {
  454. LOG_E("queue create failed, L:%d", __LINE__);
  455. return;
  456. }
  457. work_flag = 0;
  458. rt_work_init(&work1, cancel_all_work_test_fun, (void *)&work_flag);
  459. rt_work_init(&work2, cancel_all_work_test_fun, (void *)&work_flag);
  460. rt_work_init(&work3, cancel_all_work_test_fun, (void *)&work_flag);
  461. rt_work_init(&work4, cancel_all_work_test_fun, (void *)&work_flag);
  462. err = rt_workqueue_submit_work(queue, &work1, 0);
  463. uassert_int_equal(err, RT_EOK);
  464. err = rt_workqueue_submit_work(queue, &work2, 0);
  465. uassert_int_equal(err, RT_EOK);
  466. err = rt_workqueue_submit_work(queue, &work3, 10);
  467. uassert_int_equal(err, RT_EOK);
  468. err = rt_workqueue_submit_work(queue, &work4, 10);
  469. uassert_int_equal(err, RT_EOK);
  470. err = rt_workqueue_cancel_all_work(queue);
  471. uassert_int_equal(err, RT_EOK);
  472. rt_thread_delay(20);
  473. uassert_int_equal(work_flag, 0);
  474. rt_thread_delay(100);
  475. rt_workqueue_destroy(queue);
  476. }
  477. static rt_err_t utest_tc_init(void)
  478. {
  479. return RT_EOK;
  480. }
  481. static rt_err_t utest_tc_cleanup(void)
  482. {
  483. return RT_EOK;
  484. }
  485. static void testcase(void)
  486. {
  487. /* General work queue test */
  488. UTEST_UNIT_RUN(do_work_test);
  489. /* Delayed work queue test */
  490. UTEST_UNIT_RUN(do_delay_work_test);
  491. /* Cancellation of work prior to implementation */
  492. UTEST_UNIT_RUN(cancle_work_test01);
  493. /* Cancellation of work during execution */
  494. UTEST_UNIT_RUN(cancle_work_test02);
  495. /* Cancellation of work after implementation */
  496. UTEST_UNIT_RUN(cancle_work_test03);
  497. /* Synchronized cancellation of work during execution */
  498. UTEST_UNIT_RUN(cancle_work_test04);
  499. /* Cancel delayed work before execution */
  500. UTEST_UNIT_RUN(cancle_delay_work_test01);
  501. /* Multiple submissions of the same work prior to implementation */
  502. UTEST_UNIT_RUN(repeat_work_test01);
  503. /* Multiple submissions of the same work during execution */
  504. UTEST_UNIT_RUN(repeat_work_test02);
  505. /* Submitting the same task multiple times in a mission */
  506. UTEST_UNIT_RUN(repeat_work_test03);
  507. /* Multiple submissions of the same delayed task before execution */
  508. UTEST_UNIT_RUN(repeat_delay_work_test01);
  509. /* Multiple submissions of the same delayed task during execution */
  510. UTEST_UNIT_RUN(repeat_delay_work_test02);
  511. /* Cancel all works */
  512. UTEST_UNIT_RUN(cancel_all_work_test);
  513. }
  514. UTEST_TC_EXPORT(testcase, "components.drivers.ipc.workqueue_tc", utest_tc_init, utest_tc_cleanup, 300);
  515. #endif