mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-07-15 08:32:42 +08:00
Merge branch 'feature/refactor_heap' into 'master'
Refactor heap See merge request sdk/ESP8266_RTOS_SDK!449
This commit is contained in:
@ -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=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)
|
-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)
|
||||||
|
@ -65,4 +65,4 @@ endif # CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# global CFLAGS for ESP8266
|
# global CFLAGS for ESP8266
|
||||||
CFLAGS += -DMEMLEAK_DEBUG -DICACHE_FLASH
|
CFLAGS += -DICACHE_FLASH
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#ifndef BOOTLOADER_BUILD
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -73,82 +76,24 @@ int ets_printf(const char *fmt, ...);
|
|||||||
#define os_printf printf
|
#define os_printf printf
|
||||||
#endif
|
#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
|
#ifndef os_free
|
||||||
#define os_free(s) free(s)
|
#define os_free(s) heap_caps_free(s)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef os_malloc
|
#ifndef os_malloc
|
||||||
#define os_malloc(s) malloc(s)
|
#define os_malloc(s) heap_caps_malloc(s, MALLOC_CAP_32BIT)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef os_calloc
|
#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
|
#endif
|
||||||
|
|
||||||
#ifndef os_realloc
|
#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
|
#endif
|
||||||
|
|
||||||
#ifndef os_zalloc
|
#ifndef os_zalloc
|
||||||
#define os_zalloc(s) zalloc(s)
|
#define os_zalloc(s) heap_caps_zalloc(s, MALLOC_CAP_32BIT)
|
||||||
#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
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -274,75 +274,61 @@ static bool timer_delete_wrapper(void *timer, uint32_t ticks)
|
|||||||
|
|
||||||
static void *malloc_wrapper(uint32_t s, uint32_t cap)
|
static void *malloc_wrapper(uint32_t s, uint32_t cap)
|
||||||
{
|
{
|
||||||
bool iram;
|
uint32_t os_caps;
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
void *return_addr = (void *)__builtin_return_address(0);
|
||||||
|
|
||||||
if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA))
|
if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA))
|
||||||
iram = false;
|
os_caps = MALLOC_CAP_8BIT | MALLOC_CAP_DMA;
|
||||||
else
|
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)
|
static void *zalloc_wrapper(uint32_t s, uint32_t cap)
|
||||||
{
|
{
|
||||||
bool iram;
|
uint32_t os_caps;
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
void *return_addr = (void *)__builtin_return_address(0);
|
||||||
|
|
||||||
if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA))
|
if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA))
|
||||||
iram = false;
|
os_caps = MALLOC_CAP_8BIT | MALLOC_CAP_DMA;
|
||||||
else
|
else
|
||||||
iram = true;
|
os_caps = MALLOC_CAP_32BIT;
|
||||||
|
|
||||||
char *p = pvPortMalloc_trace(s, return_addr, (unsigned)-1, iram);
|
return _heap_caps_zalloc(s, os_caps, return_addr, 0);
|
||||||
if (p)
|
|
||||||
memset(p, 0, s);
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *realloc_wrapper(void *ptr, uint32_t s, uint32_t cap)
|
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);
|
void *return_addr = (void *)__builtin_return_address(0);
|
||||||
|
|
||||||
if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA))
|
if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA))
|
||||||
iram = false;
|
os_caps = MALLOC_CAP_8BIT | MALLOC_CAP_DMA;
|
||||||
else
|
else
|
||||||
iram = true;
|
os_caps = MALLOC_CAP_32BIT;
|
||||||
|
|
||||||
void *p = pvPortMalloc_trace(s, return_addr, (unsigned)-1, iram);
|
return _heap_caps_realloc(ptr, s, os_caps, return_addr, 0);
|
||||||
if (p && ptr) {
|
|
||||||
memcpy(p, ptr, s);
|
|
||||||
vPortFree_trace(ptr, return_addr, (unsigned)-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *calloc_wrapper(uint32_t cnt, uint32_t s, uint32_t cap)
|
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);
|
void *return_addr = (void *)__builtin_return_address(0);
|
||||||
|
|
||||||
if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA))
|
if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA))
|
||||||
iram = false;
|
os_caps = MALLOC_CAP_8BIT | MALLOC_CAP_DMA;
|
||||||
else
|
else
|
||||||
iram = true;
|
os_caps = MALLOC_CAP_32BIT;
|
||||||
|
|
||||||
char *p = pvPortMalloc_trace(cnt * s, return_addr, (unsigned)-1, iram);
|
return _heap_caps_calloc(cnt , s, os_caps, return_addr, 0);
|
||||||
if (p)
|
|
||||||
memset(p, 0, cnt * s);
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_wrapper(void *ptr)
|
static void free_wrapper(void *ptr)
|
||||||
{
|
{
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
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)
|
static void srand_wrapper(uint32_t seed)
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "esp_image_format.h"
|
#include "esp_image_format.h"
|
||||||
#include "esp_phy_init.h"
|
#include "esp_phy_init.h"
|
||||||
#include "esp_wifi_osi.h"
|
#include "esp_wifi_osi.h"
|
||||||
|
#include "esp_heap_caps_init.h"
|
||||||
#include "internal/esp_wifi_internal.h"
|
#include "internal/esp_wifi_internal.h"
|
||||||
|
|
||||||
#define FLASH_MAP_ADDR 0x40200000
|
#define FLASH_MAP_ADDR 0x40200000
|
||||||
@ -109,6 +110,8 @@ void call_user_start(size_t start_addr)
|
|||||||
"movi a2, 0xffffff00\n"
|
"movi a2, 0xffffff00\n"
|
||||||
"and a1, a1, a2\n");
|
"and a1, a1, a2\n");
|
||||||
|
|
||||||
|
heap_caps_init();
|
||||||
|
|
||||||
wifi_os_init();
|
wifi_os_init();
|
||||||
|
|
||||||
assert(wifi_task_create(user_init_entry, "uiT", 2048, NULL, wifi_task_get_max_priority()) != NULL);
|
assert(wifi_task_create(user_init_entry, "uiT", 2048, NULL, wifi_task_get_max_priority()) != NULL);
|
||||||
|
@ -339,7 +339,7 @@ void esp_chip_info(esp_chip_info_t* out_info)
|
|||||||
*/
|
*/
|
||||||
uint32_t esp_get_free_heap_size(void)
|
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)
|
uint32_t esp_get_minimum_free_heap_size(void)
|
||||||
{
|
{
|
||||||
return xPortGetMinimumEverFreeHeapSize();
|
return heap_caps_get_minimum_free_size(MALLOC_CAP_32BIT);
|
||||||
}
|
}
|
||||||
|
@ -89,6 +89,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "mpu_wrappers.h"
|
#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
|
* 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;
|
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) PRIVILEGED_FUNCTION;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Used by heap_5.c. */
|
#define pvMALLOC_DRAM (MALLOC_CAP_8BIT | MALLOC_CAP_32BIT | MALLOC_CAP_DMA)
|
||||||
typedef struct HeapRegion
|
#define pvMALLOC_IRAM (MALLOC_CAP_32BIT)
|
||||||
{
|
|
||||||
uint8_t *pucStartAddress;
|
|
||||||
size_t xSizeInBytes;
|
|
||||||
} HeapRegion_t;
|
|
||||||
|
|
||||||
/*
|
#define pvPortMalloc(s) heap_caps_malloc(s, pvMALLOC_DRAM)
|
||||||
* Used to define multiple heap regions for use by heap_5.c. This function
|
#define pvPortZalloc(s) heap_caps_zalloc(s, pvMALLOC_IRAM)
|
||||||
* must be called before any calls to pvPortMalloc() - not creating a task,
|
#define pvPortCalloc(c, s) heap_caps_calloc(c, s, pvMALLOC_IRAM)
|
||||||
* queue, semaphore, mutex, software timer, event group, etc. will result in
|
#define pvPortRealloc(p, s) heap_caps_realloc(p, s, pvMALLOC_IRAM)
|
||||||
* pvPortMalloc being called.
|
#define vPortFree(p) heap_caps_free(p)
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup the hardware ready for the scheduler to take control. This generally
|
* Setup the hardware ready for the scheduler to take control. This generally
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -121,7 +121,7 @@ typedef unsigned int INT32U;
|
|||||||
/* Architecture specifics. */
|
/* Architecture specifics. */
|
||||||
#define portSTACK_GROWTH ( -1 )
|
#define portSTACK_GROWTH ( -1 )
|
||||||
#define portTICK_PERIOD_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ )
|
#define portTICK_PERIOD_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ )
|
||||||
#define portBYTE_ALIGNMENT 8
|
#define portBYTE_ALIGNMENT 4
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* Scheduler utilities. */
|
/* Scheduler utilities. */
|
||||||
|
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));
|
||||||
|
#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;
|
||||||
|
}
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -28,16 +28,9 @@
|
|||||||
*/
|
*/
|
||||||
void *mem_malloc_ll(size_t s)
|
void *mem_malloc_ll(size_t s)
|
||||||
{
|
{
|
||||||
void *p;
|
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
void *return_addr = (void *)__builtin_return_address(0);
|
||||||
|
|
||||||
p = pvPortMalloc_trace(s, return_addr, (unsigned)-1, false);
|
return _heap_caps_malloc(s, MALLOC_CAP_8BIT, return_addr, 0);
|
||||||
if (IS_IRAM(p)) {
|
|
||||||
vPortFree_trace(p, return_addr, (unsigned)-1);
|
|
||||||
p = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *memp_malloc_ll(size_t type)
|
void *memp_malloc_ll(size_t type)
|
||||||
|
@ -21,48 +21,34 @@ void *malloc(size_t n)
|
|||||||
{
|
{
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
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 *realloc(void *old_ptr, size_t n)
|
||||||
{
|
{
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
void *return_addr = (void *)__builtin_return_address(0);
|
||||||
|
|
||||||
void *p = pvPortMalloc_trace(n, return_addr, (unsigned)-1, true);
|
return _heap_caps_realloc(old_ptr, n, MALLOC_CAP_32BIT, return_addr, 0);
|
||||||
if (p && old_ptr) {
|
|
||||||
memcpy(p, old_ptr, n);
|
|
||||||
vPortFree_trace(old_ptr, return_addr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *zalloc(size_t n)
|
void *zalloc(size_t n)
|
||||||
{
|
{
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
void *return_addr = (void *)__builtin_return_address(0);
|
||||||
|
|
||||||
char *p = pvPortMalloc_trace(n, return_addr, (unsigned)-1, true);
|
return _heap_caps_zalloc(n, MALLOC_CAP_32BIT, return_addr, 0);
|
||||||
if (p)
|
|
||||||
memset(p, 0, n);
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *calloc(size_t c, size_t s)
|
void *calloc(size_t c, size_t s)
|
||||||
{
|
{
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
void *return_addr = (void *)__builtin_return_address(0);
|
||||||
|
|
||||||
char *p = pvPortMalloc_trace(c * s, return_addr, (unsigned)-1, true);
|
return _heap_caps_calloc(c, s, MALLOC_CAP_32BIT, return_addr, 0);
|
||||||
if (p)
|
|
||||||
memset(p, 0, c * s);
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void free(void *ptr)
|
void free(void *ptr)
|
||||||
{
|
{
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
void *return_addr = (void *)__builtin_return_address(0);
|
||||||
|
|
||||||
vPortFree_trace(ptr, return_addr, (unsigned)-1);
|
_heap_caps_free(ptr, return_addr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,39 +93,28 @@ void *_malloc_r(struct _reent *r, size_t n)
|
|||||||
{
|
{
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
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 *_realloc_r(struct _reent *r, void *old_ptr, size_t n)
|
||||||
{
|
{
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
void *return_addr = (void *)__builtin_return_address(0);
|
||||||
|
|
||||||
void *p = pvPortMalloc_trace(n, return_addr, (unsigned)-1, true);
|
return _heap_caps_realloc(old_ptr, n, MALLOC_CAP_32BIT, return_addr, 0);
|
||||||
if (p && old_ptr) {
|
|
||||||
memcpy(p, old_ptr, n);
|
|
||||||
vPortFree_trace(old_ptr, return_addr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *_calloc_r(struct _reent *r, size_t c, size_t s)
|
void *_calloc_r(struct _reent *r, size_t c, size_t s)
|
||||||
{
|
{
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
void *return_addr = (void *)__builtin_return_address(0);
|
||||||
|
|
||||||
char *p = pvPortMalloc_trace(c * s, return_addr, (unsigned)-1, true);
|
return _heap_caps_calloc(c, s, MALLOC_CAP_32BIT, return_addr, 0);
|
||||||
if (p)
|
|
||||||
memset(p, 0, c * s);
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _free_r(struct _reent *r, void *ptr)
|
void _free_r(struct _reent *r, void *ptr)
|
||||||
{
|
{
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
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)
|
void _exit(int status)
|
||||||
|
@ -98,19 +98,11 @@ static __inline__ uint64_t be64toh(uint64_t __x) {return (((uint64_t)be32toh(__x
|
|||||||
#define htobe64(x) be64toh(x)
|
#define htobe64(x) be64toh(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MEMLEAK_DEBUG
|
|
||||||
#define SSL_MALLOC(size) os_malloc(size)
|
#define SSL_MALLOC(size) os_malloc(size)
|
||||||
#define SSL_REALLOC(mem_ref,size) os_realloc(mem_ref, size)
|
#define SSL_REALLOC(mem_ref,size) os_realloc(mem_ref, size)
|
||||||
#define SSL_CALLOC(element, size) os_calloc(element, size)
|
#define SSL_CALLOC(element, size) os_calloc(element, size)
|
||||||
#define SSL_ZALLOC(size) os_zalloc(size)
|
#define SSL_ZALLOC(size) os_zalloc(size)
|
||||||
#define SSL_FREE(mem_ref) os_free(mem_ref)
|
#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
|
#if 0
|
||||||
#define FILE_NAME_LENGTH 25
|
#define FILE_NAME_LENGTH 25
|
||||||
|
@ -19,44 +19,15 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MEMLEAK_DEBUG
|
#define ssl_mem_zalloc(s) heap_caps_zalloc(s, MALLOC_CAP_32BIT)
|
||||||
|
#define ssl_mem_malloc(s) heap_caps_malloc(s, MALLOC_CAP_32BIT)
|
||||||
extern void *pvPortMalloc( size_t xWantedSize, const char * file, unsigned line, bool use_iram);
|
#define ssl_mem_free(p) heap_caps_free(p)
|
||||||
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_memcpy memcpy
|
#define ssl_memcpy memcpy
|
||||||
#define ssl_strlen strlen
|
#define ssl_strlen strlen
|
||||||
|
@ -5,4 +5,4 @@ set(COMPONENT_PRIV_REQUIRES lwip)
|
|||||||
|
|
||||||
register_component()
|
register_component()
|
||||||
|
|
||||||
component_compile_options(-DLWIP_OPEN_SRC -DMEMLEAK_DEBUG)
|
component_compile_options(-DLWIP_OPEN_SRC)
|
||||||
|
@ -4,5 +4,3 @@
|
|||||||
COMPONENT_ADD_INCLUDEDIRS += include
|
COMPONENT_ADD_INCLUDEDIRS += include
|
||||||
|
|
||||||
COMPONENT_SRCDIRS := ./
|
COMPONENT_SRCDIRS := ./
|
||||||
|
|
||||||
CFLAGS += -DMEMLEAK_DEBUG
|
|
||||||
|
@ -28,25 +28,19 @@ void *_xmalloc(size_t n)
|
|||||||
{
|
{
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
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 _xfree(void *ptr)
|
||||||
{
|
{
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
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 *_xrealloc(void *ptr, size_t n)
|
||||||
{
|
{
|
||||||
void *return_addr = (void *)__builtin_return_address(0);
|
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);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user