Transition to hekate bdk layout
This commit is contained in:
parent
4425e81085
commit
4ffd4ce7f0
317 changed files with 60891 additions and 1003 deletions
470
bdk/libs/lvgl/lv_misc/lv_mem.c
Normal file
470
bdk/libs/lvgl/lv_misc/lv_mem.c
Normal file
|
@ -0,0 +1,470 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_mem.c
|
||||
* General and portable implementation of malloc and free.
|
||||
* The dynamic memory monitoring is also supported.
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_mem.h"
|
||||
#include "lv_math.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#if LV_MEM_CUSTOM != 0
|
||||
#include LV_MEM_CUSTOM_INCLUDE
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_MEM_ADD_JUNK 0 /*Add memory junk on alloc (0xaa) and free(0xbb) (just for testing purposes)*/
|
||||
|
||||
|
||||
#ifdef LV_MEM_ENV64
|
||||
# define MEM_UNIT uint64_t
|
||||
#else
|
||||
# define MEM_UNIT uint32_t
|
||||
#endif
|
||||
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
#if LV_ENABLE_GC == 0 /*gc custom allocations must not include header*/
|
||||
|
||||
/*The size of this union must be 32 bytes (uint32_t * 8)*/
|
||||
typedef union {
|
||||
struct {
|
||||
MEM_UNIT used: 1; //1: if the entry is used
|
||||
MEM_UNIT d_size: 31; //Size of the data
|
||||
};
|
||||
MEM_UNIT header; //The header (used + d_size)
|
||||
MEM_UNIT align[8]; //Align header size to MEM_UNIT * 8 bytes
|
||||
} lv_mem_header_t;
|
||||
|
||||
static_assert(sizeof(lv_mem_header_t) == 32, "Node header must be 32 bytes!");
|
||||
|
||||
typedef struct {
|
||||
lv_mem_header_t header;
|
||||
uint8_t first_data; /*First data byte in the allocated data (Just for easily create a pointer)*/
|
||||
} lv_mem_ent_t;
|
||||
|
||||
#endif /* LV_ENABLE_GC */
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e);
|
||||
static void * ent_alloc(lv_mem_ent_t * e, uint32_t size);
|
||||
static void ent_trunc(lv_mem_ent_t * e, uint32_t size);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
static uint8_t * work_mem;
|
||||
#endif
|
||||
|
||||
static uint32_t zero_mem; /*Give the address of this variable if 0 byte should be allocated*/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initiaiize the dyn_mem module (work memory and other variables)
|
||||
*/
|
||||
void lv_mem_init(void)
|
||||
{
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
|
||||
#if LV_MEM_ADR == 0
|
||||
/*Allocate a large array to store the dynamically allocated data*/
|
||||
static LV_MEM_ATTR MEM_UNIT work_mem_int[LV_MEM_SIZE / sizeof(MEM_UNIT)];
|
||||
work_mem = (uint8_t *) work_mem_int;
|
||||
#else
|
||||
work_mem = (uint8_t *) LV_MEM_ADR;
|
||||
#endif
|
||||
|
||||
lv_mem_ent_t * full = (lv_mem_ent_t *)work_mem;
|
||||
full->header.used = 0;
|
||||
/*The total mem size id reduced by the first header and the close patterns */
|
||||
full->header.d_size = LV_MEM_SIZE - sizeof(lv_mem_header_t);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a memory dynamically
|
||||
* @param size size of the memory to allocate in bytes
|
||||
* @return pointer to the allocated memory
|
||||
*/
|
||||
void * lv_mem_alloc(uint32_t size)
|
||||
{
|
||||
if(size == 0) {
|
||||
return &zero_mem;
|
||||
}
|
||||
|
||||
/*Round the size to lv_mem_header_t*/
|
||||
if(size & (sizeof(lv_mem_header_t) - 1)) {
|
||||
size = size & (~(sizeof(lv_mem_header_t) - 1));
|
||||
size += sizeof(lv_mem_header_t);
|
||||
}
|
||||
|
||||
void * alloc = NULL;
|
||||
|
||||
#if LV_MEM_CUSTOM == 0 /*Use the allocation from dyn_mem*/
|
||||
lv_mem_ent_t * e = NULL;
|
||||
|
||||
//Search for a appropriate entry
|
||||
do {
|
||||
//Get the next entry
|
||||
e = ent_get_next(e);
|
||||
|
||||
/*If there is next entry then try to allocate there*/
|
||||
if(e != NULL) {
|
||||
alloc = ent_alloc(e, size);
|
||||
}
|
||||
//End if there is not next entry OR the alloc. is successful
|
||||
} while(e != NULL && alloc == NULL);
|
||||
|
||||
|
||||
#else /*Use custom, user defined malloc function*/
|
||||
#if LV_ENABLE_GC == 1 /*gc must not include header*/
|
||||
alloc = LV_MEM_CUSTOM_ALLOC(size);
|
||||
#else /* LV_ENABLE_GC */
|
||||
/*Allocate a header too to store the size*/
|
||||
alloc = LV_MEM_CUSTOM_ALLOC(size + sizeof(lv_mem_header_t));
|
||||
if(alloc != NULL) {
|
||||
((lv_mem_ent_t *) alloc)->header.d_size = size;
|
||||
((lv_mem_ent_t *) alloc)->header.used = 1;
|
||||
alloc = &((lv_mem_ent_t *) alloc)->first_data;
|
||||
}
|
||||
#endif /* LV_ENABLE_GC */
|
||||
#endif /* LV_MEM_CUSTOM */
|
||||
|
||||
#if LV_MEM_ADD_JUNK
|
||||
if(alloc != NULL) memset(alloc, 0xaa, size);
|
||||
#endif
|
||||
|
||||
if(alloc == NULL) LV_LOG_WARN("Couldn't allocate memory");
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free an allocated data
|
||||
* @param data pointer to an allocated memory
|
||||
*/
|
||||
void lv_mem_free(const void * data)
|
||||
{
|
||||
if(data == &zero_mem) return;
|
||||
if(data == NULL) return;
|
||||
|
||||
|
||||
#if LV_MEM_ADD_JUNK
|
||||
memset((void *)data, 0xbb, lv_mem_get_size(data));
|
||||
#endif
|
||||
|
||||
#if LV_ENABLE_GC==0
|
||||
/*e points to the header*/
|
||||
lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data - sizeof(lv_mem_header_t));
|
||||
e->header.used = 0;
|
||||
#endif
|
||||
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
#if LV_MEM_AUTO_DEFRAG
|
||||
/* Make a simple defrag.
|
||||
* Join the following free entries after this*/
|
||||
lv_mem_ent_t * e_next;
|
||||
e_next = ent_get_next(e);
|
||||
while(e_next != NULL) {
|
||||
if(e_next->header.used == 0) {
|
||||
e->header.d_size += e_next->header.d_size + sizeof(e->header);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
e_next = ent_get_next(e_next);
|
||||
}
|
||||
#endif
|
||||
#else /*Use custom, user defined free function*/
|
||||
#if LV_ENABLE_GC==0
|
||||
LV_MEM_CUSTOM_FREE(e);
|
||||
#else
|
||||
LV_MEM_CUSTOM_FREE((void*)data);
|
||||
#endif /*LV_ENABLE_GC*/
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Reallocate a memory with a new size. The old content will be kept.
|
||||
* @param data pointer to an allocated memory.
|
||||
* Its content will be copied to the new memory block and freed
|
||||
* @param new_size the desired new size in byte
|
||||
* @return pointer to the new memory
|
||||
*/
|
||||
|
||||
#if LV_ENABLE_GC==0
|
||||
|
||||
void * lv_mem_realloc(void * data_p, uint32_t new_size)
|
||||
{
|
||||
/*Round the size to lv_mem_header_t*/
|
||||
if(new_size & (sizeof(lv_mem_header_t) - 1)) {
|
||||
new_size = new_size & (~(sizeof(lv_mem_header_t) - 1));
|
||||
new_size += sizeof(lv_mem_header_t);
|
||||
}
|
||||
|
||||
/*data_p could be previously freed pointer (in this case it is invalid)*/
|
||||
if(data_p != NULL) {
|
||||
lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data_p - sizeof(lv_mem_header_t));
|
||||
if(e->header.used == 0) {
|
||||
data_p = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t old_size = lv_mem_get_size(data_p);
|
||||
if(old_size == new_size) return data_p; /*Also avoid reallocating the same memory*/
|
||||
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
/* Only truncate the memory is possible
|
||||
* If the 'old_size' was extended by a header size in 'ent_trunc' it avoids reallocating this same memory */
|
||||
if(new_size < old_size) {
|
||||
lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data_p - sizeof(lv_mem_header_t));
|
||||
ent_trunc(e, new_size);
|
||||
return &e->first_data;
|
||||
}
|
||||
#endif
|
||||
|
||||
void * new_p;
|
||||
new_p = lv_mem_alloc(new_size);
|
||||
|
||||
if(new_p != NULL && data_p != NULL) {
|
||||
/*Copy the old data to the new. Use the smaller size*/
|
||||
if(old_size != 0) {
|
||||
memcpy(new_p, data_p, LV_MATH_MIN(new_size, old_size));
|
||||
lv_mem_free(data_p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(new_p == NULL) LV_LOG_WARN("Couldn't allocate memory");
|
||||
|
||||
return new_p;
|
||||
}
|
||||
|
||||
#else /* LV_ENABLE_GC */
|
||||
|
||||
void * lv_mem_realloc(void * data_p, uint32_t new_size)
|
||||
{
|
||||
void * new_p = LV_MEM_CUSTOM_REALLOC(data_p, new_size);
|
||||
if(new_p == NULL) LV_LOG_WARN("Couldn't allocate memory");
|
||||
return new_p;
|
||||
}
|
||||
|
||||
#endif /* lv_enable_gc */
|
||||
|
||||
/**
|
||||
* Join the adjacent free memory blocks
|
||||
*/
|
||||
void lv_mem_defrag(void)
|
||||
{
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
lv_mem_ent_t * e_free;
|
||||
lv_mem_ent_t * e_next;
|
||||
e_free = ent_get_next(NULL);
|
||||
|
||||
while(1) {
|
||||
/*Search the next free entry*/
|
||||
while(e_free != NULL) {
|
||||
if(e_free->header.used != 0) {
|
||||
e_free = ent_get_next(e_free);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(e_free == NULL) return;
|
||||
|
||||
/*Joint the following free entries to the free*/
|
||||
e_next = ent_get_next(e_free);
|
||||
while(e_next != NULL) {
|
||||
if(e_next->header.used == 0) {
|
||||
e_free->header.d_size += e_next->header.d_size + sizeof(e_next->header);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
e_next = ent_get_next(e_next);
|
||||
}
|
||||
|
||||
if(e_next == NULL) return;
|
||||
|
||||
/*Continue from the lastly checked entry*/
|
||||
e_free = e_next;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Give information about the work memory of dynamic allocation
|
||||
* @param mon_p pointer to a dm_mon_p variable,
|
||||
* the result of the analysis will be stored here
|
||||
*/
|
||||
void lv_mem_monitor(lv_mem_monitor_t * mon_p)
|
||||
{
|
||||
/*Init the data*/
|
||||
memset(mon_p, 0, sizeof(lv_mem_monitor_t));
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
lv_mem_ent_t * e;
|
||||
e = NULL;
|
||||
|
||||
e = ent_get_next(e);
|
||||
|
||||
while(e != NULL) {
|
||||
if(e->header.used == 0) {
|
||||
mon_p->free_cnt++;
|
||||
mon_p->free_size += e->header.d_size;
|
||||
if(e->header.d_size > mon_p->free_biggest_size) {
|
||||
mon_p->free_biggest_size = e->header.d_size;
|
||||
}
|
||||
} else {
|
||||
mon_p->used_cnt++;
|
||||
}
|
||||
|
||||
e = ent_get_next(e);
|
||||
}
|
||||
mon_p->total_size = LV_MEM_SIZE;
|
||||
mon_p->used_pct = 100 - ((uint64_t)100U * mon_p->free_size) / mon_p->total_size;
|
||||
mon_p->frag_pct = (uint32_t)mon_p->free_biggest_size * 100U / mon_p->free_size;
|
||||
mon_p->frag_pct = 100 - mon_p->frag_pct;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the size of an allocated memory
|
||||
* @param data pointer to an allocated memory
|
||||
* @return the size of data memory in bytes
|
||||
*/
|
||||
|
||||
#if LV_ENABLE_GC==0
|
||||
|
||||
uint32_t lv_mem_get_size(const void * data)
|
||||
{
|
||||
if(data == NULL) return 0;
|
||||
if(data == &zero_mem) return 0;
|
||||
|
||||
lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data - sizeof(lv_mem_header_t));
|
||||
|
||||
return e->header.d_size;
|
||||
}
|
||||
|
||||
#else /* LV_ENABLE_GC */
|
||||
|
||||
uint32_t lv_mem_get_size(const void * data)
|
||||
{
|
||||
return LV_MEM_CUSTOM_GET_SIZE(data);
|
||||
}
|
||||
|
||||
#endif /*LV_ENABLE_GC*/
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
/**
|
||||
* Give the next entry after 'act_e'
|
||||
* @param act_e pointer to an entry
|
||||
* @return pointer to an entry after 'act_e'
|
||||
*/
|
||||
static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e)
|
||||
{
|
||||
lv_mem_ent_t * next_e = NULL;
|
||||
|
||||
if(act_e == NULL) { /*NULL means: get the first entry*/
|
||||
next_e = (lv_mem_ent_t *) work_mem;
|
||||
} else { /*Get the next entry */
|
||||
uint8_t * data = &act_e->first_data;
|
||||
next_e = (lv_mem_ent_t *)&data[act_e->header.d_size];
|
||||
|
||||
if(&next_e->first_data >= &work_mem[LV_MEM_SIZE]) next_e = NULL;
|
||||
}
|
||||
|
||||
return next_e;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to do the real allocation with a given size
|
||||
* @param e try to allocate to this entry
|
||||
* @param size size of the new memory in bytes
|
||||
* @return pointer to the allocated memory or NULL if not enough memory in the entry
|
||||
*/
|
||||
static void * ent_alloc(lv_mem_ent_t * e, uint32_t size)
|
||||
{
|
||||
void * alloc = NULL;
|
||||
|
||||
/*If the memory is free and big enough then use it */
|
||||
if(e->header.used == 0 && e->header.d_size >= size) {
|
||||
/*Truncate the entry to the desired size */
|
||||
ent_trunc(e, size),
|
||||
|
||||
e->header.used = 1;
|
||||
|
||||
/*Save the allocated data*/
|
||||
alloc = &e->first_data;
|
||||
}
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate the data of entry to the given size
|
||||
* @param e Pointer to an entry
|
||||
* @param size new size in bytes
|
||||
*/
|
||||
static void ent_trunc(lv_mem_ent_t * e, uint32_t size)
|
||||
{
|
||||
/*Don't let empty space only for a header without data*/
|
||||
if(e->header.d_size == size + sizeof(lv_mem_header_t)) {
|
||||
size = e->header.d_size;
|
||||
}
|
||||
|
||||
/* Create the new entry after the current if there is space for it */
|
||||
if(e->header.d_size != size) {
|
||||
uint8_t * e_data = &e->first_data;
|
||||
lv_mem_ent_t * after_new_e = (lv_mem_ent_t *)&e_data[size];
|
||||
after_new_e->header.used = 0;
|
||||
after_new_e->header.d_size = e->header.d_size - size - sizeof(lv_mem_header_t);
|
||||
}
|
||||
|
||||
/* Set the new size for the original entry */
|
||||
e->header.d_size = size;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue