Skip to content

Commit

Permalink
fix(heap): memalign respect malloc_alwaysinternal_limit
Browse files Browse the repository at this point in the history
This changes `memalign` (and `posix_memalign`) so that it uses an
allocation method with the same selection criteria (checking
`malloc_alwaysinternal_limit` and picking one of:

- always MALLOC_CAP_INTERNAL
- MALLOC_CAP_INTERNAL first with fallback
- MALLOC_CAP_SPIRAM first with fallback

`malloc_alwaysinternal_limit` is in turn set by the options
`CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL` and
`CONFIG_SPRIAM_USE_CAPS_ALLOC`.

This notably affects folks using esp-rs to build rust code for the
esp-idf, as all allocations from rust use `memalign`.

Merges espressif#12375
  • Loading branch information
codysch authored and movsb committed Dec 1, 2023
1 parent 39121ee commit 10ba063
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 30 deletions.
102 changes: 75 additions & 27 deletions components/heap/heap_caps.c
Original file line number Diff line number Diff line change
Expand Up @@ -660,31 +660,8 @@ size_t heap_caps_get_allocated_size( void *ptr )
return MULTI_HEAP_REMOVE_BLOCK_OWNER_SIZE(size);
}

HEAP_IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint32_t caps)
static HEAP_IRAM_ATTR void *heap_caps_aligned_alloc_base(size_t alignment, size_t size, uint32_t caps)
{
void *ret = NULL;

if(!alignment) {
return NULL;
}

//Alignment must be a power of two:
if((alignment & (alignment - 1)) != 0) {
return NULL;
}

if (size == 0) {
return NULL;
}

if (MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size) > HEAP_SIZE_MAX) {
// Avoids int overflow when adding small numbers to size, or
// calculating 'end' from start+size, by limiting 'size' to the possible range
heap_caps_alloc_failed(size, caps, __func__);

return NULL;
}

for (int prio = 0; prio < SOC_MEMORY_TYPE_NO_PRIOS; prio++) {
//Iterate over heaps and check capabilities at this priority
heap_t *heap;
Expand All @@ -697,7 +674,7 @@ HEAP_IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint
//doesn't cover, see if they're available in other prios.
if ((get_all_caps(heap) & caps) == caps) {
//Just try to alloc, nothing special.
ret = multi_heap_aligned_alloc(heap->heap, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size), alignment);
void *ret = multi_heap_aligned_alloc(heap->heap, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size), alignment);
if (ret != NULL) {
MULTI_HEAP_SET_BLOCK_OWNER(ret);
ret = MULTI_HEAP_ADD_BLOCK_OWNER_OFFSET(ret);
Expand All @@ -709,12 +686,83 @@ HEAP_IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint
}
}

heap_caps_alloc_failed(size, caps, __func__);

//Nothing usable found.
return NULL;
}

static HEAP_IRAM_ATTR esp_err_t heap_caps_aligned_check_args(size_t alignment, size_t size, uint32_t caps, const char *funcname)
{
if (!alignment) {
return ESP_FAIL;
}

// Alignment must be a power of two:
if ((alignment & (alignment - 1)) != 0) {
return ESP_FAIL;
}

if (size == 0) {
return ESP_FAIL;
}

if (MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size) > HEAP_SIZE_MAX) {
// Avoids int overflow when adding small numbers to size, or
// calculating 'end' from start+size, by limiting 'size' to the possible range
heap_caps_alloc_failed(size, caps, funcname);
return ESP_FAIL;
}

return ESP_OK;
}

HEAP_IRAM_ATTR void *heap_caps_aligned_alloc_default(size_t alignment, size_t size)
{
void *ret = NULL;

if (malloc_alwaysinternal_limit == MALLOC_DISABLE_EXTERNAL_ALLOCS) {
return heap_caps_aligned_alloc(alignment, size, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
}

if (heap_caps_aligned_check_args(alignment, size, MALLOC_CAP_DEFAULT, __func__) != ESP_OK) {
return NULL;
}

if (size <= (size_t)malloc_alwaysinternal_limit) {
ret = heap_caps_aligned_alloc_base(alignment, size, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
} else {
ret = heap_caps_aligned_alloc_base(alignment, size, MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM);
}

if (ret != NULL) {
return ret;
}

ret = heap_caps_aligned_alloc_base(alignment, size, MALLOC_CAP_DEFAULT);

if (ret == NULL) {
heap_caps_alloc_failed(size, MALLOC_CAP_DEFAULT, __func__);
}

return ret;
}

HEAP_IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint32_t caps)
{
void *ret = NULL;

if (heap_caps_aligned_check_args(alignment, size, caps, __func__) != ESP_OK) {
return NULL;
}

ret = heap_caps_aligned_alloc_base(alignment, size, caps);

if (ret == NULL) {
heap_caps_alloc_failed(size, caps, __func__);
}

return ret;
}

HEAP_IRAM_ATTR void heap_caps_aligned_free(void *ptr)
{
heap_caps_free(ptr);
Expand Down
1 change: 1 addition & 0 deletions components/heap/heap_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ inline static uint32_t get_all_caps(const heap_t *heap)
*/
void *heap_caps_realloc_default(void *p, size_t size);
void *heap_caps_malloc_default(size_t size);
void *heap_caps_aligned_alloc_default(size_t alignment, size_t size);


#ifdef __cplusplus
Expand Down
7 changes: 4 additions & 3 deletions components/newlib/heap.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -18,6 +18,7 @@
*/
extern void *heap_caps_malloc_default( size_t size );
extern void *heap_caps_realloc_default( void *ptr, size_t size );
extern void *heap_caps_aligned_alloc_default( size_t alignment, size_t size );

void* malloc(size_t size)
{
Expand Down Expand Up @@ -71,7 +72,7 @@ void* _calloc_r(struct _reent *r, size_t nmemb, size_t size)

void* memalign(size_t alignment, size_t n)
{
return heap_caps_aligned_alloc(alignment, n, MALLOC_CAP_DEFAULT);
return heap_caps_aligned_alloc_default(alignment, n);
}

int posix_memalign(void **out_ptr, size_t alignment, size_t size)
Expand All @@ -81,7 +82,7 @@ int posix_memalign(void **out_ptr, size_t alignment, size_t size)
*out_ptr = NULL;
return 0;
}
void *result = heap_caps_aligned_alloc(alignment, size, MALLOC_CAP_DEFAULT);
void *result = heap_caps_aligned_alloc_default(alignment, size);
if (result != NULL) {
/* Modify output pointer only on success */
*out_ptr = result;
Expand Down
21 changes: 21 additions & 0 deletions components/newlib/test_apps/newlib/main/test_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <sys/param.h>
#include <stdlib.h>
#include "unity.h"
#include "esp_heap_caps.h"


TEST_CASE("misc - posix_memalign", "[newlib_misc]")
Expand Down Expand Up @@ -41,6 +42,26 @@ TEST_CASE("misc - posix_memalign", "[newlib_misc]")
TEST_ASSERT_NOT_NULL(outptr);
TEST_ASSERT_EQUAL_INT(ret, 0);
free(outptr);

outptr = magic;
heap_caps_malloc_extmem_enable(128);
ret = posix_memalign(&outptr, 16, 64);
TEST_ASSERT_TRUE(outptr != magic);
TEST_ASSERT_NOT_NULL(outptr);
TEST_ASSERT_EQUAL_INT(ret, 0);
free(outptr);

outptr = magic;
heap_caps_malloc_extmem_enable(64);
ret = posix_memalign(&outptr, 16, 128);
TEST_ASSERT_TRUE(outptr != magic);
TEST_ASSERT_NOT_NULL(outptr);
TEST_ASSERT_EQUAL_INT(ret, 0);
free(outptr);

#if CONFIG_SPIRAM_USE_MALLOC
heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
#endif
}

TEST_CASE("misc - sysconf", "[newlib_misc]")
Expand Down

0 comments on commit 10ba063

Please sign in to comment.