mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-07-15 08:32:42 +08:00
feat(heap): Add new heap component
This commit is contained in:
@ -26,6 +26,7 @@
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_phy_init.h"
|
||||
#include "esp_wifi_osi.h"
|
||||
#include "esp_heap_caps_init.h"
|
||||
#include "internal/esp_wifi_internal.h"
|
||||
|
||||
#define FLASH_MAP_ADDR 0x40200000
|
||||
@ -109,6 +110,8 @@ void call_user_start(size_t start_addr)
|
||||
"movi a2, 0xffffff00\n"
|
||||
"and a1, a1, a2\n");
|
||||
|
||||
heap_caps_init();
|
||||
|
||||
wifi_os_init();
|
||||
|
||||
assert(wifi_task_create(user_init_entry, "uiT", 2048, NULL, wifi_task_get_max_priority()) != NULL);
|
||||
|
7
components/heap/component.mk
Normal file
7
components/heap/component.mk
Normal file
@ -0,0 +1,7 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := include port/esp8266/include
|
||||
|
||||
COMPONENT_SRCDIRS := src port/esp8266
|
197
components/heap/include/esp_heap_caps.h
Normal file
197
components/heap/include/esp_heap_caps.h
Normal file
@ -0,0 +1,197 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "esp_heap_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get "HEAP_ALIGN_SIZE" bytes aligned data(HEAP_ALIGN(ptr) >= ptr).
|
||||
*/
|
||||
#define HEAP_ALIGN(ptr) (((size_t)ptr + (HEAP_ALIGN_SIZE - 1)) & ~(HEAP_ALIGN_SIZE - 1))
|
||||
|
||||
#define MALLOC_CAP_32BIT (1 << 1) ///< Memory must allow for aligned 32-bit data accesses
|
||||
#define MALLOC_CAP_8BIT (1 << 2) ///< Memory must allow for 8-bit data accesses
|
||||
#define MALLOC_CAP_DMA (1 << 3) ///< Memory must be able to accessed by DMA
|
||||
|
||||
#define MEM_BLK_TAG 0x80000000 ///< Mark the memory block used
|
||||
#define MEM_BLK_TRACE 0x80000000 ///< Mark the memory block traced
|
||||
|
||||
#define MEM_HEAD_SIZE sizeof(mem_blk_t) ///< Size of first type memory block
|
||||
#define MEM2_HEAD_SIZE sizeof(mem2_blk_t) ///< Size of second type memory block
|
||||
|
||||
/**
|
||||
* First type memory block.
|
||||
*/
|
||||
typedef struct mem_blk {
|
||||
struct mem_blk *prev; ///< Point to previous memory block
|
||||
struct mem_blk *next; ///< Point to next memory block
|
||||
} mem_blk_t;
|
||||
|
||||
/**
|
||||
* Second type memory block.
|
||||
*/
|
||||
typedef struct mem_blk2 {
|
||||
struct mem_blk2 *prev; ///< Point to previous memory block
|
||||
struct mem_blk2 *next; ///< Point to next memory block
|
||||
|
||||
const char *file; ///< Which "file" allocate the memory block
|
||||
size_t line; ///< Which "line" allocate the memory block
|
||||
} mem2_blk_t;
|
||||
|
||||
/**
|
||||
* User region information.
|
||||
*/
|
||||
typedef struct heap_region {
|
||||
void *start_addr; ///< Heap region start address
|
||||
size_t total_size; ///< Heap region total size by byte
|
||||
|
||||
uint32_t caps; ///< Heap capacity
|
||||
|
||||
void *free_blk; ///< First free memory block
|
||||
|
||||
size_t free_bytes; ///< Current free heap size by byte
|
||||
|
||||
size_t min_free_bytes; ///< Minimum free heap size by byte ever
|
||||
} heap_region_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the total free size of all the regions that have the given capabilities
|
||||
*
|
||||
* This function takes all regions capable of having the given capabilities allocated in them
|
||||
* and adds up the free space they have.
|
||||
*
|
||||
* @param caps Bitwise OR of MALLOC_CAP_* flags indicating the type of memory
|
||||
*
|
||||
* @return Amount of free bytes in the regions
|
||||
*/
|
||||
size_t heap_caps_get_free_size(uint32_t caps);
|
||||
|
||||
/**
|
||||
* @brief Get the total minimum free memory of all regions with the given capabilities
|
||||
*
|
||||
* This adds all the low water marks of the regions capable of delivering the memory
|
||||
* with the given capabilities.
|
||||
*
|
||||
* @param caps Bitwise OR of MALLOC_CAP_* flags indicating the type of memory
|
||||
*
|
||||
* @return Amount of free bytes in the regions
|
||||
*/
|
||||
size_t heap_caps_get_minimum_free_size(uint32_t caps);
|
||||
|
||||
/**
|
||||
* @brief Initialize regions of memory to the collection of heaps at runtime.
|
||||
*
|
||||
* @param region region table head point
|
||||
* @param max_num region table size
|
||||
*/
|
||||
void esp_heap_caps_init_region(heap_region_t *region, size_t max_num);
|
||||
|
||||
/**
|
||||
* @brief Allocate a chunk of memory which has the given capabilities
|
||||
*
|
||||
* Equivalent semantics to libc malloc(), for capability-aware memory.
|
||||
*
|
||||
* In SDK, ``malloc(s)`` is equivalent to ``heap_caps_malloc(s, MALLOC_CAP_32BIT)``.
|
||||
*
|
||||
* @param size Size, in bytes, of the amount of memory to allocate
|
||||
* @param caps Bitwise OR of MALLOC_CAP_* flags indicating the type of memory to be returned
|
||||
*
|
||||
* @return A pointer to the memory allocated on success, NULL on failure
|
||||
*/
|
||||
#define heap_caps_malloc(size, caps) _heap_caps_malloc(size, caps, __FILE__, __LINE__)
|
||||
|
||||
void *_heap_caps_malloc(size_t size, uint32_t caps, const char *file, size_t line);
|
||||
|
||||
/**
|
||||
* @brief Free memory previously allocated via heap_caps_(m/c/re/z)alloc().
|
||||
*
|
||||
* Equivalent semantics to libc free(), for capability-aware memory.
|
||||
*
|
||||
* In SDK, ``free(p)`` is equivalent to ``heap_caps_free(p)``.
|
||||
*
|
||||
* @param ptr Pointer to memory previously returned from heap_caps_(m/c/re/z)alloc(). Can be NULL.
|
||||
*/
|
||||
#define heap_caps_free(p) _heap_caps_free(p, __FILE__, __LINE__)
|
||||
|
||||
void _heap_caps_free(void *ptr, const char *file, size_t line);
|
||||
|
||||
/**
|
||||
* @brief Allocate a chunk of memory which has the given capabilities. The initialized value in the memory is set to zero.
|
||||
*
|
||||
* Equivalent semantics to libc calloc(), for capability-aware memory.
|
||||
*
|
||||
* In IDF, ``calloc(c, s)`` is equivalent to ``heap_caps_calloc(c, s, MALLOC_CAP_32BIT)``.
|
||||
*
|
||||
* @param n Number of continuing chunks of memory to allocate
|
||||
* @param size Size, in bytes, of a chunk of memory to allocate
|
||||
* @param caps Bitwise OR of MALLOC_CAP_* flags indicating the type of memory to be returned
|
||||
*
|
||||
* @return A pointer to the memory allocated on success, NULL on failure
|
||||
*/
|
||||
#define heap_caps_calloc(n, size, caps) _heap_caps_calloc(n, size, caps, __FILE__, __LINE__)
|
||||
|
||||
void *_heap_caps_calloc(size_t count, size_t size, uint32_t caps, const char *file, size_t line);
|
||||
|
||||
/**
|
||||
* @brief Reallocate memory previously allocated via heap_caps_(m/c/re/z)alloc().
|
||||
*
|
||||
* Equivalent semantics to libc realloc(), for capability-aware memory.
|
||||
*
|
||||
* In SDK, ``realloc(p, s)`` is equivalent to ``heap_caps_realloc(p, s, MALLOC_CAP_32BIT)``.
|
||||
*
|
||||
* 'caps' parameter can be different to the capabilities that any original 'ptr' was allocated with. In this way,
|
||||
* realloc can be used to "move" a buffer if necessary to ensure it meets a new set of capabilities.
|
||||
*
|
||||
* @param ptr Pointer to previously allocated memory, or NULL for a new allocation.
|
||||
* @param size Size of the new buffer requested, or 0 to free the buffer.
|
||||
* @param caps Bitwise OR of MALLOC_CAP_* flags indicating the type of memory desired for the new allocation.
|
||||
*
|
||||
* @return Pointer to a new buffer of size 'size' with capabilities 'caps', or NULL if allocation failed.
|
||||
*/
|
||||
#define heap_caps_realloc(ptr, size, caps) _heap_caps_realloc(ptr, size, caps, __FILE__, __LINE__)
|
||||
|
||||
void *_heap_caps_realloc(void *mem, size_t newsize, uint32_t caps, const char *file, size_t line);
|
||||
|
||||
/**
|
||||
* @brief Allocate a chunk of memory which has the given capabilities. The initialized value in the memory is set to zero.
|
||||
*
|
||||
* Equivalent semantics to libc calloc(), for capability-aware memory.
|
||||
*
|
||||
* In IDF, ``calloc(c, s)`` is equivalent to ``heap_caps_calloc(c, s, MALLOC_CAP_32BIT)``.
|
||||
*
|
||||
* @param n Number of continuing chunks of memory to allocate
|
||||
* @param size Size, in bytes, of a chunk of memory to allocate
|
||||
* @param caps Bitwise OR of MALLOC_CAP_* flags indicating the type of memory to be returned
|
||||
*
|
||||
* @return A pointer to the memory allocated on success, NULL on failure
|
||||
*/
|
||||
#define heap_caps_zalloc(size, caps) _heap_caps_zalloc(size, caps, __FILE__, __LINE__)
|
||||
|
||||
void *_heap_caps_zalloc(size_t size, uint32_t caps, const char *file, size_t line);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
31
components/heap/include/esp_heap_caps_init.h
Normal file
31
components/heap/include/esp_heap_caps_init.h
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize the capability-aware heap allocator.
|
||||
*
|
||||
* This is called once in the ESP8266 startup code. Do not call it
|
||||
* at other times.
|
||||
*/
|
||||
void heap_caps_init();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
82
components/heap/include/esp_heap_trace.h
Normal file
82
components/heap/include/esp_heap_trace.h
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
HEAP_TRACE_NONE = 0,
|
||||
|
||||
HEAP_TRACE_LEAKS,
|
||||
} heap_trace_mode_t;
|
||||
|
||||
typedef struct {
|
||||
char buf[1];
|
||||
} heap_trace_record_t;
|
||||
|
||||
/**
|
||||
* @brief Check if heap trace is on
|
||||
*
|
||||
* @return true if on or false
|
||||
*/
|
||||
int heap_trace_is_on(void);
|
||||
|
||||
/**
|
||||
* @brief Empty function just for passing compiling some place.
|
||||
*/
|
||||
esp_err_t heap_trace_init_standalone(heap_trace_record_t *record_buffer, size_t num_records);
|
||||
|
||||
/**
|
||||
* @brief Start heap tracing. All heap allocations will be traced, until heap_trace_stop() is called.
|
||||
*
|
||||
* @param mode Mode for tracing.
|
||||
* - HEAP_TRACE_LEAKS means only suspected memory leaks are traced. (When memory is freed, the record is removed from the trace buffer.)
|
||||
* @return
|
||||
* - ESP_OK Tracing is started.
|
||||
*/
|
||||
esp_err_t heap_trace_start(heap_trace_mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Stop heap tracing.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Heap tracing stopped..
|
||||
*/
|
||||
esp_err_t heap_trace_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Resume heap tracing which was previously stopped.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_NOT_SUPPORTED Project was compiled without heap tracing enabled in menuconfig.
|
||||
* - ESP_OK Heap tracing resumed.
|
||||
*/
|
||||
esp_err_t heap_trace_resume(void);
|
||||
|
||||
/**
|
||||
* @brief Dump heap trace record data to stdout
|
||||
*
|
||||
* @note It is safe to call this function while heap tracing is running, however in HEAP_TRACE_LEAK mode the dump may skip
|
||||
* entries unless heap tracing is stopped first.
|
||||
*/
|
||||
void heap_trace_dump(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
154
components/heap/include/priv/esp_heap_caps_priv.h
Normal file
154
components/heap/include/priv/esp_heap_caps_priv.h
Normal file
@ -0,0 +1,154 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _mem_blk_get_ptr(_mem_blk, _offset, _mask) \
|
||||
((mem_blk_t *)((((uint32_t *)(_mem_blk))[_offset]) & (~_mask)))
|
||||
|
||||
#define _mem_blk_set_ptr(_mem_blk, _val, _offset, _mask) \
|
||||
{ \
|
||||
uint32_t *__p = (uint32_t *)(_mem_blk); \
|
||||
uint32_t __bits = __p[_offset] & (_mask); \
|
||||
\
|
||||
__p[_offset] = (uint32_t)(_val) | __bits; \
|
||||
}
|
||||
|
||||
#define mem_blk_prev(_mem_blk) _mem_blk_get_ptr(_mem_blk, 0, MEM_BLK_TAG)
|
||||
#define mem_blk_next(_mem_blk) _mem_blk_get_ptr(_mem_blk, 1, MEM_BLK_TRACE)
|
||||
|
||||
#define mem_blk_set_prev(_mem_blk, _prev) _mem_blk_set_ptr(_mem_blk, _prev, 0, MEM_BLK_TAG)
|
||||
#define mem_blk_set_next(_mem_blk, _next) _mem_blk_set_ptr(_mem_blk, _next, 1, MEM_BLK_TRACE)
|
||||
|
||||
static inline size_t mem_blk_head_size(bool trace)
|
||||
{
|
||||
return trace ? MEM2_HEAD_SIZE : MEM_HEAD_SIZE;
|
||||
}
|
||||
|
||||
static inline void mem_blk_set_traced(mem2_blk_t *mem_blk, const char *file, size_t line)
|
||||
{
|
||||
uint32_t *val = (uint32_t *)mem_blk + 1;
|
||||
|
||||
*val |= MEM_BLK_TRACE;
|
||||
|
||||
mem_blk->file = file;
|
||||
mem_blk->line = line;
|
||||
}
|
||||
|
||||
static inline void mem_blk_set_untraced(mem2_blk_t *mem_blk)
|
||||
{
|
||||
uint32_t *val = (uint32_t *)mem_blk + 1;
|
||||
|
||||
*val &= ~MEM_BLK_TRACE;
|
||||
}
|
||||
|
||||
static inline int mem_blk_is_traced(mem_blk_t *mem_blk)
|
||||
{
|
||||
uint32_t *val = (uint32_t *)mem_blk + 1;
|
||||
|
||||
return *val & MEM_BLK_TRACE;
|
||||
}
|
||||
|
||||
static inline void mem_blk_set_used(mem_blk_t *mem_blk)
|
||||
{
|
||||
uint32_t *val = (uint32_t *)mem_blk;
|
||||
|
||||
*val |= MEM_BLK_TAG;
|
||||
}
|
||||
|
||||
static inline void mem_blk_set_unused(mem_blk_t *mem_blk)
|
||||
{
|
||||
uint32_t *val = (uint32_t *)mem_blk;
|
||||
|
||||
*val &= ~MEM_BLK_TAG;
|
||||
}
|
||||
|
||||
static inline int mem_blk_is_used(mem_blk_t *mem_blk)
|
||||
{
|
||||
uint32_t *val = (uint32_t *)mem_blk;
|
||||
|
||||
return *val & MEM_BLK_TAG;
|
||||
}
|
||||
|
||||
static inline int mem_blk_is_end(mem_blk_t *mem_blk)
|
||||
{
|
||||
return mem_blk_next(mem_blk) == NULL;
|
||||
}
|
||||
|
||||
static inline size_t blk_link_size(mem_blk_t *blk)
|
||||
{
|
||||
return (size_t)mem_blk_next(blk) - (size_t)blk;
|
||||
}
|
||||
|
||||
static inline size_t get_blk_region(void *ptr)
|
||||
{
|
||||
size_t num;
|
||||
extern heap_region_t g_heap_region[HEAP_REGIONS_MAX];
|
||||
|
||||
for (num = 0; num < HEAP_REGIONS_MAX; num++) {
|
||||
if ((uint8_t *)ptr > (uint8_t *)g_heap_region[num].start_addr
|
||||
&& (uint8_t *)ptr < ((uint8_t *)g_heap_region[num].start_addr + g_heap_region[num].total_size)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static inline size_t ptr2memblk_size(size_t size, bool trace)
|
||||
{
|
||||
size_t head_size = trace ? MEM2_HEAD_SIZE : MEM_HEAD_SIZE;
|
||||
|
||||
return HEAP_ALIGN(size + head_size);
|
||||
}
|
||||
|
||||
static inline bool ptr_is_traced(void *ptr)
|
||||
{
|
||||
uint32_t *p = (uint32_t *)ptr - 1;
|
||||
|
||||
return p[0] & 0xf0000000 ? (p[0] == 0xffffffff ? true : false) : true;
|
||||
}
|
||||
|
||||
static inline mem_blk_t *ptr2blk(void *ptr, bool trace)
|
||||
{
|
||||
size_t head_size = trace ? MEM2_HEAD_SIZE : MEM_HEAD_SIZE;
|
||||
|
||||
return (mem_blk_t *)((uint8_t *)ptr - head_size);
|
||||
}
|
||||
|
||||
static inline void *blk2ptr(mem_blk_t *mem_blk, bool trace)
|
||||
{
|
||||
size_t head_size = trace ? MEM2_HEAD_SIZE : MEM_HEAD_SIZE;
|
||||
|
||||
return (void *)((uint8_t *)mem_blk + head_size);
|
||||
}
|
||||
|
||||
static inline size_t ptr_size(void *ptr)
|
||||
{
|
||||
bool trancd = ptr_is_traced(ptr);
|
||||
mem_blk_t *blk_mem = ptr2blk(ptr, trancd);
|
||||
size_t size = blk_link_size(blk_mem) - mem_blk_head_size(trancd);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
38
components/heap/port/esp8266/esp_heap_init.c
Normal file
38
components/heap/port/esp8266/esp_heap_init.c
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
heap_region_t g_heap_region[HEAP_REGIONS_MAX];
|
||||
|
||||
/**
|
||||
* @brief Initialize the capability-aware heap allocator.
|
||||
*/
|
||||
void heap_caps_init(void)
|
||||
{
|
||||
extern char _heap_start;
|
||||
extern char _lit4_end;
|
||||
|
||||
#ifndef CONFIG_SOC_FULL_ICACHE
|
||||
g_heap_region[0].start_addr = (uint8_t *)&_lit4_end;
|
||||
g_heap_region[0].total_size = ((size_t)(0x4010C000 - (uint32_t)&_lit4_end));
|
||||
g_heap_region[0].caps = MALLOC_CAP_32BIT;
|
||||
#endif
|
||||
|
||||
g_heap_region[1].start_addr = (uint8_t *)&_heap_start;
|
||||
g_heap_region[1].total_size = ((size_t)(0x40000000 - (uint32_t)&_heap_start));
|
||||
g_heap_region[1].caps = MALLOC_CAP_8BIT | MALLOC_CAP_32BIT | MALLOC_CAP_DMA;
|
||||
|
||||
esp_heap_caps_init_region(g_heap_region, HEAP_REGIONS_MAX);
|
||||
}
|
23
components/heap/port/esp8266/include/esp_heap_config.h
Normal file
23
components/heap/port/esp8266/include/esp_heap_config.h
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define HEAP_ALIGN_SIZE 4
|
||||
|
||||
#define HEAP_REGIONS_MAX 2
|
||||
|
||||
#define MEM_BLK_MIN 1
|
34
components/heap/port/esp8266/include/esp_heap_port.h
Normal file
34
components/heap/port/esp8266/include/esp_heap_port.h
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _heap_caps_lock(_num) \
|
||||
{ \
|
||||
extern void vPortETSIntrLock(void); \
|
||||
vPortETSIntrLock(); \
|
||||
}
|
||||
|
||||
#define _heap_caps_unlock(_num) \
|
||||
{ \
|
||||
extern void vPortETSIntrUnlock(void); \
|
||||
vPortETSIntrUnlock(); \
|
||||
}
|
||||
|
||||
#define _heap_caps_feed_wdt(_num) \
|
||||
{ \
|
||||
extern void pp_soft_wdt_feed(void); \
|
||||
pp_soft_wdt_feed(); \
|
||||
}
|
||||
|
329
components/heap/src/esp_heap_caps.c
Normal file
329
components/heap/src/esp_heap_caps.c
Normal file
@ -0,0 +1,329 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_heap_port.h"
|
||||
#include "esp_heap_trace.h"
|
||||
#include "priv/esp_heap_caps_priv.h"
|
||||
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_NONE
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "heap_caps";
|
||||
extern heap_region_t g_heap_region[HEAP_REGIONS_MAX];
|
||||
|
||||
/**
|
||||
* @brief Initialize regions of memory to the collection of heaps at runtime.
|
||||
*/
|
||||
void esp_heap_caps_init_region(heap_region_t *region, size_t max_num)
|
||||
{
|
||||
uint8_t num;
|
||||
mem_blk_t *mem_start, *mem_end;
|
||||
|
||||
for (num = 0; num < max_num; num++) {
|
||||
mem_start = (mem_blk_t *)HEAP_ALIGN(region[num].start_addr);
|
||||
mem_end = (mem_blk_t *)(HEAP_ALIGN(region[num].start_addr + region[num].total_size));
|
||||
if ((uint8_t *)mem_end != region[num].start_addr + region[num].total_size)
|
||||
mem_end = (mem_blk_t *)((uint8_t *)mem_end - sizeof(void *));
|
||||
mem_end = (mem_blk_t *)((uint8_t *)mem_end - MEM_HEAD_SIZE);
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "heap %d start from %p to %p total %d bytes, mem_blk from %p to %p total",
|
||||
num, region[num].start_addr, region[num].start_addr + region[num].total_size,
|
||||
region[num].total_size, mem_start, mem_end);
|
||||
|
||||
mem_start->prev = NULL;
|
||||
mem_start->next = mem_end;
|
||||
|
||||
mem_end->prev = mem_start;
|
||||
mem_end->next = NULL;
|
||||
|
||||
g_heap_region[num].free_blk = mem_start;
|
||||
g_heap_region[num].min_free_bytes = g_heap_region[num].free_bytes = blk_link_size(mem_start);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the total free size of all the regions that have the given capabilities
|
||||
*/
|
||||
size_t heap_caps_get_free_size(uint32_t caps)
|
||||
{
|
||||
size_t bytes = 0;
|
||||
|
||||
for (int i = 0; i < HEAP_REGIONS_MAX; i++)
|
||||
if (caps == (caps & g_heap_region[i].caps))
|
||||
bytes += g_heap_region[i].free_bytes;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the total minimum free memory of all regions with the given capabilities
|
||||
*/
|
||||
size_t heap_caps_get_minimum_free_size(uint32_t caps)
|
||||
{
|
||||
size_t bytes = 0;
|
||||
|
||||
for (int i = 0; i < HEAP_REGIONS_MAX; i++)
|
||||
if (caps == (caps & g_heap_region[i].caps))
|
||||
bytes += g_heap_region[i].min_free_bytes;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate a chunk of memory which has the given capabilities
|
||||
*/
|
||||
void *_heap_caps_malloc(size_t size, uint32_t caps, const char *file, size_t line)
|
||||
{
|
||||
mem_blk_t *mem_blk, *next_mem_blk;
|
||||
void *ret_mem = NULL;
|
||||
uint32_t num;
|
||||
uint32_t mem_blk_size;
|
||||
|
||||
if (line == 0) {
|
||||
ESP_EARLY_LOGV(TAG, "caller func %p", file);
|
||||
} else {
|
||||
ESP_EARLY_LOGV(TAG, "caller file %s line %d", file, line);
|
||||
}
|
||||
|
||||
for (num = 0; num < HEAP_REGIONS_MAX; num++) {
|
||||
bool trace;
|
||||
size_t head_size;
|
||||
|
||||
if ((g_heap_region[num].caps & caps) != caps)
|
||||
continue;
|
||||
|
||||
_heap_caps_lock(num);
|
||||
|
||||
trace = heap_trace_is_on();
|
||||
|
||||
mem_blk_size = ptr2memblk_size(size, trace);
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "malloc size is %d(%x) blk size is %d(%x) region is %d", size, size,
|
||||
mem_blk_size, mem_blk_size, num);
|
||||
|
||||
if (mem_blk_size > g_heap_region[num].free_bytes)
|
||||
goto next_region;
|
||||
|
||||
mem_blk = (mem_blk_t *)g_heap_region[num].free_blk;
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "malloc start %p", mem_blk);
|
||||
|
||||
while (mem_blk && !mem_blk_is_end(mem_blk) && (mem_blk_is_used(mem_blk) || blk_link_size(mem_blk) < mem_blk_size)) {
|
||||
ESP_EARLY_LOGV(TAG, "malloc mem_blk %p next %p used %x traced %x, size %d", mem_blk, mem_blk_next(mem_blk),
|
||||
mem_blk_is_used(mem_blk), mem_blk_is_traced(mem_blk), blk_link_size(mem_blk));
|
||||
mem_blk = mem_blk_next(mem_blk);
|
||||
}
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "malloc end %p, end %d", mem_blk, mem_blk_is_end(mem_blk));
|
||||
|
||||
if (!mem_blk || mem_blk_is_end(mem_blk))
|
||||
goto next_region;
|
||||
|
||||
ret_mem = blk2ptr(mem_blk, trace);
|
||||
ESP_EARLY_LOGV(TAG, "ret_mem is %p", ret_mem);
|
||||
|
||||
head_size = mem_blk_head_size(trace);
|
||||
|
||||
if (blk_link_size(mem_blk) >= mem_blk_size + head_size + MEM_BLK_MIN)
|
||||
next_mem_blk = (mem_blk_t *)((uint8_t *)mem_blk + mem_blk_size);
|
||||
else
|
||||
next_mem_blk = mem_blk_next(mem_blk);
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "next_mem_blk is %p", next_mem_blk);
|
||||
|
||||
if (mem_blk_next(mem_blk) != next_mem_blk) {
|
||||
next_mem_blk->prev = next_mem_blk->next = NULL;
|
||||
|
||||
mem_blk_set_prev(next_mem_blk, mem_blk);
|
||||
mem_blk_set_next(next_mem_blk, mem_blk_next(mem_blk));
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "mem_blk1 %p, mem_blk->prev %p(%p), mem_blk->next %p(%p)", mem_blk, mem_blk_prev(mem_blk),
|
||||
mem_blk->prev, mem_blk_next(mem_blk), mem_blk->next);
|
||||
|
||||
mem_blk_set_prev(mem_blk_next(mem_blk), next_mem_blk);
|
||||
mem_blk_set_next(mem_blk, next_mem_blk);
|
||||
}
|
||||
|
||||
mem_blk_set_used(mem_blk);
|
||||
if (trace) {
|
||||
mem_blk_set_traced((mem2_blk_t *)mem_blk, file, line);
|
||||
ESP_EARLY_LOGV(TAG, "mem_blk1 %p set trace", mem_blk);
|
||||
}
|
||||
|
||||
if (g_heap_region[num].free_blk == mem_blk) {
|
||||
mem_blk_t *free_blk = mem_blk;
|
||||
|
||||
while (free_blk && !mem_blk_is_end(free_blk) && mem_blk_is_used(free_blk)) {
|
||||
free_blk = mem_blk_next(free_blk);
|
||||
}
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "reset free_blk from %p to %p", g_heap_region[num].free_blk, free_blk);
|
||||
g_heap_region[num].free_blk = free_blk;
|
||||
} else {
|
||||
ESP_EARLY_LOGV(TAG, "free_blk is %p", g_heap_region[num].free_blk);
|
||||
}
|
||||
|
||||
g_heap_region[num].free_bytes -= mem_blk_size;
|
||||
|
||||
if (g_heap_region[num].min_free_bytes > g_heap_region[num].free_bytes)
|
||||
g_heap_region[num].min_free_bytes = g_heap_region[num].free_bytes;
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "mem_blk2 %p, mem_blk->prev %p(%p), mem_blk->next %p(%p)", mem_blk, mem_blk_prev(mem_blk),
|
||||
mem_blk->prev, mem_blk_next(mem_blk), mem_blk->next);
|
||||
ESP_EARLY_LOGV(TAG, "next_mem_blk %p, next_mem_blk->prev %p(%p), next_mem_blk->next %p(%p)", next_mem_blk,
|
||||
mem_blk_prev(next_mem_blk), next_mem_blk->prev, mem_blk_next(next_mem_blk), next_mem_blk->next);
|
||||
ESP_EARLY_LOGV(TAG, "last_mem_blk %p, last_mem_blk->prev %p(%p), last_mem_blk->next %p(%p)", mem_blk_next(next_mem_blk),
|
||||
mem_blk_next(next_mem_blk)->prev, mem_blk_prev(mem_blk_next(next_mem_blk)), mem_blk_next(mem_blk_next(next_mem_blk)), mem_blk_next(next_mem_blk)->next);
|
||||
|
||||
next_region:
|
||||
_heap_caps_unlock(num);
|
||||
|
||||
if (ret_mem)
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "malloc return mem %p", ret_mem);
|
||||
|
||||
return ret_mem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free memory previously allocated via heap_caps_(m/c/r/z)alloc().
|
||||
*/
|
||||
void _heap_caps_free(void *ptr, const char *file, size_t line)
|
||||
{
|
||||
int num;
|
||||
mem_blk_t *mem_blk;
|
||||
mem_blk_t *tmp, *next, *prev, *last;
|
||||
|
||||
if ((int)line == 0) {
|
||||
ESP_EARLY_LOGV(TAG, "caller func %p", file);
|
||||
} else {
|
||||
ESP_EARLY_LOGV(TAG, "caller file %s line %d", file, line);
|
||||
}
|
||||
|
||||
if (!ptr) {
|
||||
ESP_EARLY_LOGE(TAG, "free(ptr=NULL)");
|
||||
if ((int)line == 0) {
|
||||
ESP_EARLY_LOGE(TAG, "caller func %p", file);
|
||||
} else {
|
||||
ESP_EARLY_LOGE(TAG, "caller file %s line %d", file, line);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
num = get_blk_region(ptr);
|
||||
|
||||
if (num >= HEAP_REGIONS_MAX) {
|
||||
ESP_EARLY_LOGE(TAG, "free(ptr_region=NULL)");
|
||||
return;
|
||||
}
|
||||
|
||||
mem_blk = ptr2blk(ptr, ptr_is_traced(ptr));
|
||||
#ifndef MEMLEAK_DEBUG
|
||||
if (mem_blk->prev) {
|
||||
ESP_EARLY_LOGE("%p already freed\n", ptr);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "Free(ptr=%p, mem_blk=%p, region=%d)", ptr, mem_blk, num);
|
||||
|
||||
_heap_caps_lock(num);
|
||||
|
||||
g_heap_region[num].free_bytes += blk_link_size(mem_blk);
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "ptr prev=%p next=%p", mem_blk_prev(mem_blk), mem_blk_next(mem_blk));
|
||||
ESP_EARLY_LOGV(TAG, "ptr1 prev->next=%p next->prev=%p", mem_blk_prev(mem_blk) ? mem_blk_next(mem_blk_prev(mem_blk)) : NULL,
|
||||
mem_blk_prev(mem_blk_next(mem_blk)));
|
||||
|
||||
mem_blk_set_unused(mem_blk);
|
||||
mem_blk_set_untraced((mem2_blk_t *)mem_blk);
|
||||
|
||||
prev = mem_blk_prev(mem_blk);
|
||||
next = mem_blk_next(mem_blk);
|
||||
last = mem_blk_next(next);
|
||||
|
||||
if (prev && !mem_blk_is_used(prev)) {
|
||||
mem_blk_set_next(prev, next);
|
||||
mem_blk_set_prev(next, prev);
|
||||
tmp = prev;
|
||||
} else
|
||||
tmp = mem_blk;
|
||||
|
||||
if (last && !mem_blk_is_used(next)) {
|
||||
mem_blk_set_next(tmp, last);
|
||||
mem_blk_set_prev(last, tmp);
|
||||
}
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "ptr2 prev->next=%p next->prev=%p", mem_blk_prev(mem_blk) ? mem_blk_next(mem_blk_prev(mem_blk)) : NULL,
|
||||
mem_blk_prev(mem_blk_next(mem_blk)));
|
||||
|
||||
if ((uint8_t *)mem_blk < (uint8_t *)g_heap_region[num].free_blk) {
|
||||
ESP_EARLY_LOGV(TAG, "Free update free block from %p to %p", g_heap_region[num].free_blk, mem_blk);
|
||||
g_heap_region[num].free_blk = mem_blk;
|
||||
}
|
||||
|
||||
_heap_caps_unlock(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate a chunk of memory which has the given capabilities. The initialized value in the memory is set to zero.
|
||||
*/
|
||||
void *_heap_caps_calloc(size_t count, size_t size, uint32_t caps, const char *file, size_t line)
|
||||
{
|
||||
void *p = _heap_caps_malloc(count * size, caps, file, line);
|
||||
if (p)
|
||||
memset(p, 0, count * size);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reallocate memory previously allocated via heap_caps_(m/c/r/z)alloc().
|
||||
*/
|
||||
void *_heap_caps_realloc(void *mem, size_t newsize, uint32_t caps, const char *file, size_t line)
|
||||
{
|
||||
void *return_addr = (void *)__builtin_return_address(0);
|
||||
|
||||
void *p = _heap_caps_malloc(newsize, caps, file, line);
|
||||
if (p && mem) {
|
||||
size_t mem_size = ptr_size(mem);
|
||||
size_t min = MIN(newsize, mem_size);
|
||||
|
||||
memcpy(p, mem, min);
|
||||
_heap_caps_free(mem, (char *)return_addr, line);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate a chunk of memory which has the given capabilities. The initialized value in the memory is set to zero.
|
||||
*/
|
||||
void *_heap_caps_zalloc(size_t size, uint32_t caps, const char *file, size_t line)
|
||||
{
|
||||
void *p = _heap_caps_malloc(size, caps, file, line);
|
||||
if (p)
|
||||
memset(p, 0, size);
|
||||
|
||||
return p;
|
||||
}
|
143
components/heap/src/esp_heap_trace.c
Normal file
143
components/heap/src/esp_heap_trace.c
Normal file
@ -0,0 +1,143 @@
|
||||
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_heap_port.h"
|
||||
#include "esp_heap_trace.h"
|
||||
#include "priv/esp_heap_caps_priv.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
//#define CONFIG_TRACE_ALL
|
||||
//#define CONFIG_TRACE_MEM_LINK 1
|
||||
//#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
|
||||
|
||||
#ifdef CONFIG_TRACE_ALL
|
||||
#define HEAP_INFO_STATE " is %s"
|
||||
#define HEAP_INFO_STATE_PARAM(_p) ,mem_blk_is_used(_p)?"used":"freed"
|
||||
#else
|
||||
#define HEAP_INFO_STATE ""
|
||||
#define HEAP_INFO_STATE_PARAM(_p)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TRACE_MEM_LINK
|
||||
#define HEAP_INFO "p %p, prev %p(%p) next %p(%p) size %d"HEAP_INFO_STATE
|
||||
#define HEAP_INFO_PARAM(_p) (_p),mem_blk_prev(_p),(_p)->prev,mem_blk_next(_p),(_p)->next,blk_link_size(_p)HEAP_INFO_STATE_PARAM(_p)
|
||||
#else
|
||||
#define HEAP_INFO "mem @%p size %d"HEAP_INFO_STATE
|
||||
#define HEAP_INFO_PARAM(_p) (_p),blk_link_size(_p)HEAP_INFO_STATE_PARAM(_p)
|
||||
#endif
|
||||
|
||||
static const char *TAG = "heap_trace";
|
||||
static int s_heap_trace_mode = HEAP_TRACE_NONE;
|
||||
extern heap_region_t g_heap_region[HEAP_REGIONS_MAX];
|
||||
|
||||
/**
|
||||
* @brief Empty function just for passing compiling some place.
|
||||
*/
|
||||
esp_err_t heap_trace_init_standalone(heap_trace_record_t *record_buffer, size_t num_records)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if heap trace is on
|
||||
*/
|
||||
int heap_trace_is_on(void)
|
||||
{
|
||||
return s_heap_trace_mode == HEAP_TRACE_LEAKS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start heap tracing. All heap allocations will be traced, until heap_trace_stop() is called.
|
||||
*/
|
||||
esp_err_t heap_trace_start(heap_trace_mode_t mode)
|
||||
{
|
||||
s_heap_trace_mode = mode;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop heap tracing.
|
||||
*/
|
||||
esp_err_t heap_trace_stop(void)
|
||||
{
|
||||
s_heap_trace_mode = HEAP_TRACE_NONE;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resume heap tracing which was previously stopped.
|
||||
*/
|
||||
esp_err_t heap_trace_resume(void)
|
||||
{
|
||||
s_heap_trace_mode = HEAP_TRACE_LEAKS;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dump heap trace record data to stdout
|
||||
*/
|
||||
void heap_trace_dump(void)
|
||||
{
|
||||
uint8_t num;
|
||||
mem_blk_t *mem_start, *mem_end, *p;
|
||||
|
||||
for (num = 0; num < HEAP_REGIONS_MAX; num++) {
|
||||
mem_start = (mem_blk_t *)HEAP_ALIGN(g_heap_region[num].start_addr);
|
||||
mem_end = (mem_blk_t *)(HEAP_ALIGN(g_heap_region[num].start_addr + g_heap_region[num].total_size));
|
||||
if ((uint8_t *)mem_end != g_heap_region[num].start_addr + g_heap_region[num].total_size)
|
||||
mem_end = (mem_blk_t *)((uint8_t *)mem_end - sizeof(void *));
|
||||
mem_end = (mem_blk_t *)((uint8_t *)mem_end - MEM_HEAD_SIZE);
|
||||
|
||||
_heap_caps_lock(num);
|
||||
|
||||
ESP_EARLY_LOGI(TAG, "\r\n\r\n");
|
||||
ESP_EARLY_LOGD(TAG, "start %p end %p", mem_start, mem_end);
|
||||
ESP_EARLY_LOGD(TAG, "free blk %p", g_heap_region[num].free_blk);
|
||||
ESP_EARLY_LOGD(TAG, "size %d mini size %d", g_heap_region[num].free_bytes, g_heap_region[num].min_free_bytes);
|
||||
|
||||
p = mem_start;
|
||||
while (p != mem_end) {
|
||||
if (mem_blk_is_used(p) && mem_blk_is_traced(p)) {
|
||||
mem2_blk_t *mem2_blk = (mem2_blk_t *)p;
|
||||
|
||||
if (mem2_blk->line == (size_t)-1) {
|
||||
ESP_EARLY_LOGI(TAG, HEAP_INFO " caller func %p", HEAP_INFO_PARAM(p), mem2_blk->file);
|
||||
} else {
|
||||
const char *file = rindex(mem2_blk->file, '/');
|
||||
if (file)
|
||||
file++;
|
||||
|
||||
ESP_EARLY_LOGI(TAG, HEAP_INFO " caller file %s line %d", HEAP_INFO_PARAM(p), file, mem2_blk->line);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_TRACE_ALL
|
||||
else {
|
||||
ESP_EARLY_LOGI(TAG, HEAP_INFO, HEAP_INFO_PARAM(p));
|
||||
}
|
||||
#endif
|
||||
p = mem_blk_next(p);
|
||||
|
||||
_heap_caps_feed_wdt(g_heap_region[num].caps & caps);
|
||||
}
|
||||
|
||||
_heap_caps_unlock(num);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user