doubao_chat/apps/common/system/mem_heap.c

1040 lines
34 KiB
C

/**
* @file
* Dynamic memory manager
*
* This is a lightweight replacement for the standard C library malloc().
*/
#include "generic/printf.h"
#ifdef SUPPORT_MS_EXTENSIONS
/* #pragma bss_seg( ".mem_heap_bss") */
/* #pragma data_seg( ".mem_heap_data") */
#pragma const_seg( ".mem_heap_const")
#pragma code_seg( ".mem_heap_code")
#endif
static inline void *sbrk(int incr);
typedef unsigned char u8_t;
typedef signed char err_t;
typedef unsigned int u32_t, mem_ptr_t;
typedef unsigned int mem_size_t;
#define MEM_HEAP_NO_SYS 0 //0:使用操作系统,1:不使用操作系统
#define MEM_HEAP_ERROR_CHECK 1
#define MEM_HEAP_CLR_MAGIC (u8_t)0xff
#define MEM_HEAP_OVERFLOW_MAGIC 0x53555aca
#define SBRK_PIECE_SIZE (20*1024*1024)
/** All allocated blocks will be MEM_HEAP_MIN_SIZE bytes big, at least!
* MEM_HEAP_MIN_SIZE can be overridden to suit your needs. Smaller values save space,
* larger values could prevent too small blocks to fragment the RAM too much. */
#define MEM_HEAP_MIN_SIZE 4
#define MEM_HEAP_STATS 1 //统计功能
/** print debug message only if debug message type is enabled...
*/
#define MEM_HEAP_PLATFORM_ASSERT(x) \
ASSERT(x)
/* ASSERT("\"%s\" failed at line %d in %s\n", x, __LINE__, __FILE__); */
#define MEM_HEAP_PLATFORM_DIAG(x) do {printf x;} while(0)
//#define MEM_HEAP_NOASSERT
/** flag for LWIP_DEBUGF to enable that debug message */
#define MEM_HEAP_DBG_ON 0x80U
/** flag for LWIP_DEBUGF to disable that debug message */
#define MEM_HEAP_DBG_OFF 0x00U
/** flag for LWIP_DEBUGF to halt after printing this debug message */
#define MEM_HEAP_DBG_HALT 0x08U
#define MEM_HEAP_DEBUG (MEM_HEAP_DBG_ON)
/*
------------------------------------
---------- MEM_HEAP options ----------
------------------------------------
*/
/**
* MEM_HEAP_ALIGNMENT: should be set to the alignment of the CPU
* 4 byte alignment -> #define MEM_HEAP_ALIGNMENT 4
* 2 byte alignment -> #define MEM_HEAP_ALIGNMENT 2
*/
#define MEM_HEAP_ALIGNMENT 4
/**
* MEM_SIZE: the size of the heap memory. If the application will send
* a lot of data that needs to be copied, this should be set high.
*/
#define MEM_HEAP_START_SIZE 0//8*1024*1024
#ifdef MEM_HEAP_DEBUG
#define MEM_HEAP_DEBUGF(debug, message) do { \
if ((debug) & MEM_HEAP_DBG_ON) { \
MEM_HEAP_PLATFORM_DIAG(message); \
if ((debug) & MEM_HEAP_DBG_HALT) { \
while(1); \
} \
} \
} while(0)
#else /* MEM_HEAP_DEBUG */
#define MEM_HEAP_DEBUGF(debug, message)
#endif /* MEM_HEAP_DEBUG */
#ifndef MEM_HEAP_NOASSERT
#define MEM_HEAP_ASSERT(message, assertion) do { if(!(assertion)) \
MEM_HEAP_PLATFORM_ASSERT(message); } while(0)
#else /* MEM_HEAP_NOASSERT */
#define MEM_HEAP_ASSERT(message, assertion)
#endif /* MEM_HEAP_NOASSERT */
#if MEM_HEAP_STATS
struct stats_mem {
#ifdef MEM_HEAP_DEBUG
const char *name;
#endif /* MEM_HEAP_DEBUG */
mem_size_t avail;
mem_size_t used;
mem_size_t max;
u32_t err;
u32_t illegal;
};
struct stats_ {
struct stats_mem mem;
};
#define STATS_INC(x) ++mem_heap.mem_stats.x
#define STATS_DEC(x) --mem_heap.mem_stats.x
#define STATS_INC_USED(x, y) do { mem_heap.mem_stats.x.used += y; \
if (mem_heap.mem_stats.x.max < mem_heap.mem_stats.x.used) { \
mem_heap.mem_stats.x.max = mem_heap.mem_stats.x.used; \
} \
} while(0)
#define MEM_STATS_AVAIL(x, y) mem_heap.mem_stats.mem.x = y
#define MEM_STATS_INC(x) STATS_INC(mem.x)
#define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y)
#define MEM_STATS_DEC_USED(x, y) mem_heap.mem_stats.mem.x -= y
#else
#define MEM_STATS_AVAIL(x, y)
#define MEM_STATS_INC(x)
#define MEM_STATS_INC_USED(x, y)
#define MEM_STATS_DEC_USED(x, y)
#endif
#if !MEM_HEAP_NO_SYS
/*#include "os/os_api.h"
*/
#include "system/spinlock.h"
/*typedef OS_MUTEX sys_mutex_t; // type of mutex
*/
/* Protect the heap only by using a semaphore */
#define MEM_HEAP_WAIT_MUTEX_TIMEOUT 0
#define MEM_HEAP_DECL_PROTECT() u16 oserr
#define MEM_HEAP_PROTECT() spin_lock(&mem_heap.lock) //os_mutex_pend(&mem_heap.mem_mutex,MEM_HEAP_WAIT_MUTEX_TIMEOUT)//os_mutex_pend(&mem_heap.mem_mutex,MEM_HEAP_WAIT_MUTEX_TIMEOUT,0)
#define MEM_HEAP_UNPROTECT() spin_unlock(&mem_heap.lock) //os_mutex_post(&mem_heap.mem_mutex)
#else /* !MEM_HEAP_NO_SYS */
#define sys_mutex_new() 0
#define MEM_HEAP_DECL_PROTECT()
#define MEM_HEAP_PROTECT()
#define MEM_HEAP_UNPROTECT()
#endif
/**
* The heap is made up as a list of structs of this type.
* This does not have to be aligned since for getting its size,
* we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes.
*/
#define MEM_USED 0x5a5aeaae
#define MEM_UNUSED 0xa5abcdef
struct mem {
#if MEM_HEAP_ERROR_CHECK == 1
u32_t check_before;
#endif
/** index of the next struct */
struct mem *next;
/** index of the previous struct */
struct mem *prev;
/** MEM_USED: this area is used; MEM_UNUSED: this area is unused */
u32_t used;
u32 rets_addr;
#if MEM_HEAP_ERROR_CHECK == 1
u32_t check_after;
#endif
};
/* some alignment macros: we define them here for better source code layout */
#define MIN_SIZE_ALIGNED MEM_HEAP_ALIGN_SIZE(MEM_HEAP_MIN_SIZE)
#define SIZEOF_STRUCT_MEM MEM_HEAP_ALIGN_SIZE(sizeof(struct mem))
#define MEM_SIZE_ALIGNED MEM_HEAP_ALIGN_SIZE(MEM_HEAP_SIZE)
/** Calculate memory size for an aligned buffer - returns the next highest
* multiple of MEM_HEAP_ALIGNMENT (e.g. MEM_HEAP_ALIGN_SIZE(3) and
* MEM_HEAP_ALIGN_SIZE(4) will both yield 4 for MEM_HEAP_ALIGNMENT == 4).
*/
#define MEM_HEAP_ALIGN_SIZE(size) (((size) + MEM_HEAP_ALIGNMENT - 1) & ~(MEM_HEAP_ALIGNMENT-1))
/** Align a memory pointer to the alignment defined by MEM_HEAP_ALIGNMENT
* so that ADDR % MEM_HEAP_ALIGNMENT == 0
*/
#define MEM_HEAP_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_HEAP_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_HEAP_ALIGNMENT-1)))
struct _mem_heap {
/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */
u8_t *ram;
/** the last entry, always unused! */
struct mem *ram_end;
/** pointer to the lowest free block, this is used for faster search */
struct mem *lfree;
/** record the last sbrk end*/
u8_t *sbrk_end;
/** record total mem_heap size */
mem_ptr_t mem_heap_size;
#if !MEM_HEAP_NO_SYS
/*sys_mutex_t mem_mutex;*/
spinlock_t lock;
#endif
#if MEM_HEAP_STATS
struct stats_ mem_stats;
#endif
u8_t mem_init;
};
static struct _mem_heap mem_heap = {
.mem_init = 0,
};
extern u32 MALLOC_SIZE[];
extern u32 HEAP_BEGIN;
extern u32 HEAP_END;
#if MEM_HEAP_STATS
static void mem_stats_init(void)
{
#ifdef MEM_HEAP_DEBUG
mem_heap.mem_stats.mem.name = "MEM_HEAP";
#endif
}
void malloc_stats(void)
{
MEM_HEAP_PLATFORM_DIAG(("\nMEM_HEAP %s\n", mem_heap.mem_stats.mem.name));
MEM_HEAP_PLATFORM_DIAG(("total: %u\n", (u32)MALLOC_SIZE));
MEM_HEAP_PLATFORM_DIAG(("left: %u\n", ((u32)MALLOC_SIZE - (u32)mem_heap.mem_stats.mem.used)));
/*MEM_HEAP_PLATFORM_DIAG(("avail: %u\n", (u32)mem_heap.mem_stats.mem.avail));
MEM_HEAP_PLATFORM_DIAG(("used: %u\n", (u32)mem_heap.mem_stats.mem.used));*/
MEM_HEAP_PLATFORM_DIAG(("max: %u\n", (u32)mem_heap.mem_stats.mem.max));
/*MEM_HEAP_PLATFORM_DIAG(("err: %u\n", (u32)mem_heap.mem_stats.mem.err));*/
}
#endif
u32 get_free_heap_size(void)
{
#if MEM_HEAP_STATS
return (u32)MALLOC_SIZE - (u32)mem_heap.mem_stats.mem.used;
#else
return 0;
#endif
}
void malloc_dump()
{
struct mem *mem;
struct mem *sbrk_lfree = 0;
MEM_HEAP_PROTECT();
u32 max_free = 0;
for (sbrk_lfree ? (mem = sbrk_lfree) : (mem = mem_heap.lfree);
mem != mem_heap.ram_end; mem = mem->next) {
if (mem->used == MEM_USED) {
printf("mem_used: %x - %x, size=%x, call_from=%x\n", (u32)mem,
(u32)mem->next, (u32)mem->next - (u32)mem,
mem->rets_addr);
} else {
printf("mem_free: %x - %x, size=%x\n",
(u32)mem, (u32)mem->next, (u32)mem->next - (u32)mem);
if (max_free < ((u32)mem->next - (u32)mem)) {
max_free = (u32)mem->next - (u32)mem;
}
}
}
MEM_HEAP_UNPROTECT();
#if MEM_HEAP_STATS
u32 last_free = (u8 *)&HEAP_END - (u8 *)mem_heap.ram_end;
if (max_free < last_free) {
max_free = last_free;
}
float fragment = 100 - 100.0 * max_free / ((u32)MALLOC_SIZE - (u32)mem_heap.mem_stats.mem.used);
printf("fragment: %f \r\n", fragment);
#endif
}
#if !MEM_HEAP_NO_SYS
static err_t sys_mutex_new(void)
{
spin_lock_init(&mem_heap.lock);
/*u16 err;
err =os_mutex_create(&mem_heap.mem_mutex) ;
MEM_HEAP_ASSERT("sys_mutex_new ",err == OS_ERR_NONE );
if(err)
return err;*/
return 0;
}
#endif
/**
* "Plug holes" by combining adjacent empty struct mems.
* After this function is through, there should not exist
* one empty struct mem pointing to another empty struct mem.
*
* @param mem this points to a struct mem which just has been freed
* @internal this function is only called by mem_free() and mem_trim()
*
* This assumes access to the heap is protected by the calling function
* already.
*/
static struct mem *
plug_holes(struct mem *mem)
{
struct mem *mem2 = mem;
struct mem *nmem;
struct mem *pmem;
// MEM_HEAP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= mem_heap.ram);
// MEM_HEAP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)mem_heap.ram_end);
MEM_HEAP_ASSERT("plug_holes: mem->used == MEM_UNUSED", mem->used == MEM_UNUSED);
/* plug hole forward */
// MEM_HEAP_ASSERT("plug_holes: mem->next <= ram_end", mem->next <= mem_heap.ram_end);
nmem = mem->next;
if (mem != nmem && nmem->used == MEM_UNUSED && (u8_t *)nmem != (u8_t *)mem_heap.ram_end) {
/* if mem->next is unused and not end of ram, combine mem and mem->next */
if (mem_heap.lfree == nmem) {
mem_heap.lfree = mem;
}
mem->next = nmem->next;
nmem->next->prev = mem;
MEM_STATS_DEC_USED(used, SIZEOF_STRUCT_MEM);
}
/* plug hole backward */
pmem = mem->prev;
/* printf("pmem : 0x%x, 0x%x", pmem, mem->rets_addr); */
if (pmem && pmem != mem && pmem->used == MEM_UNUSED) {
/* if mem->prev is unused, combine mem and mem->prev */
if (mem_heap.lfree == mem) {
mem_heap.lfree = pmem;
}
pmem->next = mem->next;
mem->next->prev = pmem;
mem2 = pmem;
MEM_STATS_DEC_USED(used, SIZEOF_STRUCT_MEM);
}
return mem2;
}
/**
* Zero the heap and initialize start, end and lowest-free
*/
static void mem_heap_init(void)
{
u8_t *sbrk_start;
struct mem *mem;
if (mem_heap.mem_init) {
return;
}
#if MEM_HEAP_STATS
mem_stats_init();
#endif
MEM_HEAP_ASSERT("Sanity check alignment",
(SIZEOF_STRUCT_MEM & (MEM_HEAP_ALIGNMENT - 1)) == 0);
mem_heap.mem_heap_size = MEM_HEAP_START_SIZE;
sbrk_start = sbrk(MEM_HEAP_START_SIZE + (2 * SIZEOF_STRUCT_MEM) + MEM_HEAP_ALIGNMENT);
/* align the heap */
mem_heap.ram = (u8_t *)MEM_HEAP_ALIGN(sbrk_start);
/* initialize the start of the heap */
mem = (struct mem *)mem_heap.ram;
mem->next = (struct mem *)&mem_heap.ram[mem_heap.mem_heap_size + SIZEOF_STRUCT_MEM];
mem->prev = mem;
mem->used = MEM_UNUSED;
/* initialize the end of the heap */
mem_heap.ram_end = (struct mem *)(void *)&mem_heap.ram[mem_heap.mem_heap_size + SIZEOF_STRUCT_MEM];
mem_heap.ram_end->used = MEM_USED;
mem_heap.ram_end->next = mem_heap.ram_end;
mem_heap.ram_end->prev = (struct mem *)mem_heap.ram;
#if MEM_HEAP_ERROR_CHECK == 1
mem->check_before = MEM_HEAP_OVERFLOW_MAGIC;
mem->check_after = MEM_HEAP_OVERFLOW_MAGIC;
mem_heap.ram_end->check_before = MEM_HEAP_OVERFLOW_MAGIC;
mem_heap.ram_end->check_after = MEM_HEAP_OVERFLOW_MAGIC;
#endif
mem_heap.sbrk_end = sbrk_start + MEM_HEAP_START_SIZE + (2 * SIZEOF_STRUCT_MEM) + MEM_HEAP_ALIGNMENT;
/* initialize the lowest-free pointer to the start of the heap */
mem_heap.lfree = (struct mem *)mem_heap.ram;
MEM_STATS_AVAIL(avail, mem_heap.mem_heap_size);
if (sys_mutex_new() != 0) {
MEM_HEAP_ASSERT("failed to create mem_mutex", 0);
}
/*malloc_stats();*/
mem_heap.mem_init = 1;
}
/**
* Put a struct mem back on the heap
*
* @param rmem is the data portion of a struct mem as returned by a previous
* call to mem_malloc()
*/
void free(void *rmem)
{
struct mem *mem;
MEM_HEAP_DECL_PROTECT();
/*u32 rets_addr;
__asm__ volatile("%0 = rets ;" : "=r"(rets_addr));
printf("??????????????????????????free: %x, %x\n", rmem, rets_addr);*/
if (rmem == (void *)0) {
// MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, ("mem_free(p == NULL) was called.\n"));
return;
}
MEM_HEAP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_HEAP_ALIGNMENT - 1)) == 0);
// MEM_HEAP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)mem_heap.ram &&
// (u8_t *)rmem < (u8_t *)mem_heap.ram_end);
// if ((u8_t *)rmem < (u8_t *)mem_heap.ram || (u8_t *)rmem >= (u8_t *)mem_heap.ram_end) {
// MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, ("mem_free: illegal memory\n"));
// /* protect mem stats from concurrent access */
// MEM_HEAP_PROTECT();
// MEM_STATS_INC(illegal);
// MEM_HEAP_UNPROTECT();
// return;
// }
/* protect the heap from concurrent access */
MEM_HEAP_PROTECT();
/* Get the corresponding struct mem ... */
mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
#if MEM_HEAP_ERROR_CHECK == 1
MEM_HEAP_ASSERT("mem_free: mem->check_before", mem->check_before == MEM_HEAP_OVERFLOW_MAGIC);
MEM_HEAP_ASSERT("mem_free: mem->check_after", mem->check_after == MEM_HEAP_OVERFLOW_MAGIC);
memset(rmem, MEM_HEAP_CLR_MAGIC, (u8_t *)mem->next - (u8_t *)rmem);
#endif
/* ... which has to be in a used state ... */
MEM_HEAP_ASSERT("mem_free: mem->used", mem->used == MEM_USED);
/* ... and is now unused. */
mem->used = MEM_UNUSED;
if (mem < mem_heap.lfree) {
/* the newly freed struct is now the lowest */
mem_heap.lfree = mem;
}
MEM_STATS_DEC_USED(used, ((mem_size_t)mem->next - (mem_size_t)mem - SIZEOF_STRUCT_MEM));
/* finally, see if prev or next are free also */
mem = plug_holes(mem);
MEM_HEAP_UNPROTECT();
}
void *get_malloc_caddr(u8 *addr, u32 offset)
{
#if MEM_HEAP_ERROR_CHECK
struct mem *mem2 = (struct mem *)(addr - SIZEOF_STRUCT_MEM);
return (void *)(&mem2->check_before);
#else
return NULL;
#endif
}
static u8 call_from_zalloc = 0;
/**
* Adam's mem_malloc() plus solution for bug #17922
* Allocate a block of memory with a minimum of 'size' bytes.
*
* @param size is the minimum size of the requested block in bytes.
* @return pointer to allocated memory or NULL if no free memory was found.
*
* Note that the returned value will always be aligned (as defined by MEM_HEAP_ALIGNMENT).
*/
static u32 rets_addr;
void *malloc(unsigned long size)
{
struct mem *mem, *mem2;
struct mem *sbrk_lfree = 0;
MEM_HEAP_DECL_PROTECT();
if (call_from_zalloc == 0) {
__asm__ volatile("%0 = rets ;" : "=r"(rets_addr));
}
if (size == 0) {
return (void *)0;
}
mem_heap_init();
/* Expand the size of the allocated memory region so that we can
adjust for alignment. */
size = MEM_HEAP_ALIGN_SIZE(size);
if (size < MIN_SIZE_ALIGNED) {
/* every data block must be at least MIN_SIZE_ALIGNED long */
size = MIN_SIZE_ALIGNED;
}
MEM_HEAP_PROTECT();
if (size > mem_heap.mem_heap_size) {
/*MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, ("malloc 0x%x > mem_heap_size(0x%x).\n", size, mem_heap.mem_heap_size));*/
/* protect the heap from concurrent access */
goto SBRK_MEM;
}
MALLOC:
/* Scan through the heap searching for a free block that is big enough,
* beginning with the lowest free block.
*/
for (sbrk_lfree ? (mem = sbrk_lfree) : (mem = mem_heap.lfree); mem != mem_heap.ram_end; mem = mem->next) {
if ((mem->used == MEM_UNUSED) &&
((mem_ptr_t)(mem->next) - ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM)) >= size) {
/* mem is not used and at least perfect fit is possible:
* mem->next - ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
if ((mem_ptr_t)(mem->next) - ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
/* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
* at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
* -> split large block, create empty remainder,
* remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
* mem->next - ((mem_ptr_t)mem + (2*SIZEOF_STRUCT_MEM)) == size,
* struct mem would fit in but no data between mem2 and mem2->next
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
* region that couldn't hold data, but when mem->next gets freed,
* the 2 regions would be combined, resulting in more free memory
*/
mem2 = (struct mem *)((mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size);
/* create mem2 struct */
mem2->used = MEM_UNUSED;
mem2->next = mem->next;
mem2->prev = mem;
#if MEM_HEAP_ERROR_CHECK == 1
mem2->check_after = MEM_HEAP_OVERFLOW_MAGIC;
mem2->check_before = MEM_HEAP_OVERFLOW_MAGIC;
#endif
/* and insert it between mem and mem->next */
mem->next = mem2;
mem->used = MEM_USED;
mem2->next->prev = mem2;
MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
} else {
/* (a mem2 struct does no fit into the user data space of mem and mem->next will always
* be used at this point: if not we have 2 unused structs in a row, plug_holes should have
* take care of this).
* -> near fit or excact fit: do not split, no mem2 creation
* also can't move mem->next directly behind mem, since mem->next
* will always be used at this point!
*/
mem->used = MEM_USED;
MEM_STATS_INC_USED(used, ((mem_ptr_t)mem->next - (mem_ptr_t)mem - SIZEOF_STRUCT_MEM));
}
if (mem == mem_heap.lfree) {
struct mem *cur = mem_heap.lfree;
/* Find next free block after mem and update lowest free pointer */
while ((cur->used == MEM_USED) && cur != mem_heap.ram_end) {
cur = cur->next;
}
mem_heap.lfree = cur;
MEM_HEAP_ASSERT("mem_malloc: !mem_heap.lfree->used", ((mem_heap.lfree == mem_heap.ram_end) || (mem_heap.lfree->used == MEM_UNUSED)));
}
MEM_HEAP_UNPROTECT();
// MEM_HEAP_ASSERT("mem_malloc: allocated memory not above ram_end.",
// (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)mem_heap.ram_end);
MEM_HEAP_ASSERT("mem_malloc: allocated memory properly aligned.",
((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_HEAP_ALIGNMENT == 0);
MEM_HEAP_ASSERT("mem_malloc: sanity check alignment",
(((mem_ptr_t)mem) & (MEM_HEAP_ALIGNMENT - 1)) == 0);
/* printf("malloc:0x%x size:0x%x\n",(u8_t *)mem + SIZEOF_STRUCT_MEM,size); */
/*if (call_from_zalloc == 0) {
printf("??????????????????????????malloc: %d, %x, %x\n", size, rets_addr,
(u8 *)mem + SIZEOF_STRUCT_MEM);
}*/
mem->rets_addr = rets_addr;
/*printf("malloc: %x\n", (u8 *)mem + SIZEOF_STRUCT_MEM);*/
return (u8_t *)mem + SIZEOF_STRUCT_MEM;
}
}
SBRK_MEM:
#define SBRK_PTR_ALIGN_FORWARD(ptr) (struct mem *)(((mem_ptr_t)ptr) & ~(mem_ptr_t)(MEM_HEAP_ALIGNMENT-1))
#define SBRK_PTR_ALIGN_BACKWARD(ptr) (struct mem *)(((mem_ptr_t)ptr + MEM_HEAP_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_HEAP_ALIGNMENT-1))
// MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, (" +SBRK_MEM\r\n"));
;
u8_t ram_end_prev_unused_flag;
u8_t *sbrk_ptr;
struct mem *sbrk_head = (struct mem *) - 1;
struct mem *new_ram_end;
mem_size_t mem_heap_incr_size;
mem_size_t remain_size, need_size;
need_size = size + 2 * SIZEOF_STRUCT_MEM + 2 * MEM_HEAP_ALIGNMENT;
if (mem_heap.ram_end->prev->used == MEM_UNUSED) {
ram_end_prev_unused_flag = 1;
sbrk_ptr = sbrk(0);//detect sbrk_ptr
if (mem_heap.sbrk_end != sbrk_ptr) { //discontinuous
remain_size = 0;
} else {
remain_size = (mem_size_t)mem_heap.ram_end - ((mem_size_t)(mem_heap.ram_end->prev) + SIZEOF_STRUCT_MEM);
}
mem_heap_incr_size = need_size - remain_size;
} else {
ram_end_prev_unused_flag = 0;
mem_heap_incr_size = need_size;
}
sbrk_ptr = sbrk(mem_heap_incr_size);
if (sbrk_ptr == (void *) - 1) {
MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, ("1sbrk ret == NULL,sbrk_malloc: could not allocate %d bytes\n", (mem_size_t)mem_heap_incr_size));
MEM_STATS_INC(err);
MEM_HEAP_UNPROTECT();
malloc_dump();
return (void *)0;
}
if (mem_heap.sbrk_end != sbrk_ptr) { //discontinuous
sbrk_head = SBRK_PTR_ALIGN_BACKWARD(sbrk_ptr);
sbrk_head->prev = mem_heap.ram_end;
sbrk_head->used = MEM_UNUSED;
#if MEM_HEAP_ERROR_CHECK == 1
sbrk_head->check_after = MEM_HEAP_OVERFLOW_MAGIC;
sbrk_head->check_before = MEM_HEAP_OVERFLOW_MAGIC;
#endif
mem_heap.ram_end->next = sbrk_head;
}
mem_heap.sbrk_end = sbrk_ptr + mem_heap_incr_size;
new_ram_end = (struct mem *)((u8_t *)(SBRK_PTR_ALIGN_FORWARD(mem_heap.sbrk_end)) - SIZEOF_STRUCT_MEM);
new_ram_end->used = MEM_USED;
new_ram_end->next = new_ram_end;
#if MEM_HEAP_ERROR_CHECK == 1
new_ram_end->check_after = MEM_HEAP_OVERFLOW_MAGIC;
new_ram_end->check_before = MEM_HEAP_OVERFLOW_MAGIC;
#endif
if (sbrk_head == (struct mem *) - 1) { //continuous
if (ram_end_prev_unused_flag) {
new_ram_end->prev = mem_heap.ram_end->prev;
mem_heap.ram_end->prev->next = new_ram_end;
} else {
new_ram_end->prev = mem_heap.ram_end;
mem_heap.ram_end->next = new_ram_end;
mem_heap.ram_end->used = MEM_UNUSED;
}
} else {
new_ram_end->prev = sbrk_head;
sbrk_head->next = new_ram_end;
}
mem_heap.ram_end = new_ram_end;
mem_heap.mem_heap_size += mem_heap_incr_size;
MEM_STATS_AVAIL(avail, mem_heap.mem_heap_size);
sbrk_lfree = new_ram_end->prev;
goto MALLOC;
}
/**
* Contiguously allocates enough space for count objects that are size bytes
* of memory each and returns a pointer to the allocated memory.
*
* The allocated memory is filled with bytes of value zero.
*
* @param count number of objects to allocate
* @param size size of the objects to allocate
* @return pointer to allocated memory / NULL pointer if there is an error
*/
void *calloc(unsigned long count, unsigned long size)
{
void *p;
/* allocate 'count' objects of size 'size' */
p = malloc(count * size);
if (p) {
/* zero the memory */
memset(p, 0, count * size);
}
return p;
}
void *zalloc(unsigned long size)
{
void *p;
__asm__ volatile("%0 = rets ;" : "=r"(rets_addr));
call_from_zalloc = 1;
p = malloc(size);
/*printf("??????????????????????????malloc: %d, %x, %x\n", size, rets_addr, p);*/
call_from_zalloc = 0;
if (p) {
memset(p, 0, size);
}
return p;
}
void *realloc(void *rmem, unsigned long newsize)
{
mem_size_t size;
struct mem *new_mem;
struct mem *mem, *mem2;
void *new_rmem = (void *)0;
/* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */
MEM_HEAP_DECL_PROTECT();
/* Expand the size of the allocated memory region so that we can
adjust for alignment. */
newsize = MEM_HEAP_ALIGN_SIZE(newsize);
if (newsize < MIN_SIZE_ALIGNED) {
/* every data block must be at least MIN_SIZE_ALIGNED long */
newsize = MIN_SIZE_ALIGNED;
}
mem_heap_init();
if (rmem == (void *)0) {
rmem = malloc(newsize);
return rmem;
}
// MEM_HEAP_ASSERT("realloc: legal memory", ((u8_t *)rmem >= (u8_t *)mem_heap.ram &&
// (u8_t *)rmem < (u8_t *)mem_heap.ram_end));
//
// if ((u8_t *)rmem < (u8_t *)mem_heap.ram || (u8_t *)rmem >= (u8_t *)mem_heap.ram_end) {
// MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, ("realloc: illegal memory\n"));
// /* protect mem stats from concurrent access */
// MEM_HEAP_PROTECT();
// MEM_STATS_INC(illegal);
// MEM_HEAP_UNPROTECT();
// return rmem;
// }
#define USE_FIX_MALLOC 1
/* protect the heap from concurrent access */
MEM_HEAP_PROTECT();
/* Get the corresponding struct mem ... */
mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
/* ... and its offset pointer */
size = (mem_size_t)(mem->next) - (mem_size_t)mem - SIZEOF_STRUCT_MEM;
#if USE_FIX_MALLOC == 0
MEM_HEAP_UNPROTECT();
#endif
if (newsize > size) {
#if USE_FIX_MALLOC == 1
if ((mem->next->used == MEM_UNUSED) && ((mem_size_t)(mem->next->next) - (mem_size_t)mem - SIZEOF_STRUCT_MEM >= newsize)) {
new_mem = (struct mem *)((mem_size_t)mem + SIZEOF_STRUCT_MEM + newsize);
if ((mem_size_t)(mem->next->next) - (mem_size_t)new_mem >= SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED) {
if (mem_heap.lfree == mem->next) {
mem_heap.lfree = new_mem;
}
if (mem_heap.ram_end->prev == mem->next) {
mem_heap.ram_end->prev = new_mem;
}
mem->next->next->prev = new_mem;
new_mem->next = mem->next->next;
new_mem->prev = mem;
new_mem->used = MEM_UNUSED;
#if MEM_HEAP_ERROR_CHECK == 1
new_mem->check_after = MEM_HEAP_OVERFLOW_MAGIC;
new_mem->check_before = MEM_HEAP_OVERFLOW_MAGIC;
#endif
mem->next = new_mem;
MEM_STATS_INC_USED(used, (newsize - size));
} else {
MEM_STATS_INC_USED(used, ((mem_size_t)mem->next->next - (mem_size_t)mem->next - SIZEOF_STRUCT_MEM));
if (mem_heap.lfree == mem->next) {
struct mem *cur = mem->next->next;
while ((cur->used == MEM_USED) && cur != mem_heap.ram_end) {
cur = cur->next;
}
mem_heap.lfree = cur;
}
if (mem_heap.ram_end->prev == mem->next) {
mem_heap.ram_end->prev = mem;
}
mem->next->next->prev = mem;
mem->next = mem->next->next;
}
MEM_HEAP_UNPROTECT();
return rmem;
} else {
MEM_HEAP_UNPROTECT();
new_rmem = malloc(newsize);
if (new_rmem != (void *)0) {
memmove(new_rmem, rmem, size);
free(rmem);
rmem = new_rmem;
return rmem;
} else {
MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, ("mem_realloc: could not allocate %d bytes\n", (mem_size_t)newsize));
return (void *)0;
}
}
#else
new_rmem = malloc(newsize);
if (new_rmem != (void *)0) {
memmove(new_rmem, rmem, size);
free(rmem);
rmem = new_rmem;
return rmem;
} else {
MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, ("mem_realloc: could not allocate %d bytes\n", (mem_size_t)newsize));
return (void *)0;
}
#endif
} else if (newsize < size) {
#if USE_FIX_MALLOC == 1
mem2 = mem->next;
if (mem2->used == MEM_UNUSED) {
/* The next struct is unused, we can simply move it at little */
struct mem *next;
/* remember the old next pointer */
next = mem2->next;
/* create new struct mem which is moved directly after the shrinked mem */
new_mem = (struct mem *)((mem_size_t)mem + SIZEOF_STRUCT_MEM + newsize);
if (mem_heap.lfree == mem2) {
mem_heap.lfree = new_mem;
}
if (mem_heap.ram_end->prev == mem2) {
mem_heap.ram_end->prev = new_mem;
}
#if MEM_HEAP_ERROR_CHECK == 1
new_mem->check_after = MEM_HEAP_OVERFLOW_MAGIC;
new_mem->check_before = MEM_HEAP_OVERFLOW_MAGIC;
#endif
mem2 = new_mem;
mem2->used = MEM_UNUSED;
/* restore the next pointer */
mem2->next = next;
/* link it back to mem */
mem2->prev = mem;
/* link mem to it */
mem->next = mem2;
/* last thing to restore linked list: as we have moved mem2,
* let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not
* the end of the heap */
if (mem2->next != mem_heap.ram_end) { //imposible?
mem2->next->prev = mem2;
}
MEM_STATS_DEC_USED(used, (size - newsize));
/* no need to plug holes, we've already done that */
} else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {
/* Next struct is used but there's room for another struct mem with
* at least MIN_SIZE_ALIGNED of data.
* Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem
* ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED').
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
* region that couldn't hold data, but when mem->next gets freed,
* the 2 regions would be combined, resulting in more free memory */
new_mem = (struct mem *)((mem_size_t)mem + SIZEOF_STRUCT_MEM + newsize);
#if MEM_HEAP_ERROR_CHECK == 1
new_mem->check_after = MEM_HEAP_OVERFLOW_MAGIC;
new_mem->check_before = MEM_HEAP_OVERFLOW_MAGIC;
#endif
mem2 = new_mem;
if (mem2 < mem_heap.lfree) {
mem_heap.lfree = mem2;
}
mem2->used = MEM_UNUSED;
mem2->next = mem->next;
mem2->prev = mem;
mem->next = mem2;
if (mem2->next != mem_heap.ram_end) {
mem2->next->prev = mem2;
}
if (mem_heap.ram_end->prev == mem) {
mem_heap.ram_end->prev = mem2;
}
MEM_STATS_DEC_USED(used, (size - newsize - SIZEOF_STRUCT_MEM));
/* the original mem->next is used, so no need to plug holes! */
}
/* else {
next struct mem is used but size between mem and mem2 is not big enough
to create another struct mem
-> don't do anyhting.
-> the remaining space stays unused since it is too small
} */
MEM_HEAP_UNPROTECT();
return rmem;
#else
return rmem;
#endif
} else if (newsize == size) {
#if USE_FIX_MALLOC == 1
MEM_HEAP_UNPROTECT();
#endif
/* No change in size, simply return */
return rmem;
}
return (void *)0;
}
#if MEM_HEAP_ERROR_CHECK == 1
void mem_heap_check(const char *const func, unsigned int line)
{
MEM_HEAP_DECL_PROTECT();
MEM_HEAP_PROTECT();
struct mem *mem;
for (mem = (struct mem *)mem_heap.ram; mem != mem_heap.ram_end->prev; mem = mem->next) {
if (((u32_t)mem > (u32_t)mem_heap.ram + mem_heap.mem_heap_size + SIZEOF_STRUCT_MEM)
|| ((u32_t)mem < (u32_t)mem_heap.ram)
|| ((u32_t)mem->next > (u32_t)mem_heap.ram + mem_heap.mem_heap_size + SIZEOF_STRUCT_MEM)
|| ((u32_t)mem->next < (u32_t)mem_heap.ram)
|| ((u32_t)mem->prev > (u32_t)mem_heap.ram + mem_heap.mem_heap_size + SIZEOF_STRUCT_MEM)
|| ((u32_t)mem->prev < (u32_t)mem_heap.ram)
|| ((mem->used != MEM_USED) && (mem->used != MEM_UNUSED))
|| (mem->check_before != MEM_HEAP_OVERFLOW_MAGIC)
|| (mem->check_after != MEM_HEAP_OVERFLOW_MAGIC)
) {
printf("{%s, %d", func, line);
printf("\n\n\n\n\n\n\n\nmem_heap was maliciously modified:\n"\
"mem_heap.ram = 0x%x\n"\
"mem_heap.mem_heap_size = 0x%x\n"\
"mem = 0x%x\n"\
"mem->next = 0x%x\n"\
"mem->prev = 0x%x\n"\
"mem->used = 0x%x\n"\
"mem->rets_addr = 0x%x\n"\
"mem->check_before = 0x%x\n"\
"mem->check_after = 0x%x\n\n\n\n\n\n\n\n\n", \
(u32_t)mem_heap.ram, mem_heap.mem_heap_size, (u32_t)mem, (u32_t)mem->next, (u32_t)mem->prev,
mem->used, mem->rets_addr, mem->check_before, mem->check_after);
while (1);
}
}
// if(func)
// {
// puts("}");
// }
MEM_HEAP_UNPROTECT();
}
#endif
#define SBRK_INTERNAL
#ifdef SBRK_INTERNAL
static void *sbrk(int increment)
{
static unsigned char *__init_addr = 0;
unsigned char *ret;
if (__init_addr == 0) {
__init_addr = (u8 *)&HEAP_BEGIN;
}
if ((__init_addr + increment >= (u8 *)&HEAP_END) && (increment > 0)) {
return (void *) - 1;
}
ret = __init_addr;
__init_addr += increment;
// printf("increment = %x sbrk %x %x %x", increment , ret ,&HEAP_BEGIN ,&HEAP_END ) ;
return ret;
}
#endif
void *pvPortMalloc(unsigned long xWantedSize)
{
return malloc(xWantedSize);
}
void vPortFree(void *pv)
{
free(pv);
}
void *kmalloc(unsigned long size, int flags)
{
return malloc(size);
}
void *vmalloc(unsigned long size)
{
return malloc(size);
}
void vfree(void *addr)
{
free(addr);
}
void *kzalloc(unsigned int len, int a)
{
return calloc(1, len);
}
void kfree(void *p)
{
free(p);
}
void memory_init(void)
{
}