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