mirror of
https://github.com/micropython/micropython.git
synced 2026-04-20 07:50:18 +02:00
py/malloc: Add m_tracked_realloc.
Add realloc support to the tracked allocation API, using an alloc-copy-free approach for simplicity and thread safety. This function compliments the existing `m_tracked_calloc()` and `m_tracked_free()` functions. Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
This commit is contained in:
committed by
Damien George
parent
501b0e6bab
commit
dc0b2c7f57
50
py/malloc.c
50
py/malloc.c
@@ -245,6 +245,15 @@ typedef struct _m_tracked_node_t {
|
||||
uint8_t data[];
|
||||
} m_tracked_node_t;
|
||||
|
||||
// Helper to get data size of a tracked node, abstracting MICROPY_TRACKED_ALLOC_STORE_SIZE.
|
||||
static inline size_t get_tracked_node_size(m_tracked_node_t *node) {
|
||||
#if MICROPY_TRACKED_ALLOC_STORE_SIZE
|
||||
return node->size;
|
||||
#else
|
||||
return gc_nbytes(node) - sizeof(m_tracked_node_t);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MICROPY_DEBUG_VERBOSE
|
||||
static size_t m_tracked_count_links(size_t *nb) {
|
||||
m_tracked_node_lock();
|
||||
@@ -292,6 +301,41 @@ void *m_tracked_calloc(size_t nmemb, size_t size) {
|
||||
return &node->data[0];
|
||||
}
|
||||
|
||||
void *m_tracked_realloc(void *ptr_in, size_t n_bytes) {
|
||||
// Handle pure allocation
|
||||
if (ptr_in == NULL) {
|
||||
return m_tracked_calloc(1, n_bytes);
|
||||
}
|
||||
|
||||
// Handle pure free
|
||||
if (n_bytes == 0) {
|
||||
m_tracked_free(ptr_in);
|
||||
return NULL;
|
||||
}
|
||||
// To keep the implementation simple, we always allocate a new buffer and copy the old data into it.
|
||||
// This could be optimised if faster performance or lower worst-case memory usage is required.
|
||||
|
||||
// Get old size
|
||||
m_tracked_node_t *old_node = (m_tracked_node_t *)((uint8_t *)ptr_in - sizeof(m_tracked_node_t));
|
||||
size_t old_size = get_tracked_node_size(old_node);
|
||||
|
||||
// Allocate new buffer
|
||||
void *new_ptr = m_tracked_calloc(1, n_bytes);
|
||||
if (new_ptr == NULL) {
|
||||
// Allocation failed, return NULL but leave original pointer intact
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Copy data (minimum of old and new size)
|
||||
size_t copy_size = MIN(old_size, n_bytes);
|
||||
memcpy(new_ptr, ptr_in, copy_size);
|
||||
|
||||
// Free old buffer
|
||||
m_tracked_free(ptr_in);
|
||||
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void m_tracked_free(void *ptr_in) {
|
||||
if (ptr_in == NULL) {
|
||||
return;
|
||||
@@ -299,11 +343,7 @@ void m_tracked_free(void *ptr_in) {
|
||||
m_tracked_node_t *node = (m_tracked_node_t *)((uint8_t *)ptr_in - sizeof(m_tracked_node_t));
|
||||
#if MICROPY_DEBUG_VERBOSE
|
||||
size_t data_bytes;
|
||||
#if MICROPY_TRACKED_ALLOC_STORE_SIZE
|
||||
data_bytes = node->size;
|
||||
#else
|
||||
data_bytes = gc_nbytes(node);
|
||||
#endif
|
||||
data_bytes = get_tracked_node_size(node);
|
||||
size_t nb;
|
||||
size_t n = m_tracked_count_links(&nb);
|
||||
DEBUG_printf("m_tracked_free(%p, [%p, %p], nbytes=%u, links=%u;%u)\n", node, node->prev, node->next, (int)data_bytes, (int)n, (int)nb);
|
||||
|
||||
@@ -138,6 +138,7 @@ MP_NORETURN void m_malloc_fail(size_t num_bytes);
|
||||
// These alloc/free functions track the pointers in a linked list so the GC does not reclaim
|
||||
// them. They can be used by code that requires traditional C malloc/free semantics.
|
||||
void *m_tracked_calloc(size_t nmemb, size_t size);
|
||||
void *m_tracked_realloc(void *ptr_in, size_t n_bytes);
|
||||
void m_tracked_free(void *ptr_in);
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user