From 7834519af893d1335afbba1f95cfade7308ef33b Mon Sep 17 00:00:00 2001 From: Jakob Hasse Date: Tue, 3 Sep 2024 12:57:03 +0200 Subject: [PATCH] refactor(pthread): added esp_pthread unit tests for linux target --- components/pthread/port/linux/pthread.c | 4 +- .../pthread/test_apps/.build-test-rules.yml | 4 + .../test_apps/pthread_unity_tests/README.md | 4 +- .../pthread_unity_tests/main/CMakeLists.txt | 23 +++-- .../pthread_unity_tests/main/test_app_main.c | 27 ++---- .../main/test_esp_pthread.c | 89 +++++++++++++++++++ .../pthread_unity_tests/main/test_pthread.c | 27 ------ .../pytest_pthread_unity_tests.py | 6 ++ 8 files changed, 127 insertions(+), 57 deletions(-) create mode 100644 components/pthread/test_apps/pthread_unity_tests/main/test_esp_pthread.c diff --git a/components/pthread/port/linux/pthread.c b/components/pthread/port/linux/pthread.c index 69fdcf86dc..107733e02e 100644 --- a/components/pthread/port/linux/pthread.c +++ b/components/pthread/port/linux/pthread.c @@ -7,12 +7,12 @@ * pthread port for Linux build */ +#include +#include #include "sdkconfig.h" #include "esp_pthread.h" #include "esp_heap_caps.h" -#include - #include #include "freertos/FreeRTOS.h" diff --git a/components/pthread/test_apps/.build-test-rules.yml b/components/pthread/test_apps/.build-test-rules.yml index 2856cec83b..2c28a098c3 100644 --- a/components/pthread/test_apps/.build-test-rules.yml +++ b/components/pthread/test_apps/.build-test-rules.yml @@ -4,3 +4,7 @@ components/pthread/test_apps/pthread_psram_tests: enable: - if: IDF_TARGET in ["esp32"] reason: PSRAM only available on ESP32, S2, S3; code is fairly generic + +components/pthread/test_apps/pthread_unity_tests: + enable: + - if: IDF_TARGET in ["esp32", "esp32c2", "esp32c3", "esp32c5", "esp32c6", "esp32c61", "esp32h2", "esp32p4", "esp32s2", "esp32s3", "linux"] diff --git a/components/pthread/test_apps/pthread_unity_tests/README.md b/components/pthread/test_apps/pthread_unity_tests/README.md index 7b96141437..d2290ca669 100644 --- a/components/pthread/test_apps/pthread_unity_tests/README.md +++ b/components/pthread/test_apps/pthread_unity_tests/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | Linux | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | ----- | diff --git a/components/pthread/test_apps/pthread_unity_tests/main/CMakeLists.txt b/components/pthread/test_apps/pthread_unity_tests/main/CMakeLists.txt index f7a98a39ae..312997658e 100644 --- a/components/pthread/test_apps/pthread_unity_tests/main/CMakeLists.txt +++ b/components/pthread/test_apps/pthread_unity_tests/main/CMakeLists.txt @@ -1,12 +1,19 @@ -set(sources "test_app_main.c" - "test_pthread.c" - "test_pthread_cond_var.c" - "test_pthread_local_storage.c" - "test_pthread_cxx.cpp" - "test_pthread_rwlock.c" - "test_pthread_semaphore.c") +idf_build_get_property(target IDF_TARGET) + +set(sources "test_app_main.c" "test_esp_pthread.c") +set(priv_requires "pthread" "unity") + +if(NOT ${target} STREQUAL "linux") + list(APPEND sources "test_pthread.c" + "test_pthread_cond_var.c" + "test_pthread_local_storage.c" + "test_pthread_cxx.cpp" + "test_pthread_rwlock.c" + "test_pthread_semaphore.c") + list(APPEND priv_requires "esp_timer" "test_utils") +endif() idf_component_register(SRCS ${sources} INCLUDE_DIRS "." - REQUIRES pthread esp_timer test_utils + REQUIRES ${priv_requires} WHOLE_ARCHIVE) diff --git a/components/pthread/test_apps/pthread_unity_tests/main/test_app_main.c b/components/pthread/test_apps/pthread_unity_tests/main/test_app_main.c index 0f773d0fed..7f98a26b29 100644 --- a/components/pthread/test_apps/pthread_unity_tests/main/test_app_main.c +++ b/components/pthread/test_apps/pthread_unity_tests/main/test_app_main.c @@ -1,44 +1,35 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "unity.h" #include "unity_test_runner.h" -#include "esp_heap_caps.h" +#include "unity_test_utils_memory.h" // Some resources are lazy allocated (e.g. newlib locks), the threshold is left for that case #define TEST_MEMORY_LEAK_THRESHOLD (-200) -static size_t before_free_8bit; -static size_t before_free_32bit; - -static void check_leak(size_t before_free, size_t after_free, const char *type) -{ - ssize_t delta = after_free - before_free; - printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); - TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); -} - void setUp(void) { - before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + unity_utils_set_leak_level(TEST_MEMORY_LEAK_THRESHOLD); + unity_utils_record_free_mem(); errno = 0; } void tearDown(void) { +#ifndef CONFIG_IDF_TARGET_LINUX // on Linux, we don't check for memory leaks with memory utils // Add a short delay of 200ms to allow the idle task to free remaining memory vTaskDelay(pdMS_TO_TICKS(200)); - size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); - check_leak(before_free_8bit, after_free_8bit, "8BIT"); - check_leak(before_free_32bit, after_free_32bit, "32BIT"); +#endif // CONFIG_IDF_TARGET_LINUX + + unity_utils_evaluate_leaks(); } void app_main(void) diff --git a/components/pthread/test_apps/pthread_unity_tests/main/test_esp_pthread.c b/components/pthread/test_apps/pthread_unity_tests/main/test_esp_pthread.c new file mode 100644 index 0000000000..e1ac3c25f6 --- /dev/null +++ b/components/pthread/test_apps/pthread_unity_tests/main/test_esp_pthread.c @@ -0,0 +1,89 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include "sdkconfig.h" +#include "esp_pthread.h" +#include "esp_heap_caps.h" +#include "unity.h" + +TEST_CASE("esp_pthread_get_default_config creates correct stack memory capabilities", "[cfg]") +{ + esp_pthread_cfg_t default_config = esp_pthread_get_default_config(); + + // The default must always be internal, 8-bit accessible RAM + TEST_ASSERT_EQUAL_HEX(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, default_config.stack_alloc_caps); +} + +TEST_CASE("wrong heap caps are rejected", "[cfg]") +{ + esp_pthread_cfg_t default_config = esp_pthread_get_default_config(); + TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_set_cfg(&default_config)); // make sure we have saved a known value + + // Test the rejection of wrong values + default_config.stack_alloc_caps = MALLOC_CAP_32BIT; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_pthread_set_cfg(&default_config)); + + default_config.stack_alloc_caps = MALLOC_CAP_32BIT | MALLOC_CAP_INTERNAL; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_pthread_set_cfg(&default_config)); + + // check that saved values are unaltered + esp_pthread_cfg_t retrieved_config; + TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_get_cfg(&retrieved_config)); + TEST_ASSERT_EQUAL_HEX(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, retrieved_config.stack_alloc_caps); +} + +// On Linux, we silently adjust the stack size since pthread on Linux +// requires a minimum stack size of 0x4000. +#if !CONFIG_IDF_TARGET_LINUX +TEST_CASE("invalid stack size is rejected", "[cfg]") +{ + esp_pthread_cfg_t default_config = esp_pthread_get_default_config(); + TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_set_cfg(&default_config)); // make sure we have saved a known value + + // Test the rejection of wrong values + default_config.stack_size = PTHREAD_STACK_MIN - 1; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_pthread_set_cfg(&default_config)); + + // check that saved values are unaltered + esp_pthread_cfg_t retrieved_config; + TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_get_cfg(&retrieved_config)); + TEST_ASSERT_EQUAL(CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT, retrieved_config.stack_size); +} +#endif // !CONFIG_IDF_TARGET_LINUX + +TEST_CASE("correct memory is accepted", "[cfg]") +{ + esp_pthread_cfg_t default_config = esp_pthread_get_default_config(); + + default_config.stack_alloc_caps = MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL; + TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_set_cfg(&default_config)); +} + +TEST_CASE("configuration is preserved inside pthread", "[cfg]") +{ + esp_pthread_cfg_t saved_config; + esp_pthread_cfg_t retrieved_config; + saved_config.stack_size = PTHREAD_STACK_MIN; + saved_config.prio = 5; + saved_config.inherit_cfg = true; + saved_config.thread_name = "test_esp_pthread"; + saved_config.pin_to_core = 0; + saved_config.stack_alloc_caps = MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL; + + TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_set_cfg(&saved_config)); + TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_get_cfg(&retrieved_config)); + + TEST_ASSERT_EQUAL(saved_config.stack_size, retrieved_config.stack_size); + TEST_ASSERT_EQUAL(saved_config.prio, retrieved_config.prio); + TEST_ASSERT_EQUAL(saved_config.inherit_cfg, retrieved_config.inherit_cfg); + TEST_ASSERT_EQUAL(saved_config.thread_name, retrieved_config.thread_name); + TEST_ASSERT_EQUAL(saved_config.pin_to_core, retrieved_config.pin_to_core); + TEST_ASSERT_EQUAL(saved_config.stack_alloc_caps, retrieved_config.stack_alloc_caps); + + esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); + TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_set_cfg(&cfg)); +} diff --git a/components/pthread/test_apps/pthread_unity_tests/main/test_pthread.c b/components/pthread/test_apps/pthread_unity_tests/main/test_pthread.c index 2ebc220b13..551158bda8 100644 --- a/components/pthread/test_apps/pthread_unity_tests/main/test_pthread.c +++ b/components/pthread/test_apps/pthread_unity_tests/main/test_pthread.c @@ -13,33 +13,6 @@ #include "unity.h" -TEST_CASE("esp_pthread_get_default_config creates correct stack memory capabilities", "[set_cfg]") -{ - esp_pthread_cfg_t default_config = esp_pthread_get_default_config(); - - // The default must always be internal, 8-bit accessible RAM - TEST_ASSERT_EQUAL_HEX(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, default_config.stack_alloc_caps); -} - -TEST_CASE("wrong heap caps are rejected", "[set_cfg]") -{ - esp_pthread_cfg_t default_config = esp_pthread_get_default_config(); - - default_config.stack_alloc_caps = MALLOC_CAP_32BIT; - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_pthread_set_cfg(&default_config)); - - default_config.stack_alloc_caps = MALLOC_CAP_32BIT | MALLOC_CAP_INTERNAL; - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_pthread_set_cfg(&default_config)); -} - -TEST_CASE("correct memory is accepted", "[set_cfg]") -{ - esp_pthread_cfg_t default_config = esp_pthread_get_default_config(); - - default_config.stack_alloc_caps = MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL; - TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_set_cfg(&default_config)); -} - static void *compute_square(void *arg) { int *num = (int *) arg; diff --git a/components/pthread/test_apps/pthread_unity_tests/pytest_pthread_unity_tests.py b/components/pthread/test_apps/pthread_unity_tests/pytest_pthread_unity_tests.py index a2a231214e..a9472aa73d 100644 --- a/components/pthread/test_apps/pthread_unity_tests/pytest_pthread_unity_tests.py +++ b/components/pthread/test_apps/pthread_unity_tests/pytest_pthread_unity_tests.py @@ -62,3 +62,9 @@ def test_pthread_qemu(dut: Dut) -> None: for case in dut.test_menu: if 'qemu-ignore' not in case.groups and case.type == 'normal': dut._run_normal_case(case, timeout=75) + + +@pytest.mark.linux +@pytest.mark.host_test +def test_pthread_linux(dut: Dut) -> None: + dut.run_all_single_board_cases(timeout=120)