test_freertos_task_delete.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /*
  7. * Test backported deletion behavior by creating tasks of various affinities and
  8. * check if the task memory is freed immediately under the correct conditions.
  9. *
  10. * The behavior of vTaskDelete() results in the immediate freeing of task memory
  11. * and the immediate execution of deletion callbacks for tasks which are not
  12. * running, provided they are not pinned to the other core (due to FPU cleanup
  13. * requirements).
  14. *
  15. * If the condition is not met, freeing of task memory and execution of
  16. * deletion callbacks will still be carried out by the Idle Task.
  17. */
  18. #include <stdio.h>
  19. #include "freertos/FreeRTOS.h"
  20. #include "freertos/task.h"
  21. #include "freertos/semphr.h"
  22. #include "esp_heap_caps.h"
  23. #include "unity.h"
  24. #include "test_utils.h"
  25. #include "esp_rom_sys.h"
  26. #define NO_OF_TSKS 3
  27. #define DELAY_TICKS 2
  28. /* Caps of all memory which is allocated from when a task is created */
  29. #define HEAP_CAPS (portTcbMemoryCaps | portStackMemoryCaps)
  30. #define DELAY_US_ITERATIONS 1000
  31. static void tsk_self_del(void *param)
  32. {
  33. vTaskDelete(NULL); //Deleting self means deleting currently running task
  34. }
  35. static void tsk_extern_del(void *param)
  36. {
  37. vTaskDelay(portMAX_DELAY); //Await external deletion
  38. }
  39. static void tsk_self_del_us_delay(void *param)
  40. {
  41. uint32_t delay = (uint32_t)param;
  42. esp_rom_delay_us(delay);
  43. vTaskDelete(NULL);
  44. }
  45. TEST_CASE("FreeRTOS Delete Tasks", "[freertos]")
  46. {
  47. /* -------------- Test vTaskDelete() on currently running tasks ----------------*/
  48. uint32_t before_count = uxTaskGetNumberOfTasks();
  49. uint32_t before_heap = heap_caps_get_free_size(HEAP_CAPS);
  50. for(int i = 0; i < portNUM_PROCESSORS; i++){
  51. for(int j = 0; j < NO_OF_TSKS; j++){
  52. TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(tsk_self_del, "tsk_self", 1024, NULL, configMAX_PRIORITIES - 1, NULL, i));
  53. }
  54. }
  55. vTaskDelay(DELAY_TICKS); //Minimal delay to see if Idle task cleans up all tasks awaiting deletion in a single tick
  56. TEST_ASSERT_EQUAL(before_count, uxTaskGetNumberOfTasks());
  57. TEST_ASSERT_EQUAL(before_heap, heap_caps_get_free_size(HEAP_CAPS));
  58. /* ------------- Test vTaskDelete() on not currently running tasks ------------ */
  59. TaskHandle_t handles[NO_OF_TSKS];
  60. before_heap = heap_caps_get_free_size(HEAP_CAPS);
  61. //Create task pinned to the same core that will not run during task deletion
  62. for(int j = 0 ; j < NO_OF_TSKS; j++){
  63. TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(tsk_extern_del, "tsk_extern", 4096, NULL, configMAX_PRIORITIES - 1, &handles[j], xPortGetCoreID()));
  64. }
  65. TEST_ASSERT_NOT_EQUAL(before_heap, heap_caps_get_free_size(HEAP_CAPS)); //Check tasks have been created
  66. //Delete the tasks, memory should be freed immediately
  67. for(int j = 0; j < NO_OF_TSKS; j++){
  68. vTaskDelete(handles[j]);
  69. }
  70. TEST_ASSERT_EQUAL(before_heap, heap_caps_get_free_size(HEAP_CAPS));
  71. /* Test self deleting no affinity task is not removed by idle task of other core before context switch */
  72. for(int i = 0; i < DELAY_US_ITERATIONS; i+= 10){
  73. vTaskDelay(1); //Sync to next tick interrupt
  74. xTaskCreatePinnedToCore(tsk_self_del_us_delay, "delay", 1024, (void *)i, UNITY_FREERTOS_PRIORITY - 1, NULL, tskNO_AFFINITY);
  75. esp_rom_delay_us(10); //Busy wait to ensure no affinity task runs on opposite core
  76. }
  77. }
  78. typedef struct {
  79. SemaphoreHandle_t sem;
  80. volatile bool deleted; // Check the deleted task doesn't keep running after being deleted
  81. } tsk_blocks_param_t;
  82. /* Task blocks as often as possible
  83. (two or more of these can share the same semaphore and "juggle" it around)
  84. */
  85. static void tsk_blocks_frequently(void *param)
  86. {
  87. tsk_blocks_param_t *p = (tsk_blocks_param_t *)param;
  88. SemaphoreHandle_t sem = p->sem;
  89. srand(xTaskGetTickCount() ^ (int)xTaskGetCurrentTaskHandle());
  90. while (1) {
  91. assert(!p->deleted);
  92. esp_rom_delay_us(rand() % 10);
  93. assert(!p->deleted);
  94. xSemaphoreTake(sem, portMAX_DELAY);
  95. assert(!p->deleted);
  96. esp_rom_delay_us(rand() % 10);
  97. assert(!p->deleted);
  98. xSemaphoreGive(sem);
  99. }
  100. }
  101. TEST_CASE("FreeRTOS Delete Blocked Tasks", "[freertos]")
  102. {
  103. TaskHandle_t blocking_tasks[portNUM_PROCESSORS + 1]; // one per CPU, plus one unpinned task
  104. tsk_blocks_param_t params[portNUM_PROCESSORS + 1] = { 0 };
  105. unsigned before = heap_caps_get_free_size(MALLOC_CAP_8BIT);
  106. printf("Free memory at start %u\n", before);
  107. /* Any bugs will depend on relative timing of destroying the tasks, so create & delete many times.
  108. Stop early if it looks like some resources have not been properly cleaned up.
  109. (1000 iterations takes about 9 seconds on ESP32 dual core)
  110. */
  111. for(unsigned iter = 0; iter < 1000; iter++) {
  112. // Create everything
  113. SemaphoreHandle_t sem = xSemaphoreCreateMutex();
  114. for(unsigned i = 0; i < portNUM_PROCESSORS + 1; i++) {
  115. params[i].deleted = false;
  116. params[i].sem = sem;
  117. TEST_ASSERT_EQUAL(pdTRUE,
  118. xTaskCreatePinnedToCore(tsk_blocks_frequently, "tsk_block", 4096, &params[i],
  119. UNITY_FREERTOS_PRIORITY - 1, &blocking_tasks[i],
  120. i < portNUM_PROCESSORS ? i : tskNO_AFFINITY));
  121. }
  122. vTaskDelay(5); // Let the tasks juggle the mutex for a bit
  123. for(unsigned i = 0; i < portNUM_PROCESSORS + 1; i++) {
  124. vTaskDelete(blocking_tasks[i]);
  125. params[i].deleted = true;
  126. }
  127. vTaskDelay(4); // Yield to the idle task for cleanup
  128. vSemaphoreDelete(sem);
  129. // Check we haven't leaked resources yet
  130. TEST_ASSERT_GREATER_OR_EQUAL(before - 256, heap_caps_get_free_size(MALLOC_CAP_8BIT));
  131. }
  132. }