diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index 32c554c159d..06bbfa1e691 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -5381,6 +5381,32 @@ void *k_heap_aligned_alloc(struct k_heap *h, size_t align, size_t bytes, void *k_heap_alloc(struct k_heap *h, size_t bytes, k_timeout_t timeout) __attribute_nonnull(1); +/** + * @brief Reallocate memory from a k_heap + * + * Reallocates and returns a memory buffer from the memory region owned + * by the heap. If no memory is available immediately, the call will + * block for the specified timeout (constructed via the standard + * timeout API, or K_NO_WAIT or K_FOREVER) waiting for memory to be + * freed. If the allocation cannot be performed by the expiration of + * the timeout, NULL will be returned. + * Reallocated memory is aligned on a multiple of pointer sizes. + * + * @note @a timeout must be set to K_NO_WAIT if called from ISR. + * @note When CONFIG_MULTITHREADING=n any @a timeout is treated as K_NO_WAIT. + * + * @funcprops \isr_ok + * + * @param h Heap from which to allocate + * @param ptr Original pointer returned from a previous allocation + * @param bytes Desired size of block to allocate + * @param timeout How long to wait, or K_NO_WAIT + * + * @return Pointer to memory the caller can now use, or NULL + */ +void *k_heap_realloc(struct k_heap *h, void *ptr, size_t bytes, k_timeout_t timeout) + __attribute_nonnull(1); + /** * @brief Free memory allocated by k_heap_alloc() * @@ -5528,6 +5554,25 @@ void k_free(void *ptr); */ void *k_calloc(size_t nmemb, size_t size); +/** @brief Expand the size of an existing allocation + * + * Returns a pointer to a new memory region with the same contents, + * but a different allocated size. If the new allocation can be + * expanded in place, the pointer returned will be identical. + * Otherwise the data will be copies to a new block and the old one + * will be freed as per sys_heap_free(). If the specified size is + * smaller than the original, the block will be truncated in place and + * the remaining memory returned to the heap. If the allocation of a + * new block fails, then NULL will be returned and the old block will + * not be freed or modified. + * + * @param ptr Original pointer returned from a previous allocation + * @param size Amount of memory requested (in bytes). + * + * @return Pointer to memory the caller can now use, or NULL. + */ +void *k_realloc(void *ptr, size_t size); + /** @} */ /* polling API - PRIVATE */ diff --git a/kernel/kheap.c b/kernel/kheap.c index ccdd6690788..a452f172a56 100644 --- a/kernel/kheap.c +++ b/kernel/kheap.c @@ -116,6 +116,32 @@ void *k_heap_alloc(struct k_heap *heap, size_t bytes, k_timeout_t timeout) return ret; } +void *k_heap_realloc(struct k_heap *heap, void *ptr, size_t bytes, k_timeout_t timeout) +{ + k_timepoint_t end = sys_timepoint_calc(timeout); + void *ret = NULL; + + k_spinlock_key_t key = k_spin_lock(&heap->lock); + + __ASSERT(!arch_is_in_isr() || K_TIMEOUT_EQ(timeout, K_NO_WAIT), ""); + + while (ret == NULL) { + ret = sys_heap_aligned_realloc(&heap->heap, ptr, sizeof(void *), bytes); + + if (!IS_ENABLED(CONFIG_MULTITHREADING) || + (ret != NULL) || K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { + break; + } + + timeout = sys_timepoint_timeout(end); + (void) z_pend_curr(&heap->lock, key, &heap->wait_q, timeout); + key = k_spin_lock(&heap->lock); + } + + k_spin_unlock(&heap->lock, key); + return ret; +} + void k_heap_free(struct k_heap *heap, void *mem) { k_spinlock_key_t key = k_spin_lock(&heap->lock); diff --git a/kernel/mempool.c b/kernel/mempool.c index 13e9c7abec2..3d7dba22fac 100644 --- a/kernel/mempool.c +++ b/kernel/mempool.c @@ -113,6 +113,34 @@ void *k_calloc(size_t nmemb, size_t size) return ret; } +void *k_realloc(void *ptr, size_t size) +{ + struct k_heap *heap, **heap_ref; + void *ret; + + if (size == 0) { + k_free(ptr); + return NULL; + } + if (ptr == NULL) { + return k_malloc(size); + } + heap_ref = ptr; + ptr = --heap_ref; + heap = *heap_ref; + + if (size_add_overflow(size, sizeof(heap_ref), &size)) { + return NULL; + } + + ret = k_heap_realloc(heap, ptr, size, K_NO_WAIT); + if (ret != NULL) { + heap_ref = ret; + ret = ++heap_ref; + } + return ret; +} + void k_thread_system_pool_assign(struct k_thread *thread) { thread->resource_pool = _SYSTEM_HEAP;