test_freertos_task_delete.c 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. /*
  2. * Test backported deletion behavior by creating tasks of various affinities and
  3. * check if the task memory is freed immediately under the correct conditions.
  4. *
  5. * The behavior of vTaskDelete() has been backported form FreeRTOS v9.0.0. This
  6. * results in the immediate freeing of task memory and the immediate execution
  7. * of deletion callbacks under the following conditions...
  8. * - When deleting a task that is not currently running on either core
  9. * - When deleting a task that is pinned to the same core (with respect to
  10. * the core that calls vTaskDelete()
  11. *
  12. * If the two conditions are not met, freeing of task memory and execution of
  13. * deletion callbacks will still be carried out by the Idle Task.
  14. */
  15. #include <stdio.h>
  16. #include "freertos/FreeRTOS.h"
  17. #include "freertos/task.h"
  18. #include "esp_heap_caps.h"
  19. #include "rom/ets_sys.h"
  20. #include "unity.h"
  21. #include "test_utils.h"
  22. #define NO_OF_TSKS 3
  23. #define DELAY_TICKS 2
  24. /* Caps of all memory which is allocated from when a task is created */
  25. #define HEAP_CAPS (portTcbMemoryCaps | portStackMemoryCaps)
  26. #define DELAY_US_ITERATIONS 1000
  27. static void tsk_self_del(void *param)
  28. {
  29. vTaskDelete(NULL); //Deleting self means deleting currently running task
  30. }
  31. static void tsk_extern_del(void *param)
  32. {
  33. vTaskDelay(portMAX_DELAY); //Await external deletion
  34. }
  35. static void tsk_self_del_us_delay(void *param)
  36. {
  37. uint32_t delay = (uint32_t)param;
  38. ets_delay_us(delay);
  39. vTaskDelete(NULL);
  40. }
  41. TEST_CASE("FreeRTOS Delete Tasks", "[freertos]")
  42. {
  43. /* -------------- Test vTaskDelete() on currently running tasks ----------------*/
  44. uint32_t before_count = uxTaskGetNumberOfTasks();
  45. uint32_t before_heap = heap_caps_get_free_size(HEAP_CAPS);
  46. for(int i = 0; i < portNUM_PROCESSORS; i++){
  47. for(int j = 0; j < NO_OF_TSKS; j++){
  48. TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(tsk_self_del, "tsk_self", 1024, NULL, configMAX_PRIORITIES - 1, NULL, i));
  49. }
  50. }
  51. vTaskDelay(DELAY_TICKS); //Minimal delay to see if Idle task cleans up all tasks awaiting deletion in a single tick
  52. TEST_ASSERT_EQUAL(before_count, uxTaskGetNumberOfTasks());
  53. TEST_ASSERT_EQUAL(before_heap, heap_caps_get_free_size(HEAP_CAPS));
  54. /* ------------- Test vTaskDelete() on not currently running tasks ------------ */
  55. TaskHandle_t handles[NO_OF_TSKS];
  56. before_heap = heap_caps_get_free_size(HEAP_CAPS);
  57. //Create task pinned to the same core that will not run during task deletion
  58. for(int j = 0 ; j < NO_OF_TSKS; j++){
  59. TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(tsk_extern_del, "tsk_extern", 4096, NULL, configMAX_PRIORITIES - 1, &handles[j], xPortGetCoreID()));
  60. }
  61. TEST_ASSERT_NOT_EQUAL(before_heap, heap_caps_get_free_size(HEAP_CAPS)); //Check tasks have been created
  62. //Delete the tasks, memory should be freed immediately
  63. for(int j = 0; j < NO_OF_TSKS; j++){
  64. vTaskDelete(handles[j]);
  65. }
  66. TEST_ASSERT_EQUAL(before_heap, heap_caps_get_free_size(HEAP_CAPS));
  67. /* Test self deleting no affinity task is not removed by idle task of other core before context switch */
  68. for(int i = 0; i < DELAY_US_ITERATIONS; i+= 10){
  69. vTaskDelay(1); //Sync to next tick interrupt
  70. xTaskCreatePinnedToCore(tsk_self_del_us_delay, "delay", 1024, (void *)i, UNITY_FREERTOS_PRIORITY - 1, NULL, tskNO_AFFINITY);
  71. ets_delay_us(10); //Busy wait to ensure no affinity task runs on opposite core
  72. }
  73. }