Merge branch 'feature/refactor_heap' into 'master'

Refactor heap

See merge request sdk/ESP8266_RTOS_SDK!449
This commit is contained in:
Dong Heng
2018-09-12 11:14:47 +08:00
27 changed files with 1097 additions and 1074 deletions

View File

@ -54,4 +54,4 @@ target_compile_options(${COMPONENT_NAME} PUBLIC -Wno-error=char-subscripts -Wno-
-Wno-error=unused-value -Wno-error=address -Wno-error=return-type -Wno-error=format-extra-args
-Wno-error=format-zero-length -Wno-error=unused-label -Wno-error=sizeof-pointer-memaccess)
target_compile_options(${COMPONENT_NAME} PUBLIC -DMEMLEAK_DEBUG -DICACHE_FLASH)
target_compile_options(${COMPONENT_NAME} PUBLIC -DICACHE_FLASH)

View File

@ -65,4 +65,4 @@ endif # CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION
endif
# global CFLAGS for ESP8266
CFLAGS += -DMEMLEAK_DEBUG -DICACHE_FLASH
CFLAGS += -DICACHE_FLASH

View File

@ -29,6 +29,9 @@
#include <stddef.h>
#include <stdio.h>
#include <stdarg.h>
#ifndef BOOTLOADER_BUILD
#include "esp_heap_caps.h"
#endif
#ifdef __cplusplus
extern "C" {
@ -73,82 +76,24 @@ int ets_printf(const char *fmt, ...);
#define os_printf printf
#endif
/* Note: check_memleak_debug_enable is a weak function inside SDK.
* please copy following codes to user_main.c.
#include "esp_libc.h"
bool check_memleak_debug_enable(void)
{
return MEMLEAK_DEBUG_ENABLE;
}
*/
#ifndef MEMLEAK_DEBUG
#define MEMLEAK_DEBUG_ENABLE 0
#ifndef os_free
#define os_free(s) free(s)
#define os_free(s) heap_caps_free(s)
#endif
#ifndef os_malloc
#define os_malloc(s) malloc(s)
#define os_malloc(s) heap_caps_malloc(s, MALLOC_CAP_32BIT)
#endif
#ifndef os_calloc
#define os_calloc(p, s) calloc(p, s)
#define os_calloc(p, s) heap_caps_calloc(p, s, MALLOC_CAP_32BIT)
#endif
#ifndef os_realloc
#define os_realloc(p, s) realloc(p, s)
#define os_realloc(p, s) heap_caps_realloc(p, s, MALLOC_CAP_32BIT)
#endif
#ifndef os_zalloc
#define os_zalloc(s) zalloc(s)
#endif
#else
#define MEMLEAK_DEBUG_ENABLE 1
#ifndef os_free
#define os_free(s) \
do{\
vPortFree_trace(s, __FILE__, __LINE__);\
}while(0)
#endif
#ifndef os_malloc
#define os_malloc(s) \
({ \
pvPortMalloc_trace(s, __FILE__, __LINE__, false); \
})
#endif
#ifndef os_malloc_iram
#define os_malloc_iram(s) \
({ \
pvPortMalloc_trace(s, __FILE__, __LINE__, true); \
})
#endif
#ifndef os_calloc
#define os_calloc(p, s) \
({ \
pvPortCalloc_trace(p, s, __FILE__, __LINE__); \
})
#endif
#ifndef os_realloc
#define os_realloc(p, s) \
({ \
pvPortRealloc_trace(p, s, __FILE__, __LINE__); \
})
#endif
#ifndef os_zalloc
#define os_zalloc(s) \
({ \
pvPortZalloc_trace(s, __FILE__, __LINE__); \
})
#endif
#define os_zalloc(s) heap_caps_zalloc(s, MALLOC_CAP_32BIT)
#endif
#ifdef __cplusplus

View File

@ -274,75 +274,61 @@ static bool timer_delete_wrapper(void *timer, uint32_t ticks)
static void *malloc_wrapper(uint32_t s, uint32_t cap)
{
bool iram;
uint32_t os_caps;
void *return_addr = (void *)__builtin_return_address(0);
if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA))
iram = false;
os_caps = MALLOC_CAP_8BIT | MALLOC_CAP_DMA;
else
iram = true;
os_caps = MALLOC_CAP_32BIT;
return pvPortMalloc_trace(s, return_addr, (unsigned)-1, iram);
return _heap_caps_malloc(s, os_caps, return_addr, 0);
}
static void *zalloc_wrapper(uint32_t s, uint32_t cap)
{
bool iram;
uint32_t os_caps;
void *return_addr = (void *)__builtin_return_address(0);
if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA))
iram = false;
os_caps = MALLOC_CAP_8BIT | MALLOC_CAP_DMA;
else
iram = true;
os_caps = MALLOC_CAP_32BIT;
char *p = pvPortMalloc_trace(s, return_addr, (unsigned)-1, iram);
if (p)
memset(p, 0, s);
return p;
return _heap_caps_zalloc(s, os_caps, return_addr, 0);
}
static void *realloc_wrapper(void *ptr, uint32_t s, uint32_t cap)
{
bool iram;
uint32_t os_caps;
void *return_addr = (void *)__builtin_return_address(0);
if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA))
iram = false;
os_caps = MALLOC_CAP_8BIT | MALLOC_CAP_DMA;
else
iram = true;
os_caps = MALLOC_CAP_32BIT;
void *p = pvPortMalloc_trace(s, return_addr, (unsigned)-1, iram);
if (p && ptr) {
memcpy(p, ptr, s);
vPortFree_trace(ptr, return_addr, (unsigned)-1);
}
return p;
return _heap_caps_realloc(ptr, s, os_caps, return_addr, 0);
}
static void *calloc_wrapper(uint32_t cnt, uint32_t s, uint32_t cap)
{
bool iram;
uint32_t os_caps;
void *return_addr = (void *)__builtin_return_address(0);
if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA))
iram = false;
os_caps = MALLOC_CAP_8BIT | MALLOC_CAP_DMA;
else
iram = true;
os_caps = MALLOC_CAP_32BIT;
char *p = pvPortMalloc_trace(cnt * s, return_addr, (unsigned)-1, iram);
if (p)
memset(p, 0, cnt * s);
return p;
return _heap_caps_calloc(cnt , s, os_caps, return_addr, 0);
}
static void free_wrapper(void *ptr)
{
void *return_addr = (void *)__builtin_return_address(0);
vPortFree_trace(ptr, return_addr, (unsigned)-1);
_heap_caps_free(ptr, return_addr, 0);
}
static void srand_wrapper(uint32_t seed)

View File

@ -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);

View File

@ -339,7 +339,7 @@ void esp_chip_info(esp_chip_info_t* out_info)
*/
uint32_t esp_get_free_heap_size(void)
{
return xPortGetFreeHeapSize();
return heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
/**
@ -347,5 +347,5 @@ uint32_t esp_get_free_heap_size(void)
*/
uint32_t esp_get_minimum_free_heap_size(void)
{
return xPortGetMinimumEverFreeHeapSize();
return heap_caps_get_minimum_free_size(MALLOC_CAP_32BIT);
}

View File

@ -89,6 +89,7 @@ extern "C" {
#endif
#include "mpu_wrappers.h"
#include "esp_heap_caps.h"
/*
* Setup the stack of a new task so it is ready to be placed under the
@ -102,49 +103,14 @@ extern "C" {
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) PRIVILEGED_FUNCTION;
#endif
/* Used by heap_5.c. */
typedef struct HeapRegion
{
uint8_t *pucStartAddress;
size_t xSizeInBytes;
} HeapRegion_t;
#define pvMALLOC_DRAM (MALLOC_CAP_8BIT | MALLOC_CAP_32BIT | MALLOC_CAP_DMA)
#define pvMALLOC_IRAM (MALLOC_CAP_32BIT)
/*
* Used to define multiple heap regions for use by heap_5.c. This function
* must be called before any calls to pvPortMalloc() - not creating a task,
* queue, semaphore, mutex, software timer, event group, etc. will result in
* pvPortMalloc being called.
*
* pxHeapRegions passes in an array of HeapRegion_t structures - each of which
* defines a region of memory that can be used as the heap. The array is
* terminated by a HeapRegions_t structure that has a size of 0. The region
* with the lowest start address must appear first in the array.
*/
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) PRIVILEGED_FUNCTION;
/*
* Map to the memory management routines required for the port.
*/
void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION;
void *pvPortZalloc( size_t xWantedSize ) PRIVILEGED_FUNCTION;
void *pvPortCalloc( size_t count, size_t size ) PRIVILEGED_FUNCTION;
void *pvPortRealloc( void *pv, size_t newsize ) PRIVILEGED_FUNCTION;
void vPortFree( void *pv ) PRIVILEGED_FUNCTION;
#ifdef MEMLEAK_DEBUG
void *pvPortMalloc_trace( size_t xWantedSize, const char * file, unsigned line, bool use_iram ) PRIVILEGED_FUNCTION;
void *pvPortZalloc_trace( size_t xWantedSize, const char * file, unsigned line ) PRIVILEGED_FUNCTION;
void *pvPortCalloc_trace( size_t count, size_t size, const char * file, unsigned line ) PRIVILEGED_FUNCTION;
void *pvPortRealloc_trace( void *pv, size_t newsize, const char *file, unsigned line ) PRIVILEGED_FUNCTION;
void vPortFree_trace( void *pv, const char * file, unsigned line ) PRIVILEGED_FUNCTION;
void pvShowMalloc();
#endif
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;
size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION;
size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION;
#define pvPortMalloc(s) heap_caps_malloc(s, pvMALLOC_DRAM)
#define pvPortZalloc(s) heap_caps_zalloc(s, pvMALLOC_IRAM)
#define pvPortCalloc(c, s) heap_caps_calloc(c, s, pvMALLOC_IRAM)
#define pvPortRealloc(p, s) heap_caps_realloc(p, s, pvMALLOC_IRAM)
#define vPortFree(p) heap_caps_free(p)
/*
* Setup the hardware ready for the scheduler to take control. This generally

View File

@ -1,838 +0,0 @@
/*
FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd.
All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
***************************************************************************
* *
* FreeRTOS provides completely free yet professionally developed, *
* robust, strictly quality controlled, supported, and cross *
* platform software that has become a de facto standard. *
* *
* Help yourself get started quickly and support the FreeRTOS *
* project by purchasing a FreeRTOS tutorial book, reference *
* manual, or both from: http://www.FreeRTOS.org/Documentation *
* *
* Thank you! *
* *
***************************************************************************
This file is part of the FreeRTOS distribution.
FreeRTOS is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License (version 2) as published by the
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
>>! NOTE: The modification to the GPL is included to allow you to !<<
>>! distribute a combined work that includes FreeRTOS without being !<<
>>! obliged to provide the source code for proprietary components !<<
>>! outside of the FreeRTOS kernel. !<<
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. Full license text is available from the following
link: http://www.freertos.org/a00114.html
1 tab == 4 spaces!
***************************************************************************
* *
* Having a problem? Start by reading the FAQ "My application does *
* not run, what could be wrong?" *
* *
* http://www.FreeRTOS.org/FAQHelp.html *
* *
***************************************************************************
http://www.FreeRTOS.org - Documentation, books, training, latest versions,
license and Real Time Engineers Ltd. contact details.
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
compatible FAT file system, and our tiny thread aware UDP/IP stack.
http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
licenses offer ticketed support, indemnification and middleware.
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
engineered and independently SIL3 certified version for use in safety and
mission critical applications that require provable dependability.
1 tab == 4 spaces!
*/
/*
* A sample implementation of pvPortMalloc() that allows the heap to be defined
* across multiple non-contigous blocks and combines (coalescences) adjacent
* memory blocks as they are freed.
*
* See heap_1.c, heap_2.c, heap_3.c and heap_4.c for alternative
* implementations, and the memory management pages of http://www.FreeRTOS.org
* for more information.
*
* Usage notes:
*
* vPortDefineHeapRegions() ***must*** be called before pvPortMalloc().
* pvPortMalloc() will be called if any task objects (tasks, queues, event
* groups, etc.) are created, therefore vPortDefineHeapRegions() ***must*** be
* called before any other objects are defined.
*
* vPortDefineHeapRegions() takes a single parameter. The parameter is an array
* of HeapRegion_t structures. HeapRegion_t is defined in portable.h as
*
* typedef struct HeapRegion
* {
* uint8_t *pucStartAddress; << Start address of a block of memory that will be part of the heap.
* size_t xSizeInBytes; << Size of the block of memory.
* } HeapRegion_t;
*
* The array is terminated using a NULL zero sized region definition, and the
* memory regions defined in the array ***must*** appear in address order from
* low address to high address. So the following is a valid example of how
* to use the function.
*
* HeapRegion_t xHeapRegions[] =
* {
* { ( uint8_t * ) 0x80000000UL, 0x10000 }, << Defines a block of 0x10000 bytes starting at address 0x80000000
* { ( uint8_t * ) 0x90000000UL, 0xa0000 }, << Defines a block of 0xa0000 bytes starting at address of 0x90000000
* { NULL, 0 } << Terminates the array.
* };
*
* vPortDefineHeapRegions( xHeapRegions ); << Pass the array into vPortDefineHeapRegions().
*
* Note 0x80000000 is the lower address so appears in the array first.
*
*/
#include "sdkconfig.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp8266/eagle_soc.h"
#include "rom/ets_sys.h"
#include "esp8266/rom_functions.h"
#ifdef MEMLEAK_DEBUG
#include "spi_flash.h"
extern esp_spi_flash_chip_t flashchip;
#endif
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#define mtCOVERAGE_TEST_MARKER()
#if 1
#define mem_printf(fmt, args...) ets_printf(fmt,## args)
#else
#define mem_printf(fmt, args...)
#endif
/* Block sizes must not get too small. */
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( uxHeapStructSize << 1 ) )
/* Assumes 8bit bytes! */
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
/* Define the linked list structure. This is used to link free blocks in order
of their memory address. */
typedef struct A_BLOCK_LINK
{
struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */
size_t xBlockSize; /*<< The size of the free block. */
#ifdef MEMLEAK_DEBUG
const char *file;
unsigned line;
#endif
} BlockLink_t;
/*-----------------------------------------------------------*/
/*
* Inserts a block of memory that is being freed into the correct position in
* the list of free memory blocks. The block being freed will be merged with
* the block in front it and/or the block behind it if the memory blocks are
* adjacent to each other.
*/
static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert );
/*-----------------------------------------------------------*/
/* The size of the structure placed at the beginning of each allocated memory
block must by correctly byte aligned. */
static const uint32_t uxHeapStructSize = ( ( sizeof ( BlockLink_t ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK );
/* Create a couple of list links to mark the start and end of the list. */
static BlockLink_t xStart, *pxEnd = NULL;
#ifdef MEMLEAK_DEBUG
//add by jjj, we Link the used blocks here
static BlockLink_t yStart;
static size_t yFreeBytesRemaining;
#endif
/* Keeps track of the number of free bytes remaining, but says nothing about
fragmentation. */
static size_t xFreeBytesRemaining = 0;
static size_t xMinimumEverFreeBytesRemaining = 0;
/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize
member of an BlockLink_t structure is set then the block belongs to the
application. When the bit is free the block is still part of the free heap
space. */
static size_t xBlockAllocatedBit = 0;
extern char _heap_start;
extern char _lit4_end;
static HeapRegion_t xHeapRegions[] =
{
{ NULL, 0 },
{ NULL, 0 },
{ NULL, 0 }
};
#ifdef MEMLEAK_DEBUG
#define pvPortMalloc_t(xWantedSize) pvPortMalloc_trace(xWantedSize, file, line, false)
#define vPortFree_t(pv) vPortFree_trace(pv, file, line)
#define pvPortCalloc_t(count, size) pvPortCalloc_trace(count, size, file, line)
#else
#define pvPortMalloc_t(xWantedSize) pvPortMalloc(xWantedSize)
#define vPortFree_t(pv) vPortFree(pv)
#define pvPortCalloc_t(count, size) pvPortCalloc(count, size)
#endif
/*-----------------------------------------------------------*/
bool __attribute__((weak)) check_memleak_debug_enable(void)
{
return 0;
}
#ifdef MEMLEAK_DEBUG
void prvInsertBlockIntoUsedList(BlockLink_t *pxBlockToInsert)
{
BlockLink_t *pxIterator;
for( pxIterator = &yStart; pxIterator->pxNextFreeBlock < pxBlockToInsert && pxIterator->pxNextFreeBlock != NULL;pxIterator = pxIterator->pxNextFreeBlock)
{
/* Nothing to do here. */
}
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
pxIterator->pxNextFreeBlock = pxBlockToInsert;
yFreeBytesRemaining += pxBlockToInsert->xBlockSize;
}
#define SPI_FLASH_START ((void *)0x40100000)
#define SPI_FLASH_SIZE 0x100000
#define SPI_FLASH_END (SPI_FLASH_START + SPI_FLASH_SIZE)
void pvShowMalloc()
{
BlockLink_t *pxIterator;
//ets_printf("sh0:%d,%d,",uxHeapStructSize,sizeof( BlockLink_t ));
if(uxHeapStructSize < sizeof( BlockLink_t ))
return;
ETS_INTR_LOCK();
Wait_SPI_Idle(&flashchip);
Cache_Read_Enable_New();
//ets_printf("sh1,");
printf("--------Show Malloc--------\n");
for( pxIterator = &yStart; pxIterator->pxNextFreeBlock != NULL;pxIterator = pxIterator->pxNextFreeBlock) {
BlockLink_t *blk = pxIterator->pxNextFreeBlock;
//ets_printf("sh2,");
const char *basename = blk->file;
/* This matches a similar check that vGetFileName() used to
* do, but the code seems fine without it
if (SPI_FLASH_START <= (void *)basename && (void *)basename < SPI_FLASH_END) {
basename = NULL;
}
*/
/* The file contains the absolute path, try to shorten in by
* looking for path separators. Checks for both UNIX and
* Windows separators. */
if (basename) {
basename = strrchr(basename, '/');
if (basename) {
basename++;
} else {
basename = strrchr(blk->file, '\\');
if (basename) {
basename++;
}
}
} else {
basename = "";
}
if (((unsigned)-1) == blk->line)
printf("F(1):%-30p malloc %10d @ %p\n", blk->file, blk->xBlockSize - 0x80000000, ( void * ) ( ( ( unsigned char * ) blk ) + uxHeapStructSize));
else
printf("F(2):%-30sL:%4u malloc %10d @ %p\n", basename, blk->line, blk->xBlockSize - 0x80000000, ( void * ) ( ( ( unsigned char * ) blk ) + uxHeapStructSize));
//ets_printf("sh3,");
// ets_delay_us(2000);
system_soft_wdt_feed();
}
printf("--------Free %d--------\n\n", xFreeBytesRemaining);
#if 0
uint32_t last_link = (uint32_t)yStart.pxNextFreeBlock;
uint32_t index = 0;
printf("'*':used, '-'free, each %d bytes\n", portBYTE_ALIGNMENT_v);
printf("%x:", last_link);
for( pxIterator = &yStart; pxIterator->pxNextFreeBlock != NULL;pxIterator = pxIterator->pxNextFreeBlock) {
uint16_t i;
for (i = 0; i < ((uint32_t)pxIterator->pxNextFreeBlock - last_link) / portBYTE_ALIGNMENT_v; i++) {
index++;
printf("-");
if (index % 64 == 0) {
printf("\n%x:", (uint32_t)yStart.pxNextFreeBlock + index * portBYTE_ALIGNMENT_v);
}
}
for (i = 0; i < pxIterator->pxNextFreeBlock->xBlockSize / portBYTE_ALIGNMENT_v; i++) {
index++;
printf("*");
if (index % 64 == 0) {
printf("\n%x:", (uint32_t)yStart.pxNextFreeBlock + index * portBYTE_ALIGNMENT_v);
}
}
last_link = ((uint32_t)pxIterator->pxNextFreeBlock + pxIterator->pxNextFreeBlock->xBlockSize);
system_soft_wdt_feed();
}
printf("\n\n");
#endif
//ets_printf("sh4\n");
ETS_INTR_UNLOCK();
}
void system_show_malloc(void) __attribute__((alias("pvShowMalloc")));
int prvRemoveBlockFromUsedList(BlockLink_t *pxBlockToRemove)
{
BlockLink_t *pxIterator;
for( pxIterator = &yStart; pxIterator->pxNextFreeBlock != pxBlockToRemove && pxIterator->pxNextFreeBlock != NULL;pxIterator = pxIterator->pxNextFreeBlock)
{
/* Nothing to do here. */
}
if(pxIterator->pxNextFreeBlock != pxBlockToRemove){
return -1;
}
pxIterator->pxNextFreeBlock = pxBlockToRemove->pxNextFreeBlock;
yFreeBytesRemaining -= pxBlockToRemove->xBlockSize;
return 0;
}
#endif
size_t xPortWantedSizeAlign(size_t xWantedSize)
{
return xWantedSize;
}
/*
* @brief add trace information to allocated memory
*/
void esp_mem_trace(const void *ptr, const char *trace, int no)
{
BlockLink_t *pxLink = (BlockLink_t *)((uint8_t *)ptr - uxHeapStructSize);
pxLink->file = trace;
pxLink->line = (unsigned)no;
}
void *pvPortMalloc( size_t xWantedSize )
#ifdef MEMLEAK_DEBUG
{
void *return_addr = (void *)__builtin_return_address(0);
return pvPortMalloc_trace( xWantedSize, return_addr, (unsigned)-1, false );
}
void *pvPortMalloc_trace( size_t xWantedSize, const char * file, unsigned line, bool use_iram )
#endif
{
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
void *pvReturn = NULL;
static bool is_inited = false;
if (!is_inited) {
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions );
xHeapRegions[0].pucStartAddress = ( uint8_t * )&_heap_start;
xHeapRegions[0].xSizeInBytes = (( size_t)( 0x40000000 - (uint32_t)&_heap_start));
#ifndef CONFIG_SOC_FULL_ICACHE
xHeapRegions[1].pucStartAddress = ( uint8_t * )&_lit4_end;
xHeapRegions[1].xSizeInBytes = (( size_t)( 0x4010C000 - (uint32_t)&_lit4_end));
#endif
is_inited = true;
vPortDefineHeapRegions(xHeapRegions);
}
/* The heap must be initialised before the first call to
prvPortMalloc(). */
configASSERT( pxEnd );
// vTaskSuspendAll();
ETS_INTR_LOCK();
{
/* Check the requested block size is not so large that the top bit is
set. The top bit of the block size member of the BlockLink_t structure
is used to determine who owns the block - the application or the
kernel, so it must be free. */
if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
{
/* The wanted size is increased so it can contain a BlockLink_t
structure in addition to the requested amount of bytes. */
if( xWantedSize > 0 )
{
xWantedSize += uxHeapStructSize;
/* Ensure that blocks are always aligned to the required number
of bytes. */
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
{
/* Byte alignment required. */
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
{
/* Traverse the list from the start (lowest address) block until
one of adequate size is found. */
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
BlockLink_t *pxIterator;
/* Iterate through the list until a block is found that has a higher address
than the block being inserted. */
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock != 0; pxIterator = pxIterator->pxNextFreeBlock )
{
if ((line == 0 || use_iram == true) && (uint32_t)pxIterator->pxNextFreeBlock > 0x40000000 && pxIterator->pxNextFreeBlock->xBlockSize > xWantedSize) {
pxPreviousBlock = pxIterator;
pxBlock = pxIterator->pxNextFreeBlock;
break;
}
}
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
{
pxPreviousBlock = pxBlock;
pxBlock = pxBlock->pxNextFreeBlock;
}
/* If the end marker was reached then a block of adequate size
was not found. */
if( pxBlock != pxEnd )
{
/* Return the memory space pointed to - jumping over the
BlockLink_t structure at its start. */
pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + uxHeapStructSize );
/* This block is being returned for use so must be taken out
of the list of free blocks. */
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
/* If the block is larger than required it can be split into
two. */
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
{
/* This block is to be split into two. Create a new
block following the number of bytes requested. The void
cast is used to prevent byte alignment warnings from the
compiler. */
pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
/* Calculate the sizes of two blocks split from the
single block. */
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
pxBlock->xBlockSize = xWantedSize;
/* Insert the new block into the list of free blocks. */
prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
xFreeBytesRemaining -= pxBlock->xBlockSize;
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
{
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* The block is being returned - it is allocated and owned
by the application and has no "next" block. */
pxBlock->xBlockSize |= xBlockAllocatedBit;
pxBlock->pxNextFreeBlock = NULL;
#ifdef MEMLEAK_DEBUG
if(uxHeapStructSize >= sizeof( BlockLink_t )){
pxBlock->file = file;
pxBlock->line = line;
}
//link the use block
prvInsertBlockIntoUsedList(pxBlock);
#endif
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
traceMALLOC( pvReturn, xWantedSize );
}
// ( void ) xTaskResumeAll();
ETS_INTR_UNLOCK();
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
extern void vApplicationMallocFailedHook( void );
vApplicationMallocFailedHook();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif
return pvReturn;
}
/*-----------------------------------------------------------*/
void vPortFree( void *pv )
#ifdef MEMLEAK_DEBUG
{
void *return_addr = (void *)__builtin_return_address(0);
vPortFree_trace(pv, return_addr, (unsigned)-1);
}
void vPortFree_trace( void *pv, const char * file, unsigned line )
#endif
{
uint8_t *puc = ( uint8_t * ) pv;
BlockLink_t *pxLink;
if( pv != NULL )
{
/* The memory being freed will have an BlockLink_t structure immediately
before it. */
puc -= uxHeapStructSize;
/* This casting is to keep the compiler from issuing warnings. */
pxLink = ( void * ) puc;
/* Check the block is actually allocated. */
configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
configASSERT( pxLink->pxNextFreeBlock == NULL );
if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
{
#ifndef MEMLEAK_DEBUG
if( pxLink->pxNextFreeBlock == NULL )
#endif
{
/* The block is being returned to the heap - it is no longer
allocated. */
pxLink->xBlockSize &= ~xBlockAllocatedBit;
//vTaskSuspendAll();
ETS_INTR_LOCK();
#ifdef MEMLEAK_DEBUG
if(prvRemoveBlockFromUsedList(pxLink) < 0){
printf("%p already freed\n", pv);
}
else
#endif
{
/* Add this block to the list of free blocks. */
xFreeBytesRemaining += pxLink->xBlockSize;
traceFREE( pv, pxLink->xBlockSize );
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
}
// ( void ) xTaskResumeAll();
ETS_INTR_UNLOCK();
}
#ifndef MEMLEAK_DEBUG
else
{
mtCOVERAGE_TEST_MARKER();
}
#endif
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
/*-----------------------------------------------------------*/
void *pvPortCalloc(size_t count, size_t size)
#ifdef MEMLEAK_DEBUG
{
void *return_addr = (void *)__builtin_return_address(0);
return pvPortCalloc_trace(count, size, return_addr, (unsigned)-1);
}
void *pvPortCalloc_trace(size_t count, size_t size, const char * file, unsigned line)
#endif
{
char *p = pvPortMalloc_trace(count * size, file, line, true);
if (p)
memset(p, 0, count * size);
return p;
}
/*-----------------------------------------------------------*/
void *pvPortRealloc(void *mem, size_t newsize)
#ifdef MEMLEAK_DEBUG
{
void *return_addr = (void *)__builtin_return_address(0);
return pvPortRealloc_trace(mem, newsize, return_addr, (unsigned)-1);
}
void *pvPortRealloc_trace(void *mem, size_t newsize, const char *file, unsigned line)
#endif
{
void *return_addr = (void *)__builtin_return_address(0);
void *p = pvPortMalloc_trace(newsize, file, line, true);
if (p && mem) {
memcpy(p, mem, newsize);
vPortFree_trace(mem, return_addr, 0);
}
return p;
}
/*-----------------------------------------------------------*/
void *pvPortZalloc(size_t size)
#ifdef MEMLEAK_DEBUG
{
void *return_addr = (void *)__builtin_return_address(0);
return pvPortZalloc_trace(size, return_addr, (unsigned)-1);
}
void *pvPortZalloc_trace(size_t size, const char * file, unsigned line)
#endif
{
char *p = pvPortMalloc_trace(size, file, line, true);
if (p)
memset(p, 0, size);
return p;
}
size_t xPortGetFreeHeapSize( void )
{
return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
size_t xPortGetMinimumEverFreeHeapSize( void )
{
return xMinimumEverFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert )
{
BlockLink_t *pxIterator;
uint8_t *puc;
/* Iterate through the list until a block is found that has a higher address
than the block being inserted. */
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
{
/* Nothing to do here, just iterate to the right position. */
}
/* Do the block being inserted, and the block it is being inserted after
make a contiguous block of memory? */
puc = ( uint8_t * ) pxIterator;
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
{
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
pxBlockToInsert = pxIterator;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Do the block being inserted, and the block it is being inserted before
make a contiguous block of memory? */
puc = ( uint8_t * ) pxBlockToInsert;
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
{
if( pxIterator->pxNextFreeBlock != pxEnd )
{
/* Form one big block from the two blocks. */
pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxEnd;
}
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
}
/* If the block being inserted plugged a gab, so was merged with the block
before and the block after, then it's pxNextFreeBlock pointer will have
already been set, and should not be set here as that would make it point
to itself. */
if( pxIterator != pxBlockToInsert )
{
pxIterator->pxNextFreeBlock = pxBlockToInsert;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/*-----------------------------------------------------------*/
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions )
{
BlockLink_t *pxFirstFreeBlockInRegion = NULL, *pxPreviousFreeBlock;
uint8_t *pucAlignedHeap;
size_t xTotalRegionSize, xTotalHeapSize = 0;
uint8_t xDefinedRegions = 0;
uint32_t ulAddress;
const HeapRegion_t *pxHeapRegion;
/* Can only call once! */
configASSERT( pxEnd == NULL );
pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );
while( pxHeapRegion->xSizeInBytes > 0 )
{
xTotalRegionSize = pxHeapRegion->xSizeInBytes;
/* Ensure the heap region starts on a correctly aligned boundary. */
ulAddress = ( uint32_t ) pxHeapRegion->pucStartAddress;
if( ( ulAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{
ulAddress += ( portBYTE_ALIGNMENT - 1 );
ulAddress &= ~portBYTE_ALIGNMENT_MASK;
/* Adjust the size for the bytes lost to alignment. */
xTotalRegionSize -= ulAddress - ( uint32_t ) pxHeapRegion->pucStartAddress;
}
pucAlignedHeap = ( uint8_t * ) ulAddress;
/* Set xStart if it has not already been set. */
if( xDefinedRegions == 0 )
{
/* xStart is used to hold a pointer to the first item in the list of
free blocks. The void cast is used to prevent compiler warnings. */
xStart.pxNextFreeBlock = ( BlockLink_t * ) pucAlignedHeap;
xStart.xBlockSize = ( size_t ) 0;
}
else
{
/* Should only get here if one region has already been added to the
heap. */
configASSERT( pxEnd != NULL );
/* Check blocks are passed in with increasing start addresses. */
configASSERT( ulAddress > ( uint32_t ) pxEnd );
}
/* Remember the location of the end marker in the previous region, if
any. */
pxPreviousFreeBlock = pxEnd;
/* pxEnd is used to mark the end of the list of free blocks and is
inserted at the end of the region space. */
ulAddress = ( ( uint32_t ) pucAlignedHeap ) + xTotalRegionSize;
ulAddress -= uxHeapStructSize;
ulAddress &= ~portBYTE_ALIGNMENT_MASK;
pxEnd = ( BlockLink_t * ) ulAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = NULL;
/* To start with there is a single free block in this region that is
sized to take up the entire heap region minus the space taken by the
free block structure. */
pxFirstFreeBlockInRegion = ( BlockLink_t * ) pucAlignedHeap;
pxFirstFreeBlockInRegion->xBlockSize = ulAddress - ( uint32_t ) pxFirstFreeBlockInRegion;
pxFirstFreeBlockInRegion->pxNextFreeBlock = pxEnd;
/* If this is not the first region that makes up the entire heap space
then link the previous region to this region. */
if( pxPreviousFreeBlock != NULL )
{
pxPreviousFreeBlock->pxNextFreeBlock = pxFirstFreeBlockInRegion;
}
xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize;
/* Move onto the next HeapRegion_t structure. */
xDefinedRegions++;
pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );
}
xMinimumEverFreeBytesRemaining = xTotalHeapSize;
xFreeBytesRemaining = xTotalHeapSize;
/* Check something was actually defined before it is accessed. */
configASSERT( xTotalHeapSize );
/* Work out the position of the top bit in a size_t variable. */
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
#ifdef MEMLEAK_DEBUG
//add by jjj
yStart.pxNextFreeBlock = NULL;
yStart.xBlockSize = ( size_t ) 0;
yFreeBytesRemaining = 0;
#endif
}

View File

@ -121,7 +121,7 @@ typedef unsigned int INT32U;
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
#define portBYTE_ALIGNMENT 4
/*-----------------------------------------------------------*/
/* Scheduler utilities. */

View File

@ -0,0 +1,7 @@
#
# Component Makefile
#
COMPONENT_ADD_INCLUDEDIRS := include port/esp8266/include
COMPONENT_SRCDIRS := src port/esp8266

View 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

View 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

View 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

View 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

View 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);
}

View 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

View 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(); \
}

View 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));
#ifdef CONFIG_ESP_HEAP_CHECK_FREED
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;
}

View 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);
}
}

View File

@ -28,16 +28,9 @@
*/
void *mem_malloc_ll(size_t s)
{
void *p;
void *return_addr = (void *)__builtin_return_address(0);
p = pvPortMalloc_trace(s, return_addr, (unsigned)-1, false);
if (IS_IRAM(p)) {
vPortFree_trace(p, return_addr, (unsigned)-1);
p = NULL;
}
return p;
return _heap_caps_malloc(s, MALLOC_CAP_8BIT, return_addr, 0);
}
void *memp_malloc_ll(size_t type)

View File

@ -21,48 +21,34 @@ void *malloc(size_t n)
{
void *return_addr = (void *)__builtin_return_address(0);
return pvPortMalloc_trace(n, return_addr, (unsigned)-1, true);
return _heap_caps_malloc(n, MALLOC_CAP_32BIT, return_addr, 0);
}
void *realloc(void *old_ptr, size_t n)
{
void *return_addr = (void *)__builtin_return_address(0);
void *p = pvPortMalloc_trace(n, return_addr, (unsigned)-1, true);
if (p && old_ptr) {
memcpy(p, old_ptr, n);
vPortFree_trace(old_ptr, return_addr, 0);
}
return p;
return _heap_caps_realloc(old_ptr, n, MALLOC_CAP_32BIT, return_addr, 0);
}
void *zalloc(size_t n)
{
void *return_addr = (void *)__builtin_return_address(0);
char *p = pvPortMalloc_trace(n, return_addr, (unsigned)-1, true);
if (p)
memset(p, 0, n);
return p;
return _heap_caps_zalloc(n, MALLOC_CAP_32BIT, return_addr, 0);
}
void *calloc(size_t c, size_t s)
{
void *return_addr = (void *)__builtin_return_address(0);
char *p = pvPortMalloc_trace(c * s, return_addr, (unsigned)-1, true);
if (p)
memset(p, 0, c * s);
return p;
return _heap_caps_calloc(c, s, MALLOC_CAP_32BIT, return_addr, 0);
}
void free(void *ptr)
{
void *return_addr = (void *)__builtin_return_address(0);
vPortFree_trace(ptr, return_addr, (unsigned)-1);
_heap_caps_free(ptr, return_addr, 0);
}

View File

@ -93,39 +93,28 @@ void *_malloc_r(struct _reent *r, size_t n)
{
void *return_addr = (void *)__builtin_return_address(0);
return pvPortMalloc_trace(n, return_addr, (unsigned)-1, true);
return _heap_caps_malloc(n, MALLOC_CAP_32BIT, return_addr, 0);
}
void *_realloc_r(struct _reent *r, void *old_ptr, size_t n)
{
void *return_addr = (void *)__builtin_return_address(0);
void *p = pvPortMalloc_trace(n, return_addr, (unsigned)-1, true);
if (p && old_ptr) {
memcpy(p, old_ptr, n);
vPortFree_trace(old_ptr, return_addr, 0);
}
return p;
return _heap_caps_realloc(old_ptr, n, MALLOC_CAP_32BIT, return_addr, 0);
}
void *_calloc_r(struct _reent *r, size_t c, size_t s)
{
void *return_addr = (void *)__builtin_return_address(0);
char *p = pvPortMalloc_trace(c * s, return_addr, (unsigned)-1, true);
if (p)
memset(p, 0, c * s);
return p;
return _heap_caps_calloc(c, s, MALLOC_CAP_32BIT, return_addr, 0);
}
void _free_r(struct _reent *r, void *ptr)
{
void *return_addr = (void *)__builtin_return_address(0);
vPortFree_trace(ptr, return_addr, (unsigned)-1);
_heap_caps_free(ptr, return_addr, 0);
}
void _exit(int status)

View File

@ -98,19 +98,11 @@ static __inline__ uint64_t be64toh(uint64_t __x) {return (((uint64_t)be32toh(__x
#define htobe64(x) be64toh(x)
#endif
#ifdef MEMLEAK_DEBUG
#define SSL_MALLOC(size) os_malloc(size)
#define SSL_REALLOC(mem_ref,size) os_realloc(mem_ref, size)
#define SSL_CALLOC(element, size) os_calloc(element, size)
#define SSL_ZALLOC(size) os_zalloc(size)
#define SSL_FREE(mem_ref) os_free(mem_ref)
#else
#define SSL_MALLOC(size) malloc(size)
#define SSL_REALLOC(mem_ref,size) realloc(mem_ref, size)
#define SSL_CALLOC(element, size) calloc(element, size)
#define SSL_ZALLOC(size) zalloc(size)
#define SSL_FREE(mem_ref) free(mem_ref)
#endif
#if 0
#define FILE_NAME_LENGTH 25

View File

@ -19,44 +19,15 @@
#include <stdio.h>
#include "esp_system.h"
#include "esp_heap_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef MEMLEAK_DEBUG
extern void *pvPortMalloc( size_t xWantedSize, const char * file, unsigned line, bool use_iram);
extern void *pvPortZalloc( size_t xWantedSize, const char * file, unsigned line);
extern void vPortFree(void *pv, const char * file, unsigned line);
#define ssl_mem_malloc(s) \
({ \
pvPortMalloc(s, __FILE__, __LINE__, false); \
})
#define ssl_mem_zalloc(s) \
({ \
pvPortZalloc(s, __FILE__, __LINE__); \
})
#define ssl_mem_free(s) \
do{\
vPortFree(s, __FILE__, __LINE__);\
}while(0)
#else
extern void *pvPortMalloc( size_t xWantedSize );
extern void *pvPortZalloc( size_t xWantedSize );
extern void vPortFree(void *pv);
#define ssl_mem_zalloc(s) pvPortZalloc(s)
#define ssl_mem_malloc(s) pvPortMalloc(s)
#define ssl_mem_free(p) vPortFree(p)
#endif
#define ssl_mem_zalloc(s) heap_caps_zalloc(s, MALLOC_CAP_32BIT)
#define ssl_mem_malloc(s) heap_caps_malloc(s, MALLOC_CAP_32BIT)
#define ssl_mem_free(p) heap_caps_free(p)
#define ssl_memcpy memcpy
#define ssl_strlen strlen

View File

@ -5,4 +5,4 @@ set(COMPONENT_PRIV_REQUIRES lwip)
register_component()
component_compile_options(-DLWIP_OPEN_SRC -DMEMLEAK_DEBUG)
component_compile_options(-DLWIP_OPEN_SRC)

View File

@ -4,5 +4,3 @@
COMPONENT_ADD_INCLUDEDIRS += include
COMPONENT_SRCDIRS := ./
CFLAGS += -DMEMLEAK_DEBUG

View File

@ -28,25 +28,19 @@ void *_xmalloc(size_t n)
{
void *return_addr = (void *)__builtin_return_address(0);
return pvPortMalloc_trace(n, return_addr, (unsigned)-1, false);
return _heap_caps_malloc(n, MALLOC_CAP_8BIT, return_addr, 0);
}
void _xfree(void *ptr)
{
void *return_addr = (void *)__builtin_return_address(0);
vPortFree_trace(ptr, return_addr, (unsigned)-1);
_heap_caps_free(ptr, return_addr, 0);
}
void *_xrealloc(void *ptr, size_t n)
{
void *return_addr = (void *)__builtin_return_address(0);
void *p = pvPortMalloc_trace(n, return_addr, (unsigned)-1, false);
if (p && ptr) {
// n ?
memcpy(p, ptr, n);
vPortFree_trace(ptr, return_addr, (unsigned)-1);
}
return p;
return _heap_caps_realloc(ptr, n, MALLOC_CAP_8BIT, return_addr, 0);
}