condvar_broadcast_tc.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-11-20 Shell add test suites
  9. * 2026-03-19 cl2t Add standardized utest documentation block
  10. */
  11. /**
  12. * Test Case Name: Condition Variable Broadcast Test
  13. *
  14. * Test Objectives:
  15. * - Verify that rt_condvar_broadcast() correctly wakes up all threads
  16. * waiting on a condition variable.
  17. * - Test core APIs: rt_condvar_broadcast(), rt_condvar_timedwait(),
  18. * rt_mutex_take(), rt_mutex_release(), rt_mutex_get_owner().
  19. *
  20. * Test Scenarios:
  21. * - Creates 8 worker threads, each acquiring a mutex and then waiting on
  22. * a condition variable via rt_condvar_timedwait().
  23. * - The main thread calls rt_condvar_broadcast() to wake all waiters.
  24. * - Each woken thread verifies it re-acquired the mutex, increments a
  25. * counter, and releases the mutex.
  26. * - The main thread verifies all 8 threads were successfully woken.
  27. *
  28. * Verification Metrics:
  29. * - All waiting threads must be woken after broadcast (waken_num == THREAD_NUM).
  30. * - Each woken thread must hold the mutex (verified via rt_mutex_get_owner()).
  31. * - rt_condvar_timedwait() must return 0 on successful wake.
  32. * - Mutex release must succeed for each woken thread.
  33. *
  34. * Dependencies:
  35. * - Software configuration: RT_USING_SMART must be enabled.
  36. * - Environmental assumptions: The platform must support multi-threading
  37. * with at least 8 concurrent threads.
  38. *
  39. * Expected Results:
  40. * - Final output: "[ PASSED ] [ result ] testcase (testcases.ipc.condvar.broadcast)"
  41. * - No assertion failures during test execution.
  42. */
  43. #include "common.h"
  44. #include "rtconfig.h"
  45. #include "utest_assert.h"
  46. #include <rtdevice.h>
  47. #include <rtdef.h>
  48. static struct rt_mutex _local_mtx;
  49. static struct rt_condvar _local_cv;
  50. #define THREAD_NUM 8
  51. #define STACK_SIZE (0x2000)
  52. static volatile int start_num;
  53. static volatile int waken_num;
  54. static void thr_func(void *arg)
  55. {
  56. int rc;
  57. rt_mutex_t mutex = &_local_mtx;
  58. rt_condvar_t cond = &_local_cv;
  59. rt_mutex_take(mutex, RT_WAITING_FOREVER);
  60. start_num++;
  61. rc = rt_condvar_timedwait(cond, mutex, RT_KILLABLE, RT_WAITING_FOREVER);
  62. if (rc != 0)
  63. {
  64. LOG_E("cond_wait returned %d\n", rc);
  65. uassert_false(1);
  66. return;
  67. }
  68. if (rt_mutex_get_owner(mutex) != rt_thread_self())
  69. {
  70. LOG_E("Should not be able to lock the mutex again");
  71. uassert_false(1);
  72. return;
  73. }
  74. else
  75. {
  76. uassert_true(1);
  77. }
  78. LOG_I("Thread was wakened and acquired the mutex again");
  79. waken_num++;
  80. if (rt_mutex_release(mutex) != 0)
  81. {
  82. LOG_E("Failed to release the mutex");
  83. uassert_false(1);
  84. return;
  85. }
  86. else
  87. {
  88. uassert_true(1);
  89. }
  90. return ;
  91. }
  92. static void *stack_addr[THREAD_NUM];
  93. static void condvar_broadcast_tc(void)
  94. {
  95. rt_mutex_t mutex = &_local_mtx;
  96. rt_condvar_t cond = &_local_cv;
  97. struct rt_thread thread[THREAD_NUM];
  98. for (size_t i = 0; i < THREAD_NUM; i++)
  99. {
  100. if (rt_thread_init(&thread[i], "utest", thr_func, RT_NULL,
  101. stack_addr[i], STACK_SIZE, 25, 100) != 0)
  102. {
  103. LOG_E("Fail to create thread[%d]\n", i);
  104. return;
  105. }
  106. rt_thread_startup(&thread[i]);
  107. }
  108. while (start_num < THREAD_NUM)
  109. rt_thread_mdelay(1);
  110. rt_mutex_take(mutex, RT_WAITING_FOREVER);
  111. if (rt_condvar_broadcast(cond))
  112. {
  113. uassert_false(1);
  114. return ;
  115. }
  116. rt_mutex_release(mutex);
  117. rt_thread_mdelay(1);
  118. if (waken_num < THREAD_NUM)
  119. {
  120. LOG_E("[Main thread] Not all waiters were wakened\n");
  121. uassert_false(1);
  122. return ;
  123. }
  124. else
  125. {
  126. utest_int_equal(waken_num, THREAD_NUM);
  127. }
  128. LOG_I("[Main thread] all waiters were wakened\n");
  129. return;
  130. }
  131. static rt_err_t utest_tc_init(void)
  132. {
  133. start_num = 0;
  134. waken_num = 0;
  135. if (rt_mutex_init(&_local_mtx, "utest", RT_IPC_FLAG_PRIO) != 0)
  136. {
  137. perror("pthread_mutex_init() error");
  138. uassert_false(1);
  139. return -1;
  140. }
  141. rt_condvar_init(&_local_cv, NULL);
  142. for (size_t i = 0; i < THREAD_NUM; i++)
  143. {
  144. stack_addr[i] =
  145. rt_pages_alloc_ext(rt_page_bits(STACK_SIZE), PAGE_ANY_AVAILABLE);
  146. utest_int_not_equal(stack_addr[i], RT_NULL);
  147. }
  148. return RT_EOK;
  149. }
  150. static rt_err_t utest_tc_cleanup(void)
  151. {
  152. rt_mutex_detach(&_local_mtx);
  153. rt_condvar_detach(&_local_cv);
  154. for (size_t i = 0; i < THREAD_NUM; i++)
  155. {
  156. rt_pages_free(stack_addr[i], rt_page_bits(STACK_SIZE));
  157. stack_addr[i] = 0;
  158. }
  159. return RT_EOK;
  160. }
  161. static void testcase(void)
  162. {
  163. UTEST_UNIT_RUN(condvar_broadcast_tc);
  164. }
  165. UTEST_TC_EXPORT(testcase, "testcases.ipc.condvar.broadcast", utest_tc_init,
  166. utest_tc_cleanup, 10);