feat(ble/nimble): support runtime allocation for mempool

This commit is contained in:
chenjianhua
2025-10-28 17:24:52 +08:00
parent 8fd41d86c4
commit c6709f6efa
25 changed files with 427 additions and 49 deletions
+6
View File
@@ -71,6 +71,8 @@ struct os_mempool {
SLIST_HEAD(,os_memblock);
/** Name for memory block */
const char *name;
/** The number of allocated blocks. */
uint32_t mp_alloc_blocks;
};
/**
@@ -78,6 +80,10 @@ struct os_mempool {
* (struct os_mempool_ext *).
*/
#define OS_MEMPOOL_F_EXT 0x01
/* Flag to indicate runtime allocation mode */
#define OS_MEMPOOL_F_RUNTIME 0x02
/* Flag to indicate reuse block for runtime allocation mode */
#define OS_MEMPOOL_F_REUSED 0x04
struct os_mempool_ext;
+10 -2
View File
@@ -66,6 +66,9 @@ static struct ble_npl_event ble_hs_ev_stop;
extern void os_msys_init(void);
extern void os_mempool_module_init(void);
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
extern void os_mempool_deinit(void);
#endif
/**
* Called when the host stop procedure has completed.
@@ -93,6 +96,9 @@ esp_err_t esp_nimble_init(void)
esp_err_t ret;
#endif
#if !SOC_ESP_NIMBLE_CONTROLLER || !CONFIG_BT_CONTROLLER_ENABLED
/* Initialize the global memory pool */
os_mempool_module_init();
/* Initialize the function pointers for OS porting */
npl_freertos_funcs_init();
@@ -117,8 +123,6 @@ esp_err_t esp_nimble_init(void)
/* Initialize default event queue */
ble_npl_eventq_init(&g_eventq_dflt);
/* Initialize the global memory pool */
os_mempool_module_init();
os_msys_init();
#endif
@@ -165,6 +169,10 @@ esp_err_t esp_nimble_deinit(void)
npl_freertos_mempool_deinit();
#endif
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
os_mempool_deinit();
#endif
return ESP_OK;
}
+170 -2
View File
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include "syscfg/syscfg.h"
#include "modlog/modlog.h"
#include "esp_nimble_mem.h"
#if !MYNEWT_VAL(OS_SYSVIEW_TRACE_MEMPOOL)
#define OS_TRACE_DISABLE_FILE_API
#endif
@@ -132,9 +133,12 @@ os_mempool_init_internal(struct os_mempool *mp, uint16_t blocks,
return OS_INVALID_PARM;
}
/* For runtime allocation mode, membuf can be NULL */
#if !MYNEWT_VAL(MP_RUNTIME_ALLOC)
if ((!membuf) && (blocks != 0)) {
return OS_INVALID_PARM;
}
#endif
if (membuf != NULL) {
/* Blocks need to be sized properly and memory buffer should be
@@ -155,6 +159,22 @@ os_mempool_init_internal(struct os_mempool *mp, uint16_t blocks,
mp->name = name;
SLIST_FIRST(mp) = membuf;
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
if (membuf == NULL) {
/* Runtime allocation mode */
mp->mp_membuf_addr = 0;
mp->mp_flags |= OS_MEMPOOL_F_RUNTIME;
#if MYNEWT_VAL(MP_BLOCK_REUSED)
mp->mp_flags |= OS_MEMPOOL_F_REUSED;
mp->mp_alloc_blocks = 0;
#endif
SLIST_FIRST(mp) = NULL;
STAILQ_INSERT_TAIL(&g_os_mempool_list, mp, mp_list);
return OS_OK;
}
#endif
if (blocks > 0) {
os_mempool_poison(mp, membuf);
os_mempool_guard(mp, membuf);
@@ -255,6 +275,28 @@ os_mempool_clear(struct os_mempool *mp)
return OS_INVALID_PARM;
}
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
/* For runtime allocation mode, check whether all blocks have been freed */
if (mp->mp_flags & OS_MEMPOOL_F_RUNTIME) {
assert(mp->mp_num_free == mp->mp_num_blocks);
/* For block reused mode, free all allocated blocks */
if (mp->mp_flags & OS_MEMPOOL_F_REUSED) {
void *temp_ptr;
block_ptr = SLIST_FIRST(mp);
while (block_ptr) {
temp_ptr = block_ptr;
block_ptr = SLIST_NEXT(block_ptr, mb_next);
nimble_platform_mem_free(temp_ptr);
}
mp->mp_alloc_blocks = 0;
}
/* Only reset statistics */
SLIST_FIRST(mp) = NULL;
mp->mp_min_free = mp->mp_num_blocks;
return OS_OK;
}
#endif
true_block_size = OS_MEMPOOL_TRUE_BLOCK_SIZE(mp);
/* cleanup the memory pool structure */
@@ -287,7 +329,11 @@ os_mempool_clear(struct os_mempool *mp)
os_error_t
os_mempool_ext_clear(struct os_mempool_ext *mpe)
{
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
mpe->mpe_mp.mp_flags &= ~OS_MEMPOOL_F_EXT;
#else
mpe->mpe_mp.mp_flags = 0;
#endif
mpe->mpe_put_cb = NULL;
mpe->mpe_put_arg = NULL;
@@ -299,6 +345,13 @@ os_mempool_is_sane(const struct os_mempool *mp)
{
struct os_memblock *block;
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
/* Runtime mode cannot verify sanity */
if (mp->mp_flags & OS_MEMPOOL_F_RUNTIME) {
assert(0);
}
#endif
/* Verify that each block in the free list belongs to the mempool. */
SLIST_FOREACH(block, mp, mb_next) {
if (!os_memblock_from(mp, block)) {
@@ -318,6 +371,13 @@ os_memblock_from(const struct os_mempool *mp, const void *block_addr)
uintptr_t baddr32;
uint32_t end;
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
/* Runtime allocation mode doesn't support from */
if (mp->mp_flags & OS_MEMPOOL_F_RUNTIME) {
assert(0);
}
#endif
static_assert(sizeof block_addr == sizeof baddr32,
"Pointer to void must be 32-bits.");
@@ -348,6 +408,64 @@ os_memblock_get(struct os_mempool *mp)
/* Check to make sure they passed in a memory pool (or something) */
block = NULL;
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
/* Runtime allocation mode */
if (mp && mp->mp_flags & OS_MEMPOOL_F_RUNTIME) {
bool need_alloc = false;
void *allocated_block;
uint32_t alloc_size;
OS_ENTER_CRITICAL(sr);
if (mp->mp_num_free) {
if (mp->mp_flags & OS_MEMPOOL_F_REUSED) {
if (SLIST_FIRST(mp) != NULL) {
block = SLIST_FIRST(mp);
SLIST_FIRST(mp) = SLIST_NEXT(block, mb_next);
} else if (mp->mp_alloc_blocks < mp->mp_num_blocks) {
need_alloc = true;
mp->mp_alloc_blocks++;
}
} else {
need_alloc = true;
}
/* Decrement number free by 1 */
mp->mp_num_free--;
if (mp->mp_min_free > mp->mp_num_free) {
mp->mp_min_free = mp->mp_num_free;
}
}
OS_EXIT_CRITICAL(sr);
/* Allocate outside critical section to avoid holding lock too long */
if (need_alloc) {
alloc_size = OS_MEMPOOL_TRUE_BLOCK_SIZE(mp);
allocated_block = nimble_platform_mem_malloc(alloc_size);
if (allocated_block) {
/* Initialize poison and guard */
os_mempool_poison(mp, allocated_block);
os_mempool_guard(mp, allocated_block);
/* Save mempool pointer for block */
block = (struct os_memblock *)(allocated_block);
} else {
// Should not happen
OS_ENTER_CRITICAL(sr);
mp->mp_num_free++;
OS_EXIT_CRITICAL(sr);
esp_rom_printf("%s malloc failed, size=%u\n", __func__, alloc_size);
}
} else if (block) {
os_mempool_poison_check(mp, block);
os_mempool_guard_check(mp, block);
}
return block;
}
#endif
if (mp) {
OS_ENTER_CRITICAL(sr);
/* Check for any free */
@@ -386,6 +504,33 @@ os_memblock_put_from_cb(struct os_mempool *mp, void *block_addr)
os_trace_api_u32x2(OS_TRACE_ID_MEMBLOCK_PUT_FROM_CB, (uint32_t)(uintptr_t)mp,
(uint32_t)(uintptr_t)block_addr);
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
if (mp->mp_flags & OS_MEMPOOL_F_RUNTIME) {
bool need_free = true;
os_mempool_guard_check(mp, block_addr);
/* Runtime allocation mode - free directly */
OS_ENTER_CRITICAL(sr);
if (mp->mp_flags & OS_MEMPOOL_F_REUSED) {
block = (struct os_memblock *)block_addr;
SLIST_NEXT(block, mb_next) = SLIST_FIRST(mp);
SLIST_FIRST(mp) = block;
need_free = false;
}
mp->mp_num_free++;
assert(mp->mp_num_blocks >= mp->mp_num_free);
OS_EXIT_CRITICAL(sr);
/* Free outside critical section */
if (need_free) {
free(block_addr);
} else {
os_mempool_poison(mp, block_addr);
}
return OS_OK;
}
#endif
os_mempool_guard_check(mp, block_addr);
os_mempool_poison(mp, block_addr);
@@ -426,8 +571,13 @@ os_memblock_put(struct os_mempool *mp, void *block_addr)
}
#if MYNEWT_VAL(OS_MEMPOOL_CHECK)
/* Check that the block we are freeing is a valid block! */
assert(os_memblock_from(mp, block_addr));
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
if (!(mp->mp_flags & OS_MEMPOOL_F_RUNTIME))
#endif
{
/* Check that the block we are freeing is a valid block! */
assert(os_memblock_from(mp, block_addr));
}
/*
* Check for duplicate free.
@@ -485,3 +635,21 @@ os_mempool_module_init(void)
{
STAILQ_INIT(&g_os_mempool_list);
}
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
void
os_mempool_deinit(void)
{
struct os_mempool *mp = NULL;
mp = STAILQ_FIRST(&g_os_mempool_list);
// All mempool blocks should be reclaimed after nimble deinit
while (mp) {
if (mp->mp_flags & OS_MEMPOOL_F_RUNTIME) {
os_mempool_clear(mp);
}
mp = STAILQ_NEXT(mp, mp_list);
}
}
#endif
+33 -26
View File
@@ -114,9 +114,13 @@ static os_membuf_t *ble_freertos_ev_buf = NULL;
#else
struct os_mempool ble_freertos_ev_pool;
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
static os_membuf_t *ble_freertos_ev_buf = NULL;
#else
static os_membuf_t ble_freertos_ev_buf[
OS_MEMPOOL_SIZE(BLE_TOTAL_EV_COUNT, sizeof (struct ble_npl_event_freertos))
];
#endif
#endif
@@ -176,7 +180,7 @@ npl_freertos_event_init(struct ble_npl_event *ev, ble_npl_event_fn *fn,
{
struct ble_npl_event_freertos *event = NULL;
#if OS_MEM_ALLOC
if (!os_memblock_from(&ble_freertos_ev_pool,ev->event)) {
if (!ev->event) {
ev->event = os_memblock_get(&ble_freertos_ev_pool);
}
#else
@@ -217,7 +221,7 @@ npl_freertos_eventq_init(struct ble_npl_eventq *evq)
{
struct ble_npl_eventq_freertos *eventq = NULL;
#if OS_MEM_ALLOC
if (!os_memblock_from(&ble_freertos_evq_pool,evq->eventq)) {
if (!evq->eventq) {
evq->eventq = os_memblock_get(&ble_freertos_evq_pool);
eventq = (struct ble_npl_eventq_freertos*)evq->eventq;
BLE_LL_ASSERT(eventq);
@@ -399,7 +403,7 @@ npl_freertos_mutex_init(struct ble_npl_mutex *mu)
{
struct ble_npl_mutex_freertos *mutex = NULL;
#if OS_MEM_ALLOC
if (!os_memblock_from(&ble_freertos_mutex_pool,mu->mutex)) {
if (!mu->mutex) {
mu->mutex = os_memblock_get(&ble_freertos_mutex_pool);
mutex = (struct ble_npl_mutex_freertos *)mu->mutex;
@@ -546,7 +550,7 @@ npl_freertos_sem_init(struct ble_npl_sem *sem, uint16_t tokens)
{
struct ble_npl_sem_freertos *semaphor = NULL;
#if OS_MEM_ALLOC
if (!os_memblock_from(&ble_freertos_sem_pool,sem->sem)) {
if (!sem->sem) {
sem->sem = os_memblock_get(&ble_freertos_sem_pool);
semaphor = (struct ble_npl_sem_freertos *)sem->sem;
@@ -708,7 +712,7 @@ npl_freertos_callout_init(struct ble_npl_callout *co, struct ble_npl_eventq *evq
struct ble_npl_callout_freertos *callout = NULL;
#if OS_MEM_ALLOC
if (!os_memblock_from(&ble_freertos_co_pool, co->co)) {
if (!co->co) {
co->co = os_memblock_get(&ble_freertos_co_pool);
callout = (struct ble_npl_callout_freertos *)co->co;
BLE_LL_ASSERT(callout);
@@ -1151,7 +1155,7 @@ int npl_freertos_mempool_init(void)
{
int rc = -1;
#if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED
#if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED && !MYNEWT_VAL(MP_RUNTIME_ALLOC)
ble_freertos_ev_buf = nimble_platform_mem_malloc(OS_MEMPOOL_SIZE(BLE_TOTAL_EV_COUNT, sizeof (struct ble_npl_event_freertos)) * sizeof(os_membuf_t));
if(!ble_freertos_ev_buf) {
goto _error;
@@ -1159,14 +1163,17 @@ int npl_freertos_mempool_init(void)
#endif
#if CONFIG_BT_CONTROLLER_ENABLED
/* It is not recommended to use MP_RUNTIME_ALLOC when the block size is 4 bytes. */
ble_freertos_evq_buf = nimble_platform_mem_malloc(OS_MEMPOOL_SIZE(BLE_TOTAL_EVQ_COUNT, sizeof (struct ble_npl_eventq_freertos)) * sizeof(os_membuf_t));
if(!ble_freertos_evq_buf) {
goto _error;
}
#if !MYNEWT_VAL(MP_RUNTIME_ALLOC)
ble_freertos_co_buf = nimble_platform_mem_malloc(OS_MEMPOOL_SIZE(BLE_TOTAL_CO_COUNT, sizeof (struct ble_npl_callout_freertos)) * sizeof(os_membuf_t));
if(!ble_freertos_co_buf) {
goto _error;
}
#endif
ble_freertos_sem_buf = nimble_platform_mem_malloc(OS_MEMPOOL_SIZE(BLE_TOTAL_SEM_COUNT, sizeof (struct ble_npl_sem_freertos)) * sizeof(os_membuf_t));
if(!ble_freertos_sem_buf) {
goto _error;
@@ -1215,28 +1222,28 @@ int npl_freertos_mempool_init(void)
_error:
#if CONFIG_BT_CONTROLLER_ENABLED
if(ble_freertos_evq_buf) {
if (ble_freertos_evq_buf) {
nimble_platform_mem_free(ble_freertos_evq_buf);
ble_freertos_evq_buf = NULL;
ble_freertos_evq_buf = NULL;
}
if(ble_freertos_co_buf) {
if (ble_freertos_co_buf) {
nimble_platform_mem_free(ble_freertos_co_buf);
ble_freertos_co_buf = NULL;
ble_freertos_co_buf = NULL;
}
if(ble_freertos_sem_buf) {
if (ble_freertos_sem_buf) {
nimble_platform_mem_free(ble_freertos_sem_buf);
ble_freertos_sem_buf = NULL;
ble_freertos_sem_buf = NULL;
}
if(ble_freertos_mutex_buf) {
if (ble_freertos_mutex_buf) {
nimble_platform_mem_free(ble_freertos_mutex_buf);
ble_freertos_mutex_buf = NULL;
ble_freertos_mutex_buf = NULL;
}
#endif
#if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED
if(ble_freertos_ev_buf) {
if (ble_freertos_ev_buf) {
nimble_platform_mem_free(ble_freertos_ev_buf);
ble_freertos_ev_buf = NULL;
ble_freertos_ev_buf = NULL;
}
return -1;
#endif
@@ -1248,28 +1255,28 @@ _error:
void npl_freertos_mempool_deinit(void)
{
#if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED
if(ble_freertos_ev_buf) {
if (ble_freertos_ev_buf) {
nimble_platform_mem_free(ble_freertos_ev_buf);
ble_freertos_ev_buf = NULL;
ble_freertos_ev_buf = NULL;
}
#endif
#if CONFIG_BT_CONTROLLER_ENABLED
if(ble_freertos_evq_buf) {
if (ble_freertos_evq_buf) {
nimble_platform_mem_free(ble_freertos_evq_buf);
ble_freertos_evq_buf = NULL;
ble_freertos_evq_buf = NULL;
}
if(ble_freertos_co_buf) {
if (ble_freertos_co_buf) {
nimble_platform_mem_free(ble_freertos_co_buf);
ble_freertos_co_buf = NULL;
ble_freertos_co_buf = NULL;
}
if(ble_freertos_sem_buf) {
if (ble_freertos_sem_buf) {
nimble_platform_mem_free(ble_freertos_sem_buf);
ble_freertos_sem_buf = NULL;
ble_freertos_sem_buf = NULL;
}
if(ble_freertos_mutex_buf) {
if (ble_freertos_mutex_buf) {
nimble_platform_mem_free(ble_freertos_mutex_buf);
ble_freertos_mutex_buf = NULL;
ble_freertos_mutex_buf = NULL;
}
#endif
}