test_queuesets.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include "freertos/FreeRTOS.h"
  9. #include "freertos/task.h"
  10. #include "freertos/queue.h"
  11. #include "freertos/semphr.h"
  12. #include "freertos/idf_additions.h"
  13. #include "unity.h"
  14. #include "test_utils.h"
  15. #define QUEUE_LEN 4
  16. static void allocate_resources(int num_queues, int queue_len, QueueHandle_t *queue_list_ret, QueueSetHandle_t *queue_set_ret)
  17. {
  18. // Create queue set
  19. *queue_set_ret = xQueueCreateSet(num_queues * queue_len);
  20. TEST_ASSERT_NOT_EQUAL(NULL, *queue_set_ret);
  21. // Create queues and add them to the queue set
  22. for (int i = 0; i < num_queues; i++) {
  23. queue_list_ret[i] = xQueueCreate(queue_len, sizeof(BaseType_t));
  24. TEST_ASSERT_NOT_EQUAL(NULL, queue_list_ret[i]);
  25. TEST_ASSERT_EQUAL(pdPASS, xQueueAddToSet(queue_list_ret[i], *queue_set_ret));
  26. }
  27. }
  28. static void free_resources(int num_queues, QueueHandle_t *queue_list, QueueSetHandle_t queue_set)
  29. {
  30. // Remove queues form queue set and delete the queues
  31. for (int i = 0; i < num_queues; i++) {
  32. TEST_ASSERT_EQUAL(pdPASS, xQueueRemoveFromSet(queue_list[i], queue_set));
  33. vQueueDelete(queue_list[i]);
  34. }
  35. vQueueDelete(queue_set);
  36. }
  37. /*
  38. Test queue sets basic
  39. Purpose:
  40. - Test that queue set works as expected
  41. Procedure:
  42. - Create NUM_QUEUES queues and add them to the same queue set
  43. - Fill each queue sequentially with QUEUE_LEN items
  44. Expected:
  45. - Each call to xQueueSend() should generate a member in the queue set
  46. - The order of the members should match the order in which xQueueSend() was called
  47. - The item sent by the xQueueSend() is correct when read
  48. */
  49. #define NUM_QUEUES 5
  50. TEST_CASE("Test Queue sets", "[freertos]")
  51. {
  52. // Create queues and queue set
  53. QueueHandle_t queues[NUM_QUEUES];
  54. QueueSetHandle_t queue_set;
  55. allocate_resources(NUM_QUEUES, QUEUE_LEN, queues, &queue_set);
  56. // Fill each queue sequentially with QUEUE_LEN items
  57. for (int i = 0; i < NUM_QUEUES; i++) {
  58. for (int j = 0; j < QUEUE_LEN; j++) {
  59. BaseType_t item = j;
  60. TEST_ASSERT_EQUAL(pdTRUE, xQueueSend(queues[i], &item, 0));
  61. }
  62. }
  63. for (int i = 0; i < NUM_QUEUES; i++) {
  64. for (int j = 0; j < QUEUE_LEN; j++) {
  65. // Check the queue set member
  66. QueueSetMemberHandle_t member = xQueueSelectFromSet(queue_set, 0);
  67. TEST_ASSERT_EQUAL(queues[i], member);
  68. // Check the queue's items
  69. BaseType_t item;
  70. TEST_ASSERT_EQUAL(pdTRUE, xQueueReceive(member, &item, 0));
  71. TEST_ASSERT_EQUAL(j, item);
  72. }
  73. }
  74. // Check that there are no more members
  75. TEST_ASSERT_EQUAL(NULL, xQueueSelectFromSet(queue_set, 0));
  76. // Cleanup queues and queue set
  77. free_resources(NUM_QUEUES, queues, queue_set);
  78. }
  79. #ifndef CONFIG_FREERTOS_UNICORE
  80. /*
  81. Test queue set SMP thread safety
  82. Purpose:
  83. - Test that queue set works when being used from different cores simultaneously
  84. Procedure:
  85. - Create a queue for each core and add them to the same queue set
  86. - Create a task on each core to send QUEUE_LEN items to their assigned queue
  87. - Synchronize the tasks so that the start sending at the same time
  88. Expected:
  89. - Each call to xQueueSend() should generate a member in the queue set
  90. - The item sent by the xQueueSend() is correct when read
  91. */
  92. static volatile bool start_other_cores;
  93. static SemaphoreHandle_t done_sem = NULL;
  94. static void send_func(void *arg)
  95. {
  96. QueueHandle_t queue = (QueueHandle_t)arg;
  97. BaseType_t core_id = xPortGetCoreID();
  98. if (core_id == 0) {
  99. // We are core 0. Trigger the other cores to start
  100. start_other_cores = true;
  101. } else {
  102. // Wait to be started by main core
  103. while (!start_other_cores) {
  104. ;
  105. }
  106. }
  107. // Fill the queue assigned to the current core
  108. for (int i = 0; i < QUEUE_LEN; i++) {
  109. TEST_ASSERT_EQUAL(pdTRUE, xQueueSend(queue, &core_id, 0));
  110. }
  111. if (core_id != 0) {
  112. // Indicate completion to core 0 and self delete
  113. xSemaphoreGive(done_sem);
  114. vTaskDelete(NULL);
  115. }
  116. }
  117. TEST_CASE("Test queue sets multi-core", "[freertos]")
  118. {
  119. // Create done semaphore
  120. done_sem = xSemaphoreCreateCounting(portNUM_PROCESSORS - 1, 0);
  121. TEST_ASSERT_NOT_EQUAL(NULL, done_sem);
  122. // Create queues and queue set
  123. QueueHandle_t queues[portNUM_PROCESSORS];
  124. QueueSetHandle_t queue_set;
  125. allocate_resources(portNUM_PROCESSORS, QUEUE_LEN, queues, &queue_set);
  126. // Create tasks of the same priority for all cores except for core 0
  127. for (int i = 1; i < portNUM_PROCESSORS; i++) {
  128. TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(send_func, "send", 2048, (void *)queues[i], UNITY_FREERTOS_PRIORITY, NULL, i));
  129. }
  130. // Core 0 calls send_func as well triggering the simultaneous sends from all cores
  131. send_func((void *)queues[0]);
  132. // Wait for all other cores to be done
  133. for (int i = 1; i < portNUM_PROCESSORS; i++) {
  134. xSemaphoreTake(done_sem, portMAX_DELAY);
  135. }
  136. // Read queues from the queue set, then read an item from the queue
  137. uint32_t queues_check_count[portNUM_PROCESSORS] = {0};
  138. QueueSetMemberHandle_t member = xQueueSelectFromSet(queue_set, 0);
  139. while (member != NULL) {
  140. // Read the core ID from the queue, check that core ID is sane
  141. BaseType_t core_id;
  142. TEST_ASSERT_EQUAL(pdTRUE, xQueueReceive(member, &core_id, 0));
  143. TEST_ASSERT_LESS_THAN(portNUM_PROCESSORS, core_id);
  144. queues_check_count[core_id]++;
  145. // Get next member
  146. member = xQueueSelectFromSet(queue_set, 0);
  147. }
  148. // Check that all items from all queues have been read
  149. for (int i = 0; i < portNUM_PROCESSORS; i++) {
  150. TEST_ASSERT_EQUAL(QUEUE_LEN, queues_check_count[i]);
  151. }
  152. // Cleanup queues and queue set
  153. free_resources(portNUM_PROCESSORS, queues, queue_set);
  154. // Cleanup done sem
  155. vSemaphoreDelete(done_sem);
  156. done_sem = NULL;
  157. }
  158. #endif // CONFIG_FREERTOS_UNICORE