mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/linux_heap' into 'master'
heap: add linux target support Closes IDF-6000 See merge request espressif/esp-idf!21401
This commit is contained in:
commit
2f348d93c7
@ -385,6 +385,14 @@ test_esp_system:
|
||||
- echo "*" | timeout 5 build/test_esp_system.elf | tee log.txt || true
|
||||
- grep "6 Tests 0 Failures 0 Ignored" log.txt
|
||||
|
||||
test_heap_linux:
|
||||
extends: .host_test_template
|
||||
script:
|
||||
- cd ${IDF_PATH}/components/heap/host_test/host_test_linux/
|
||||
- idf.py build
|
||||
- echo "*" | timeout 5 build/test_heap.elf | tee log.txt || true
|
||||
- grep "4 Tests 0 Failures 0 Ignored" log.txt
|
||||
|
||||
test_esp_timer_cxx:
|
||||
extends: .host_test_template
|
||||
script:
|
||||
|
@ -103,9 +103,9 @@ TEST_CASE("register_too_many_shutdown_handler_fails", "[esp_system]")
|
||||
|
||||
TEST_CASE("heap_size_stubs", "[esp_system]")
|
||||
{
|
||||
TEST_ASSERT_EQUAL(47000, esp_get_free_heap_size());
|
||||
TEST_ASSERT_EQUAL(47000, esp_get_free_internal_heap_size());
|
||||
TEST_ASSERT_EQUAL(47000, esp_get_minimum_free_heap_size());
|
||||
TEST_ASSERT_EQUAL(UINT32_MAX, esp_get_free_heap_size());
|
||||
TEST_ASSERT_EQUAL(UINT32_MAX, esp_get_free_internal_heap_size());
|
||||
TEST_ASSERT_EQUAL(UINT32_MAX, esp_get_minimum_free_heap_size());
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
|
@ -12,8 +12,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_private/system_internal.h"
|
||||
|
||||
static const uint32_t MAGIC_HEAP_SIZE = 47000;
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
// dummy, we should never get here on Linux
|
||||
void esp_restart_noos_dig(void)
|
||||
@ -23,17 +22,17 @@ void esp_restart_noos_dig(void)
|
||||
|
||||
uint32_t esp_get_free_heap_size( void )
|
||||
{
|
||||
return MAGIC_HEAP_SIZE;
|
||||
return heap_caps_get_free_size( MALLOC_CAP_DEFAULT );
|
||||
}
|
||||
|
||||
uint32_t esp_get_free_internal_heap_size( void )
|
||||
{
|
||||
return MAGIC_HEAP_SIZE;
|
||||
return heap_caps_get_free_size( MALLOC_CAP_8BIT | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL );
|
||||
}
|
||||
|
||||
uint32_t esp_get_minimum_free_heap_size( void )
|
||||
{
|
||||
return MAGIC_HEAP_SIZE;
|
||||
return heap_caps_get_minimum_free_size( MALLOC_CAP_DEFAULT );
|
||||
}
|
||||
|
||||
const char *esp_get_idf_version(void)
|
||||
|
@ -1,5 +1,8 @@
|
||||
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
|
||||
|
||||
components/heap/host_test/host_test_linux:
|
||||
enable:
|
||||
- if: IDF_TARGET == "linux"
|
||||
components/heap/test_apps:
|
||||
disable_test:
|
||||
- if: IDF_TARGET == "esp32c6"
|
||||
|
@ -1,3 +1,12 @@
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
# On Linux, we only support a few features, hence this simple component registration
|
||||
if(${target} STREQUAL "linux")
|
||||
idf_component_register(SRCS "heap_caps_linux.c"
|
||||
INCLUDE_DIRS "include")
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(srcs
|
||||
"heap_caps.c"
|
||||
"heap_caps_init.c"
|
||||
|
225
components/heap/heap_caps_linux.c
Normal file
225
components/heap/heap_caps_linux.c
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
static esp_alloc_failed_hook_t alloc_failed_callback;
|
||||
|
||||
static const uint32_t MAGIC_HEAP_SIZE = UINT32_MAX;
|
||||
|
||||
esp_err_t heap_caps_register_failed_alloc_callback(esp_alloc_failed_hook_t callback)
|
||||
{
|
||||
if (callback == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
alloc_failed_callback = callback;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void heap_caps_alloc_failed(size_t requested_size, uint32_t caps, const char *function_name)
|
||||
{
|
||||
if (alloc_failed_callback) {
|
||||
alloc_failed_callback(requested_size, caps, function_name);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS
|
||||
esp_system_abort("Memory allocation failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
Routine to allocate a bit of memory with certain capabilities. caps is a bitfield of MALLOC_CAP_* bits.
|
||||
*/
|
||||
static void *heap_caps_malloc_base( size_t size, uint32_t caps)
|
||||
{
|
||||
|
||||
void *ptr = malloc(size);
|
||||
|
||||
if (!ptr && size > 0) {
|
||||
heap_caps_alloc_failed(size, caps, __func__);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *heap_caps_malloc( size_t size, uint32_t caps)
|
||||
{
|
||||
return heap_caps_malloc_base(size, caps);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void heap_caps_malloc_extmem_enable(size_t limit)
|
||||
{
|
||||
(void)limit;
|
||||
// No distinction between external vs internal memory on linux
|
||||
}
|
||||
|
||||
void *heap_caps_malloc_default( size_t size )
|
||||
{
|
||||
return heap_caps_malloc_base(size, MALLOC_CAP_DEFAULT);
|
||||
}
|
||||
|
||||
void *heap_caps_malloc_prefer( size_t size, size_t num, ... )
|
||||
{
|
||||
return heap_caps_malloc(size, MALLOC_CAP_DEFAULT);
|
||||
}
|
||||
|
||||
|
||||
static void *heap_caps_realloc_base( void *ptr, size_t size, uint32_t caps)
|
||||
{
|
||||
ptr = realloc(ptr, caps);
|
||||
|
||||
if (ptr == NULL && size > 0) {
|
||||
heap_caps_alloc_failed(size, caps, __func__);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *heap_caps_realloc( void *ptr, size_t size, uint32_t caps)
|
||||
{
|
||||
return heap_caps_realloc_base(ptr, size, caps);
|
||||
}
|
||||
|
||||
void *heap_caps_realloc_default( void *ptr, size_t size )
|
||||
{
|
||||
return heap_caps_realloc_base(ptr, size, MALLOC_CAP_DEFAULT);
|
||||
}
|
||||
|
||||
void *heap_caps_realloc_prefer( void *ptr, size_t size, size_t num, ... )
|
||||
{
|
||||
return heap_caps_realloc_base(ptr, size, MALLOC_CAP_DEFAULT);
|
||||
}
|
||||
|
||||
void heap_caps_free( void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static void *heap_caps_calloc_base( size_t n, size_t size, uint32_t caps)
|
||||
{
|
||||
size_t size_bytes;
|
||||
|
||||
if (__builtin_mul_overflow(n, size, &size_bytes)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return calloc(n, size);
|
||||
}
|
||||
|
||||
void *heap_caps_calloc( size_t n, size_t size, uint32_t caps)
|
||||
{
|
||||
void *ptr = heap_caps_calloc_base(n, size, caps);
|
||||
|
||||
if (!ptr && size > 0) {
|
||||
heap_caps_alloc_failed(size, caps, __func__);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void *heap_caps_calloc_prefer( size_t n, size_t size, size_t num, ... )
|
||||
{
|
||||
return heap_caps_calloc_base(n, size, MALLOC_CAP_DEFAULT);
|
||||
}
|
||||
|
||||
size_t heap_caps_get_total_size(uint32_t caps)
|
||||
{
|
||||
return MAGIC_HEAP_SIZE;
|
||||
}
|
||||
|
||||
size_t heap_caps_get_free_size( uint32_t caps )
|
||||
{
|
||||
return MAGIC_HEAP_SIZE;
|
||||
}
|
||||
|
||||
size_t heap_caps_get_minimum_free_size( uint32_t caps )
|
||||
{
|
||||
return MAGIC_HEAP_SIZE;
|
||||
}
|
||||
|
||||
size_t heap_caps_get_largest_free_block( uint32_t caps )
|
||||
{
|
||||
return MAGIC_HEAP_SIZE;
|
||||
}
|
||||
|
||||
void heap_caps_get_info( multi_heap_info_t *info, uint32_t caps )
|
||||
{
|
||||
bzero(info, sizeof(multi_heap_info_t));
|
||||
}
|
||||
|
||||
void heap_caps_print_heap_info( uint32_t caps )
|
||||
{
|
||||
printf("No heap summary available when building for the linux target");
|
||||
}
|
||||
|
||||
bool heap_caps_check_integrity(uint32_t caps, bool print_errors)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool heap_caps_check_integrity_all(bool print_errors)
|
||||
{
|
||||
return heap_caps_check_integrity(MALLOC_CAP_INVALID, print_errors);
|
||||
}
|
||||
|
||||
bool heap_caps_check_integrity_addr(intptr_t addr, bool print_errors)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void heap_caps_dump(uint32_t caps)
|
||||
{
|
||||
}
|
||||
|
||||
void heap_caps_dump_all(void)
|
||||
{
|
||||
heap_caps_dump(MALLOC_CAP_INVALID);
|
||||
}
|
||||
|
||||
size_t heap_caps_get_allocated_size( void *ptr )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint32_t caps)
|
||||
{
|
||||
void *ptr = aligned_alloc(alignment, size);
|
||||
|
||||
if (!ptr && size > 0) {
|
||||
heap_caps_alloc_failed(size, caps, __func__);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void heap_caps_aligned_free(void *ptr)
|
||||
{
|
||||
heap_caps_free(ptr);
|
||||
}
|
||||
|
||||
void *heap_caps_aligned_calloc(size_t alignment, size_t n, size_t size, uint32_t caps)
|
||||
{
|
||||
size_t size_bytes;
|
||||
if (__builtin_mul_overflow(n, size, &size_bytes)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *ptr = heap_caps_aligned_alloc(alignment, size_bytes, caps);
|
||||
if (ptr != NULL) {
|
||||
memset(ptr, 0, size_bytes);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
9
components/heap/host_test/host_test_linux/CMakeLists.txt
Normal file
9
components/heap/host_test/host_test_linux/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(COMPONENTS main)
|
||||
project(test_heap)
|
3
components/heap/host_test/host_test_linux/README.md
Normal file
3
components/heap/host_test/host_test_linux/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
| Supported Targets | Linux |
|
||||
| ----------------- | ----- |
|
||||
|
@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "test_heap_linux.c"
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES unity)
|
112
components/heap/host_test/host_test_linux/main/test_heap_linux.c
Normal file
112
components/heap/host_test/host_test_linux/main/test_heap_linux.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "unity.h"
|
||||
|
||||
#define MALLOC_LEN 1000
|
||||
#define TEST_VAL 0xAB
|
||||
|
||||
TEST_CASE("Alloc APIs", "[heap]")
|
||||
{
|
||||
uint8_t * p = heap_caps_malloc(MALLOC_LEN, MALLOC_CAP_DEFAULT);
|
||||
TEST_ASSERT_NOT_NULL(p);
|
||||
memset(p, TEST_VAL, MALLOC_LEN);
|
||||
|
||||
p = heap_caps_realloc(p, 2*MALLOC_LEN, MALLOC_CAP_DEFAULT);
|
||||
TEST_ASSERT_NOT_NULL(p);
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8(TEST_VAL, p, MALLOC_LEN);
|
||||
|
||||
heap_caps_realloc(p, 0, MALLOC_CAP_DEFAULT);
|
||||
|
||||
p = heap_caps_calloc(MALLOC_LEN, sizeof(uint8_t), MALLOC_CAP_DEFAULT);
|
||||
TEST_ASSERT_NOT_NULL(p);
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8(0, p, MALLOC_LEN);
|
||||
|
||||
/*Alloc prefer APIs*/
|
||||
p = heap_caps_malloc_prefer(MALLOC_LEN, MALLOC_CAP_DEFAULT);
|
||||
TEST_ASSERT_NOT_NULL(p);
|
||||
memset(p, TEST_VAL, MALLOC_LEN);
|
||||
|
||||
p = heap_caps_realloc_prefer(p, 2*MALLOC_LEN, MALLOC_CAP_DEFAULT);
|
||||
TEST_ASSERT_NOT_NULL(p);
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8(TEST_VAL, p, MALLOC_LEN);
|
||||
|
||||
heap_caps_realloc_prefer(p, 0, MALLOC_CAP_DEFAULT);
|
||||
|
||||
p = heap_caps_calloc_prefer(MALLOC_LEN, sizeof(uint8_t), MALLOC_CAP_DEFAULT);
|
||||
TEST_ASSERT_NOT_NULL(p);
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8(0, p, MALLOC_LEN);
|
||||
|
||||
heap_caps_free(p);
|
||||
}
|
||||
|
||||
TEST_CASE("Size APIs", "[heap]")
|
||||
{
|
||||
/* These functions doesnt provide any useful information on linux
|
||||
These "tests" are simply included to check that all the functions in the header
|
||||
are actually mocked
|
||||
*/
|
||||
printf("heap_caps_get_total_size: %zu\n", heap_caps_get_total_size(MALLOC_CAP_DEFAULT));
|
||||
printf("heap_caps_get_free_size: %zu\n", heap_caps_get_free_size(MALLOC_CAP_DEFAULT));
|
||||
printf("heap_caps_get_minimum_free_size: %zu\n", heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT));
|
||||
printf("heap_caps_get_largest_free_block: %zu\n", heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT));
|
||||
|
||||
multi_heap_info_t info;
|
||||
heap_caps_get_info(&info, MALLOC_CAP_DEFAULT);
|
||||
heap_caps_check_integrity_all(true);
|
||||
heap_caps_check_integrity(MALLOC_CAP_DEFAULT, true);
|
||||
heap_caps_check_integrity_addr((intptr_t)&info, true);
|
||||
heap_caps_malloc_extmem_enable(100);
|
||||
|
||||
heap_caps_dump(MALLOC_CAP_DEFAULT);
|
||||
heap_caps_dump_all();
|
||||
TEST_ASSERT_TRUE(heap_caps_get_allocated_size(&info) == 0);
|
||||
}
|
||||
|
||||
#define TEST_ALIGNMENT 0x1F
|
||||
|
||||
TEST_CASE("Aligned alloc APIs", "[heap]")
|
||||
{
|
||||
uint8_t * p = heap_caps_aligned_alloc(TEST_ALIGNMENT, MALLOC_LEN, MALLOC_CAP_DEFAULT);
|
||||
TEST_ASSERT_NOT_NULL(p);
|
||||
TEST_ASSERT_TRUE(((intptr_t)p & (0x1F -1)) == 0);
|
||||
memset(p, TEST_VAL, MALLOC_LEN);
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8(TEST_VAL, p, MALLOC_LEN);
|
||||
heap_caps_free(p);
|
||||
|
||||
p = heap_caps_aligned_calloc(TEST_ALIGNMENT, MALLOC_LEN, sizeof(uint8_t), MALLOC_CAP_DEFAULT);
|
||||
TEST_ASSERT_NOT_NULL(p);
|
||||
TEST_ASSERT_TRUE(((intptr_t)p & (0x1F -1)) == 0);
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8(0, p, MALLOC_LEN);
|
||||
heap_caps_free(p);
|
||||
}
|
||||
|
||||
static bool alloc_failed;
|
||||
|
||||
void alloc_failed_cb(size_t size, uint32_t caps, const char * function_name)
|
||||
{
|
||||
printf("Failed alloc of size %zu bytes at %s", size, function_name);
|
||||
alloc_failed = true;
|
||||
}
|
||||
|
||||
TEST_CASE("Misc APIs", "[heap]")
|
||||
{
|
||||
heap_caps_register_failed_alloc_callback(alloc_failed_cb);
|
||||
|
||||
heap_caps_malloc(SIZE_MAX, MALLOC_CAP_DEFAULT);
|
||||
TEST_ASSERT_TRUE(alloc_failed);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
printf("Running heap linux API host test app");
|
||||
unity_run_menu();
|
||||
}
|
@ -0,0 +1 @@
|
||||
CONFIG_IDF_TARGET="linux"
|
@ -226,7 +226,7 @@ function(__build_init idf_path)
|
||||
endforeach()
|
||||
|
||||
if("${target}" STREQUAL "linux")
|
||||
set(requires_common freertos log esp_rom esp_common esp_system linux)
|
||||
set(requires_common freertos heap log esp_rom esp_common esp_system linux)
|
||||
idf_build_set_property(__COMPONENT_REQUIRES_COMMON "${requires_common}")
|
||||
else()
|
||||
# Set components required by all other components in the build
|
||||
|
Loading…
Reference in New Issue
Block a user