mirror of https://github.com/ARMmbed/mbed-os.git
Merge commit '0613e29fde32daa609eb6ae4ad785112b8fd9729'
* commit '0613e29fde32daa609eb6ae4ad785112b8fd9729': Squashed 'features/FEATURE_COMMON_PAL/nanostack-libservice/' changes from 6444c8a..854505dpull/4715/head
commit
17f1111817
|
@ -18,8 +18,11 @@
|
||||||
/**
|
/**
|
||||||
* \file nsdynmemLIB.h
|
* \file nsdynmemLIB.h
|
||||||
* \brief Dynamical Memory API for library model
|
* \brief Dynamical Memory API for library model
|
||||||
*
|
* nsdynmemlib provides access to one default heap, along with the ability to use extra user heaps.
|
||||||
|
* ns_dyn_mem_alloc/free always access the default heap initialised by ns_dyn_mem_init.
|
||||||
|
* ns_mem_alloc/free access a user heap initialised by ns_mem_init. User heaps are identified by a book-keeping pointer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef NSDYNMEMLIB_H_
|
#ifndef NSDYNMEMLIB_H_
|
||||||
#define NSDYNMEMLIB_H_
|
#define NSDYNMEMLIB_H_
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -28,6 +31,12 @@ extern "C" {
|
||||||
|
|
||||||
#include "ns_types.h"
|
#include "ns_types.h"
|
||||||
|
|
||||||
|
// Added to maintain backward compatibility with older implementation of ns_dyn_mem APIs
|
||||||
|
#define NSDYNMEMLIB_API_VERSION 2
|
||||||
|
|
||||||
|
typedef uint16_t ns_mem_block_size_t; //external interface unsigned heap block size type
|
||||||
|
typedef uint16_t ns_mem_heap_size_t; //total heap size type.
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \enum heap_fail_t
|
* \enum heap_fail_t
|
||||||
* \brief Dynamically heap system failure call back event types.
|
* \brief Dynamically heap system failure call back event types.
|
||||||
|
@ -47,14 +56,17 @@ typedef enum {
|
||||||
*/
|
*/
|
||||||
typedef struct mem_stat_t {
|
typedef struct mem_stat_t {
|
||||||
/*Heap stats*/
|
/*Heap stats*/
|
||||||
int16_t heap_sector_size; /**< Heap total Sector len. */
|
ns_mem_heap_size_t heap_sector_size; /**< Heap total Sector len. */
|
||||||
int16_t heap_sector_alloc_cnt; /**< Reserved Heap sector cnt. */
|
ns_mem_heap_size_t heap_sector_alloc_cnt; /**< Reserved Heap sector cnt. */
|
||||||
int16_t heap_sector_allocated_bytes; /**< Reserved Heap data in bytes. */
|
ns_mem_heap_size_t heap_sector_allocated_bytes; /**< Reserved Heap data in bytes. */
|
||||||
int16_t heap_sector_allocated_bytes_max; /**< Reserved Heap data in bytes max value. */
|
ns_mem_heap_size_t heap_sector_allocated_bytes_max; /**< Reserved Heap data in bytes max value. */
|
||||||
uint32_t heap_alloc_total_bytes; /**< Total Heap allocated bytes. */
|
uint32_t heap_alloc_total_bytes; /**< Total Heap allocated bytes. */
|
||||||
uint32_t heap_alloc_fail_cnt; /**< Counter for Heap allocation fail. */
|
uint32_t heap_alloc_fail_cnt; /**< Counter for Heap allocation fail. */
|
||||||
} mem_stat_t;
|
} mem_stat_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ns_mem_book ns_mem_book_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Init and set Dynamical heap pointer and length.
|
* \brief Init and set Dynamical heap pointer and length.
|
||||||
*
|
*
|
||||||
|
@ -62,7 +74,7 @@ typedef struct mem_stat_t {
|
||||||
* \param heap_size size of the heap buffer
|
* \param heap_size size of the heap buffer
|
||||||
* \return None
|
* \return None
|
||||||
*/
|
*/
|
||||||
extern void ns_dyn_mem_init(uint8_t *heap, uint16_t h_size, void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr);
|
extern void ns_dyn_mem_init(void *heap, ns_mem_heap_size_t h_size, void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,7 +96,7 @@ extern void ns_dyn_mem_free(void *heap_ptr);
|
||||||
* \return 0, Allocate Fail
|
* \return 0, Allocate Fail
|
||||||
* \return >0, Pointer to allocated data sector.
|
* \return >0, Pointer to allocated data sector.
|
||||||
*/
|
*/
|
||||||
extern void *ns_dyn_mem_temporary_alloc(int16_t alloc_size);
|
extern void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size);
|
||||||
/**
|
/**
|
||||||
* \brief Allocate long period data.
|
* \brief Allocate long period data.
|
||||||
*
|
*
|
||||||
|
@ -95,7 +107,7 @@ extern void *ns_dyn_mem_temporary_alloc(int16_t alloc_size);
|
||||||
* \return 0, Allocate Fail
|
* \return 0, Allocate Fail
|
||||||
* \return >0, Pointer to allocated data sector.
|
* \return >0, Pointer to allocated data sector.
|
||||||
*/
|
*/
|
||||||
extern void *ns_dyn_mem_alloc(int16_t alloc_size);
|
extern void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Get pointer to the current mem_stat_t set via ns_dyn_mem_init.
|
* \brief Get pointer to the current mem_stat_t set via ns_dyn_mem_init.
|
||||||
|
@ -110,6 +122,65 @@ extern void *ns_dyn_mem_alloc(int16_t alloc_size);
|
||||||
*/
|
*/
|
||||||
extern const mem_stat_t *ns_dyn_mem_get_mem_stat(void);
|
extern const mem_stat_t *ns_dyn_mem_get_mem_stat(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Init and set Dynamical heap pointer and length.
|
||||||
|
*
|
||||||
|
* \param heap_ptr Pointer to dynamically heap buffer
|
||||||
|
* \param heap_size size of the heap buffer
|
||||||
|
* \return !=0, Pointer to ns_mem_book_t.
|
||||||
|
*/
|
||||||
|
extern ns_mem_book_t *ns_mem_init(void *heap, ns_mem_heap_size_t h_size, void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Free allocated memory.
|
||||||
|
*
|
||||||
|
* \param book Address of book keeping structure
|
||||||
|
* \param heap_ptr Pointer to allocated memory
|
||||||
|
*
|
||||||
|
* \return 0, Free OK
|
||||||
|
* \return <0, Free Fail
|
||||||
|
*/
|
||||||
|
extern void ns_mem_free(ns_mem_book_t *book, void *heap_ptr);
|
||||||
|
/**
|
||||||
|
* \brief Allocate temporary data.
|
||||||
|
*
|
||||||
|
* Space allocate started from beginning of the heap sector
|
||||||
|
*
|
||||||
|
* \param book Address of book keeping structure
|
||||||
|
* \param alloc_size Allocated data size
|
||||||
|
*
|
||||||
|
* \return 0, Allocate Fail
|
||||||
|
* \return >0, Pointer to allocated data sector.
|
||||||
|
*/
|
||||||
|
extern void *ns_mem_temporary_alloc(ns_mem_book_t *book, ns_mem_block_size_t alloc_size);
|
||||||
|
/**
|
||||||
|
* \brief Allocate long period data.
|
||||||
|
*
|
||||||
|
* Space allocate started from end of the heap sector
|
||||||
|
*
|
||||||
|
* \param book Address of book keeping structure
|
||||||
|
* \param alloc_size Allocated data size
|
||||||
|
*
|
||||||
|
* \return 0, Allocate Fail
|
||||||
|
* \return >0, Pointer to allocated data sector.
|
||||||
|
*/
|
||||||
|
extern void *ns_mem_alloc(ns_mem_book_t *book, ns_mem_block_size_t alloc_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get pointer to the current mem_stat_t set via ns_mem_init.
|
||||||
|
*
|
||||||
|
* Get pointer to the statistics information, if one is set during the
|
||||||
|
* initialization. This may be useful for statistics collection purposes.
|
||||||
|
*
|
||||||
|
* Note: the caller may not modify the returned structure.
|
||||||
|
*
|
||||||
|
* \param book Address of book keeping structure
|
||||||
|
*
|
||||||
|
* \return NULL, no mem_stat_t was given on initialization
|
||||||
|
* \return !=0, Pointer to mem_stat_t.
|
||||||
|
*/
|
||||||
|
extern const mem_stat_t *ns_mem_get_mem_stat(ns_mem_book_t *book);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
"extraIncludes": [
|
"extraIncludes": [
|
||||||
"mbed-client-libservice"
|
"mbed-client-libservice"
|
||||||
],
|
],
|
||||||
"dependencies": {},
|
"dependencies": {
|
||||||
|
"mbed-trace": "ARMmbed/mbed-trace"
|
||||||
|
},
|
||||||
"targetDependencies": {}
|
"targetDependencies": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,102 +20,128 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "ns_list.h"
|
#include "ns_list.h"
|
||||||
|
|
||||||
void (*heap_failure_callback)(heap_fail_t);
|
|
||||||
|
|
||||||
#ifndef STANDARD_MALLOC
|
#ifndef STANDARD_MALLOC
|
||||||
static int *heap_main = 0;
|
|
||||||
static int *heap_main_end = 0;
|
|
||||||
static uint16_t heap_size = 0;
|
|
||||||
|
|
||||||
typedef enum mem_stat_update_t {
|
typedef enum mem_stat_update_t {
|
||||||
DEV_HEAP_ALLOC_OK,
|
DEV_HEAP_ALLOC_OK,
|
||||||
DEV_HEAP_ALLOC_FAIL,
|
DEV_HEAP_ALLOC_FAIL,
|
||||||
DEV_HEAP_FREE,
|
DEV_HEAP_FREE,
|
||||||
} mem_stat_update_t;
|
} mem_stat_update_t;
|
||||||
|
|
||||||
|
|
||||||
static mem_stat_t *mem_stat_info_ptr = 0;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ns_list_link_t link;
|
ns_list_link_t link;
|
||||||
} hole_t;
|
} hole_t;
|
||||||
|
|
||||||
static NS_LIST_DEFINE(holes_list, hole_t, link);
|
typedef int ns_mem_word_size_t; // internal signed heap block size type
|
||||||
|
|
||||||
|
/* struct for book keeping variables */
|
||||||
|
struct ns_mem_book {
|
||||||
|
ns_mem_word_size_t *heap_main;
|
||||||
|
ns_mem_word_size_t *heap_main_end;
|
||||||
|
mem_stat_t *mem_stat_info_ptr;
|
||||||
|
void (*heap_failure_callback)(heap_fail_t);
|
||||||
|
NS_LIST_HEAD(hole_t, link) holes_list;
|
||||||
|
ns_mem_heap_size_t heap_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static ns_mem_book_t *default_book; // heap pointer for original "ns_" API use
|
||||||
|
|
||||||
// size of a hole_t in our word units
|
// size of a hole_t in our word units
|
||||||
#define HOLE_T_SIZE ((sizeof(hole_t) + sizeof(int) - 1) / sizeof(int))
|
#define HOLE_T_SIZE ((sizeof(hole_t) + sizeof(ns_mem_word_size_t) - 1) / sizeof(ns_mem_word_size_t))
|
||||||
|
|
||||||
static NS_INLINE hole_t *hole_from_block_start(int *start)
|
static NS_INLINE hole_t *hole_from_block_start(ns_mem_word_size_t *start)
|
||||||
{
|
{
|
||||||
return (hole_t *)(start + 1);
|
return (hole_t *)(start + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NS_INLINE int *block_start_from_hole(hole_t *start)
|
static NS_INLINE ns_mem_word_size_t *block_start_from_hole(hole_t *start)
|
||||||
{
|
{
|
||||||
return ((int *)start) - 1;
|
return ((ns_mem_word_size_t *)start) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void heap_failure(ns_mem_book_t *book, heap_fail_t reason)
|
||||||
static void heap_failure(heap_fail_t reason)
|
|
||||||
{
|
{
|
||||||
if (heap_failure_callback) {
|
if (book->heap_failure_callback) {
|
||||||
heap_failure_callback(reason);
|
book->heap_failure_callback(reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ns_dyn_mem_init(uint8_t *heap, uint16_t h_size, void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr)
|
void ns_dyn_mem_init(void *heap, ns_mem_heap_size_t h_size,
|
||||||
|
void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr)
|
||||||
{
|
{
|
||||||
#ifndef STANDARD_MALLOC
|
default_book = ns_mem_init(heap, h_size, passed_fptr, info_ptr);
|
||||||
int *ptr;
|
|
||||||
int temp_int;
|
|
||||||
/* Do memory alignment */
|
|
||||||
temp_int = ((uintptr_t)heap % sizeof(int));
|
|
||||||
if (temp_int) {
|
|
||||||
heap += (sizeof(int) - temp_int);
|
|
||||||
h_size -= (sizeof(int) - temp_int);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make correction for total length also */
|
|
||||||
temp_int = (h_size % sizeof(int));
|
|
||||||
if (temp_int) {
|
|
||||||
h_size -= (sizeof(int) - temp_int);
|
|
||||||
}
|
|
||||||
heap_main = (int *)heap; // SET Heap Pointer
|
|
||||||
heap_size = h_size; //Set Heap Size
|
|
||||||
temp_int = (h_size / sizeof(int));
|
|
||||||
temp_int -= 2;
|
|
||||||
ptr = heap_main;
|
|
||||||
*ptr = -(temp_int);
|
|
||||||
ptr += (temp_int + 1);
|
|
||||||
*ptr = -(temp_int);
|
|
||||||
heap_main_end = ptr;
|
|
||||||
|
|
||||||
ns_list_init(&holes_list);
|
|
||||||
ns_list_add_to_start(&holes_list, hole_from_block_start(heap_main));
|
|
||||||
|
|
||||||
//RESET Memory by Hea Len
|
|
||||||
if (info_ptr) {
|
|
||||||
mem_stat_info_ptr = info_ptr;
|
|
||||||
memset(mem_stat_info_ptr, 0, sizeof(mem_stat_t));
|
|
||||||
mem_stat_info_ptr->heap_sector_size = heap_size;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
heap_failure_callback = passed_fptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mem_stat_t *ns_dyn_mem_get_mem_stat(void)
|
const mem_stat_t *ns_dyn_mem_get_mem_stat(void)
|
||||||
{
|
{
|
||||||
#ifndef STANDARD_MALLOC
|
#ifndef STANDARD_MALLOC
|
||||||
return mem_stat_info_ptr;
|
return ns_mem_get_mem_stat(default_book);
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ns_mem_book_t *ns_mem_init(void *heap, ns_mem_heap_size_t h_size,
|
||||||
|
void (*passed_fptr)(heap_fail_t),
|
||||||
|
mem_stat_t *info_ptr)
|
||||||
|
{
|
||||||
|
#ifndef STANDARD_MALLOC
|
||||||
|
ns_mem_book_t *book;
|
||||||
|
|
||||||
|
ns_mem_word_size_t *ptr;
|
||||||
|
ns_mem_word_size_t temp_int;
|
||||||
|
/* Do memory alignment */
|
||||||
|
temp_int = ((uintptr_t)heap % sizeof(ns_mem_word_size_t));
|
||||||
|
if (temp_int) {
|
||||||
|
heap = (uint8_t *) heap + (sizeof(ns_mem_word_size_t) - temp_int);
|
||||||
|
h_size -= (sizeof(ns_mem_word_size_t) - temp_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make correction for total length also */
|
||||||
|
temp_int = (h_size % sizeof(ns_mem_word_size_t));
|
||||||
|
if (temp_int) {
|
||||||
|
h_size -= (sizeof(ns_mem_word_size_t) - temp_int);
|
||||||
|
}
|
||||||
|
book = heap;
|
||||||
|
book->heap_main = (ns_mem_word_size_t *)&(book[1]); // SET Heap Pointer
|
||||||
|
book->heap_size = h_size - sizeof(ns_mem_book_t); //Set Heap Size
|
||||||
|
temp_int = (book->heap_size / sizeof(ns_mem_word_size_t));
|
||||||
|
temp_int -= 2;
|
||||||
|
ptr = book->heap_main;
|
||||||
|
*ptr = -(temp_int);
|
||||||
|
ptr += (temp_int + 1);
|
||||||
|
*ptr = -(temp_int);
|
||||||
|
book->heap_main_end = ptr;
|
||||||
|
|
||||||
|
ns_list_init(&book->holes_list);
|
||||||
|
ns_list_add_to_start(&book->holes_list, hole_from_block_start(book->heap_main));
|
||||||
|
|
||||||
|
book->mem_stat_info_ptr = info_ptr;
|
||||||
|
//RESET Memory by Hea Len
|
||||||
|
if (info_ptr) {
|
||||||
|
memset(book->mem_stat_info_ptr, 0, sizeof(mem_stat_t));
|
||||||
|
book->mem_stat_info_ptr->heap_sector_size = book->heap_size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
//There really is no support to standard malloc in this library anymore
|
||||||
|
book->heap_failure_callback = passed_fptr;
|
||||||
|
|
||||||
|
return book;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mem_stat_t *ns_mem_get_mem_stat(ns_mem_book_t *heap)
|
||||||
|
{
|
||||||
|
#ifndef STANDARD_MALLOC
|
||||||
|
return heap->mem_stat_info_ptr;
|
||||||
#else
|
#else
|
||||||
return NULL;
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef STANDARD_MALLOC
|
#ifndef STANDARD_MALLOC
|
||||||
void dev_stat_update(mem_stat_update_t type, int16_t size)
|
static void dev_stat_update(mem_stat_t *mem_stat_info_ptr, mem_stat_update_t type, ns_mem_block_size_t size)
|
||||||
{
|
{
|
||||||
if (mem_stat_info_ptr) {
|
if (mem_stat_info_ptr) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -138,26 +164,27 @@ void dev_stat_update(mem_stat_update_t type, int16_t size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int convert_allocation_size(int16_t requested_bytes)
|
static ns_mem_word_size_t convert_allocation_size(ns_mem_book_t *book, ns_mem_block_size_t requested_bytes)
|
||||||
{
|
{
|
||||||
if (heap_main == 0) {
|
if (book->heap_main == 0) {
|
||||||
heap_failure(NS_DYN_MEM_HEAP_SECTOR_UNITIALIZED);
|
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_UNITIALIZED);
|
||||||
} else if (requested_bytes < 1) {
|
} else if (requested_bytes < 1) {
|
||||||
heap_failure(NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID);
|
heap_failure(book, NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID);
|
||||||
} else if ((size_t)requested_bytes > (heap_size - 2 * sizeof(int)) ) {
|
} else if (requested_bytes > (book->heap_size - 2 * sizeof(ns_mem_word_size_t)) ) {
|
||||||
heap_failure(NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID);
|
heap_failure(book, NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID);
|
||||||
}
|
}
|
||||||
return (requested_bytes + sizeof(int) - 1) / sizeof(int);
|
return (requested_bytes + sizeof(ns_mem_word_size_t) - 1) / sizeof(ns_mem_word_size_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks that block length indicators are valid
|
// Checks that block length indicators are valid
|
||||||
// Block has format: Size of data area [1 word] | data area [abs(size) words]| Size of data area [1 word]
|
// Block has format: Size of data area [1 word] | data area [abs(size) words]| Size of data area [1 word]
|
||||||
// If Size is negative it means area is unallocated
|
// If Size is negative it means area is unallocated
|
||||||
static int8_t ns_block_validate(int *block_start)
|
// For direction, use 1 for direction up and -1 for down
|
||||||
|
static int8_t ns_mem_block_validate(ns_mem_word_size_t *block_start, int direction)
|
||||||
{
|
{
|
||||||
int8_t ret_val = -1;
|
int8_t ret_val = -1;
|
||||||
int *end = block_start;
|
ns_mem_word_size_t *end = block_start;
|
||||||
int size_start = *end;
|
ns_mem_word_size_t size_start = *end;
|
||||||
end += (1 + abs(size_start));
|
end += (1 + abs(size_start));
|
||||||
if (size_start != 0 && size_start == *end) {
|
if (size_start != 0 && size_start == *end) {
|
||||||
ret_val = 0;
|
ret_val = 0;
|
||||||
|
@ -167,29 +194,35 @@ static int8_t ns_block_validate(int *block_start)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// For direction, use 1 for direction up and -1 for down
|
// For direction, use 1 for direction up and -1 for down
|
||||||
static void *ns_dyn_mem_internal_alloc(const int16_t alloc_size, int direction)
|
static void *ns_mem_internal_alloc(ns_mem_book_t *book, const ns_mem_block_size_t alloc_size, int direction)
|
||||||
{
|
{
|
||||||
#ifndef STANDARD_MALLOC
|
#ifndef STANDARD_MALLOC
|
||||||
int *block_ptr = NULL;
|
if (!book) {
|
||||||
|
/* We can not do anything except return NULL because we can't find book
|
||||||
|
keeping block */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ns_mem_word_size_t *block_ptr = NULL;
|
||||||
|
|
||||||
platform_enter_critical();
|
platform_enter_critical();
|
||||||
|
|
||||||
int data_size = convert_allocation_size(alloc_size);
|
ns_mem_word_size_t data_size = convert_allocation_size(book, alloc_size);
|
||||||
if (!data_size) {
|
if (!data_size) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ns_list_foreach, either forwards or backwards, result to ptr
|
// ns_list_foreach, either forwards or backwards, result to ptr
|
||||||
for (hole_t *cur_hole = direction > 0 ? ns_list_get_first(&holes_list)
|
for (hole_t *cur_hole = direction > 0 ? ns_list_get_first(&book->holes_list)
|
||||||
: ns_list_get_last(&holes_list);
|
: ns_list_get_last(&book->holes_list);
|
||||||
cur_hole;
|
cur_hole;
|
||||||
cur_hole = direction > 0 ? ns_list_get_next(&holes_list, cur_hole)
|
cur_hole = direction > 0 ? ns_list_get_next(&book->holes_list, cur_hole)
|
||||||
: ns_list_get_previous(&holes_list, cur_hole)
|
: ns_list_get_previous(&book->holes_list, cur_hole)
|
||||||
) {
|
) {
|
||||||
int *p = block_start_from_hole(cur_hole);
|
ns_mem_word_size_t *p = block_start_from_hole(cur_hole);
|
||||||
if (ns_block_validate(p) != 0 || *p >= 0) {
|
if (ns_mem_block_validate(p, direction) != 0 || *p >= 0) {
|
||||||
//Validation failed, or this supposed hole has positive (allocated) size
|
//Validation failed, or this supposed hole has positive (allocated) size
|
||||||
heap_failure(NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
|
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (-*p >= data_size) {
|
if (-*p >= data_size) {
|
||||||
|
@ -203,10 +236,10 @@ static void *ns_dyn_mem_internal_alloc(const int16_t alloc_size, int direction)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t block_data_size = -*block_ptr;
|
ns_mem_word_size_t block_data_size = -*block_ptr;
|
||||||
if (block_data_size >= (data_size + 2 + HOLE_T_SIZE)) {
|
if (block_data_size >= (data_size + 2 + HOLE_T_SIZE)) {
|
||||||
int hole_size = block_data_size - data_size - 2;
|
ns_mem_word_size_t hole_size = block_data_size - data_size - 2;
|
||||||
int *hole_ptr;
|
ns_mem_word_size_t *hole_ptr;
|
||||||
//There is enough room for a new hole so create it first
|
//There is enough room for a new hole so create it first
|
||||||
if ( direction > 0 ) {
|
if ( direction > 0 ) {
|
||||||
hole_ptr = block_ptr + 1 + data_size + 1;
|
hole_ptr = block_ptr + 1 + data_size + 1;
|
||||||
|
@ -214,12 +247,12 @@ static void *ns_dyn_mem_internal_alloc(const int16_t alloc_size, int direction)
|
||||||
// Would like to just replace this block_ptr with new descriptor, but
|
// Would like to just replace this block_ptr with new descriptor, but
|
||||||
// they could overlap, so ns_list_replace might fail
|
// they could overlap, so ns_list_replace might fail
|
||||||
//ns_list_replace(&holes_list, block_ptr, hole_from_block_start(hole_ptr));
|
//ns_list_replace(&holes_list, block_ptr, hole_from_block_start(hole_ptr));
|
||||||
hole_t *before = ns_list_get_previous(&holes_list, hole_from_block_start(block_ptr));
|
hole_t *before = ns_list_get_previous(&book->holes_list, hole_from_block_start(block_ptr));
|
||||||
ns_list_remove(&holes_list, hole_from_block_start(block_ptr));
|
ns_list_remove(&book->holes_list, hole_from_block_start(block_ptr));
|
||||||
if (before) {
|
if (before) {
|
||||||
ns_list_add_after(&holes_list, before, hole_from_block_start(hole_ptr));
|
ns_list_add_after(&book->holes_list, before, hole_from_block_start(hole_ptr));
|
||||||
} else {
|
} else {
|
||||||
ns_list_add_to_start(&holes_list, hole_from_block_start(hole_ptr));
|
ns_list_add_to_start(&book->holes_list, hole_from_block_start(hole_ptr));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hole_ptr = block_ptr;
|
hole_ptr = block_ptr;
|
||||||
|
@ -232,20 +265,20 @@ static void *ns_dyn_mem_internal_alloc(const int16_t alloc_size, int direction)
|
||||||
} else {
|
} else {
|
||||||
// Not enough room for a left-over hole, so use the whole block
|
// Not enough room for a left-over hole, so use the whole block
|
||||||
data_size = block_data_size;
|
data_size = block_data_size;
|
||||||
ns_list_remove(&holes_list, hole_from_block_start(block_ptr));
|
ns_list_remove(&book->holes_list, hole_from_block_start(block_ptr));
|
||||||
}
|
}
|
||||||
block_ptr[0] = data_size;
|
block_ptr[0] = data_size;
|
||||||
block_ptr[1 + data_size] = data_size;
|
block_ptr[1 + data_size] = data_size;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (mem_stat_info_ptr) {
|
if (book->mem_stat_info_ptr) {
|
||||||
if (block_ptr) {
|
if (block_ptr) {
|
||||||
//Update Allocate OK
|
//Update Allocate OK
|
||||||
dev_stat_update(DEV_HEAP_ALLOC_OK, (data_size + 2) * sizeof(int));
|
dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_OK, (data_size + 2) * sizeof(ns_mem_word_size_t));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//Update Allocate Fail, second parameter is not used for stats
|
//Update Allocate Fail, second parameter is not used for stats
|
||||||
dev_stat_update(DEV_HEAP_ALLOC_FAIL, 0);
|
dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
platform_exit_critical();
|
platform_exit_critical();
|
||||||
|
@ -262,18 +295,28 @@ static void *ns_dyn_mem_internal_alloc(const int16_t alloc_size, int direction)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void *ns_dyn_mem_alloc(int16_t alloc_size)
|
void *ns_mem_alloc(ns_mem_book_t *heap, ns_mem_block_size_t alloc_size)
|
||||||
{
|
{
|
||||||
return ns_dyn_mem_internal_alloc(alloc_size, -1);
|
return ns_mem_internal_alloc(heap, alloc_size, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *ns_dyn_mem_temporary_alloc(int16_t alloc_size)
|
void *ns_mem_temporary_alloc(ns_mem_book_t *heap, ns_mem_block_size_t alloc_size)
|
||||||
{
|
{
|
||||||
return ns_dyn_mem_internal_alloc(alloc_size, 1);
|
return ns_mem_internal_alloc(heap, alloc_size, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size)
|
||||||
|
{
|
||||||
|
return ns_mem_alloc(default_book, alloc_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size)
|
||||||
|
{
|
||||||
|
return ns_mem_temporary_alloc(default_book, alloc_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef STANDARD_MALLOC
|
#ifndef STANDARD_MALLOC
|
||||||
static void ns_free_and_merge_with_adjacent_blocks(int * const cur_block, int data_size)
|
static void ns_mem_free_and_merge_with_adjacent_blocks(ns_mem_book_t *book, ns_mem_word_size_t *cur_block, ns_mem_word_size_t data_size)
|
||||||
{
|
{
|
||||||
// Theory of operation: Block is always in form | Len | Data | Len |
|
// Theory of operation: Block is always in form | Len | Data | Len |
|
||||||
// So we need to check length of previous (if current not heap start)
|
// So we need to check length of previous (if current not heap start)
|
||||||
|
@ -282,21 +325,21 @@ static void ns_free_and_merge_with_adjacent_blocks(int * const cur_block, int da
|
||||||
|
|
||||||
hole_t *existing_start = NULL;
|
hole_t *existing_start = NULL;
|
||||||
hole_t *existing_end = NULL;
|
hole_t *existing_end = NULL;
|
||||||
int *start = cur_block;
|
ns_mem_word_size_t *start = cur_block;
|
||||||
int *end = cur_block + data_size + 1;
|
ns_mem_word_size_t *end = cur_block + data_size + 1;
|
||||||
//invalidate current block
|
//invalidate current block
|
||||||
*start = -data_size;
|
*start = -data_size;
|
||||||
*end = -data_size;
|
*end = -data_size;
|
||||||
size_t merged_data_size = data_size;
|
ns_mem_word_size_t merged_data_size = data_size;
|
||||||
|
|
||||||
if (start != heap_main) {
|
if (start != book->heap_main) {
|
||||||
if (*(start - 1) < 0) {
|
if (*(start - 1) < 0) {
|
||||||
int *block_end = start - 1;
|
int *block_end = start - 1;
|
||||||
size_t block_size = 1 + (-*block_end) + 1;
|
size_t block_size = 1 + (-*block_end) + 1;
|
||||||
merged_data_size += block_size;
|
merged_data_size += block_size;
|
||||||
start -= block_size;
|
start -= block_size;
|
||||||
if (*start != *block_end) {
|
if (*start != *block_end) {
|
||||||
heap_failure(NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
|
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
|
||||||
}
|
}
|
||||||
if (block_size >= 1 + HOLE_T_SIZE + 1) {
|
if (block_size >= 1 + HOLE_T_SIZE + 1) {
|
||||||
existing_start = hole_from_block_start(start);
|
existing_start = hole_from_block_start(start);
|
||||||
|
@ -304,14 +347,14 @@ static void ns_free_and_merge_with_adjacent_blocks(int * const cur_block, int da
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end != heap_main_end) {
|
if (end != book->heap_main_end) {
|
||||||
if (*(end + 1) < 0) {
|
if (*(end + 1) < 0) {
|
||||||
int *block_start = end + 1;
|
int *block_start = end + 1;
|
||||||
size_t block_size = 1 + (-*block_start) + 1;
|
size_t block_size = 1 + (-*block_start) + 1;
|
||||||
merged_data_size += block_size;
|
merged_data_size += block_size;
|
||||||
end += block_size;
|
end += block_size;
|
||||||
if (*end != *block_start) {
|
if (*end != *block_start) {
|
||||||
heap_failure(NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
|
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
|
||||||
}
|
}
|
||||||
if (block_size >= 1 + HOLE_T_SIZE + 1) {
|
if (block_size >= 1 + HOLE_T_SIZE + 1) {
|
||||||
existing_end = hole_from_block_start(block_start);
|
existing_end = hole_from_block_start(block_start);
|
||||||
|
@ -326,8 +369,8 @@ static void ns_free_and_merge_with_adjacent_blocks(int * const cur_block, int da
|
||||||
// Will replace with descriptor at bottom of merged block.
|
// Will replace with descriptor at bottom of merged block.
|
||||||
// (Can't use ns_list_replace, because of danger of overlap)
|
// (Can't use ns_list_replace, because of danger of overlap)
|
||||||
// Optimisation - note our position for insertion below.
|
// Optimisation - note our position for insertion below.
|
||||||
before = ns_list_get_next(&holes_list, existing_end);
|
before = ns_list_get_next(&book->holes_list, existing_end);
|
||||||
ns_list_remove(&holes_list, existing_end);
|
ns_list_remove(&book->holes_list, existing_end);
|
||||||
}
|
}
|
||||||
if (existing_start) {
|
if (existing_start) {
|
||||||
// Extending hole described by "existing_start" upwards.
|
// Extending hole described by "existing_start" upwards.
|
||||||
|
@ -340,7 +383,7 @@ static void ns_free_and_merge_with_adjacent_blocks(int * const cur_block, int da
|
||||||
// Locate hole position in list, if we don't already know
|
// Locate hole position in list, if we don't already know
|
||||||
// from merging with the block above.
|
// from merging with the block above.
|
||||||
if (!existing_end) {
|
if (!existing_end) {
|
||||||
ns_list_foreach(hole_t, ptr, &holes_list) {
|
ns_list_foreach(hole_t, ptr, &book->holes_list) {
|
||||||
if (ptr > to_add) {
|
if (ptr > to_add) {
|
||||||
before = ptr;
|
before = ptr;
|
||||||
break;
|
break;
|
||||||
|
@ -348,9 +391,9 @@ static void ns_free_and_merge_with_adjacent_blocks(int * const cur_block, int da
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (before) {
|
if (before) {
|
||||||
ns_list_add_before(&holes_list, before, to_add);
|
ns_list_add_before(&book->holes_list, before, to_add);
|
||||||
} else {
|
} else {
|
||||||
ns_list_add_to_end(&holes_list, to_add);
|
ns_list_add_to_end(&book->holes_list, to_add);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -360,39 +403,35 @@ static void ns_free_and_merge_with_adjacent_blocks(int * const cur_block, int da
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ns_dyn_mem_free(void *block)
|
void ns_mem_free(ns_mem_book_t *book, void *block)
|
||||||
{
|
{
|
||||||
#ifndef STANDARD_MALLOC
|
#ifndef STANDARD_MALLOC
|
||||||
int *ptr = block;
|
|
||||||
int size;
|
|
||||||
|
|
||||||
if (!block) {
|
if (!block) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!heap_main) {
|
ns_mem_word_size_t *ptr = block;
|
||||||
heap_failure(NS_DYN_MEM_HEAP_SECTOR_UNITIALIZED);
|
ns_mem_word_size_t size;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
platform_enter_critical();
|
platform_enter_critical();
|
||||||
ptr --;
|
ptr --;
|
||||||
//Read Current Size
|
//Read Current Size
|
||||||
size = *ptr;
|
size = *ptr;
|
||||||
if (size < 0) {
|
if (ptr < book->heap_main || ptr >= book->heap_main_end) {
|
||||||
heap_failure(NS_DYN_MEM_DOUBLE_FREE);
|
heap_failure(book, NS_DYN_MEM_POINTER_NOT_VALID);
|
||||||
} else if (ptr < heap_main || ptr >= heap_main_end) {
|
} else if ((ptr + size) >= book->heap_main_end) {
|
||||||
heap_failure(NS_DYN_MEM_POINTER_NOT_VALID);
|
heap_failure(book, NS_DYN_MEM_POINTER_NOT_VALID);
|
||||||
} else if ((ptr + size) >= heap_main_end) {
|
} else if (size < 0) {
|
||||||
heap_failure(NS_DYN_MEM_POINTER_NOT_VALID);
|
heap_failure(book, NS_DYN_MEM_DOUBLE_FREE);
|
||||||
} else {
|
} else {
|
||||||
if (ns_block_validate(ptr) != 0) {
|
if (ns_mem_block_validate(ptr, 1) != 0) {
|
||||||
heap_failure(NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
|
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
|
||||||
} else {
|
} else {
|
||||||
ns_free_and_merge_with_adjacent_blocks(ptr, size);
|
ns_mem_free_and_merge_with_adjacent_blocks(book, ptr, size);
|
||||||
if (mem_stat_info_ptr) {
|
if (book->mem_stat_info_ptr) {
|
||||||
//Update Free Counter
|
//Update Free Counter
|
||||||
dev_stat_update(DEV_HEAP_FREE, (size + 2) * sizeof(int));
|
dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_FREE, (size + 2) * sizeof(ns_mem_word_size_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -403,3 +442,8 @@ void ns_dyn_mem_free(void *block)
|
||||||
platform_exit_critical();
|
platform_exit_critical();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ns_dyn_mem_free(void *block)
|
||||||
|
{
|
||||||
|
ns_mem_free(default_book, block);
|
||||||
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ TEST(dynmem, init)
|
||||||
mem_stat_t info;
|
mem_stat_t info;
|
||||||
reset_heap_error();
|
reset_heap_error();
|
||||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||||
CHECK(info.heap_sector_size >= (size-4));
|
CHECK(info.heap_sector_size >= (size-64));
|
||||||
CHECK(!heap_have_failed());
|
CHECK(!heap_have_failed());
|
||||||
CHECK(ns_dyn_mem_get_mem_stat() == &info);
|
CHECK(ns_dyn_mem_get_mem_stat() == &info);
|
||||||
free(heap);
|
free(heap);
|
||||||
|
@ -50,7 +50,7 @@ TEST(dynmem, different_sizes)
|
||||||
mem_stat_t info;
|
mem_stat_t info;
|
||||||
uint8_t *heap = (uint8_t*)malloc(size);
|
uint8_t *heap = (uint8_t*)malloc(size);
|
||||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||||
CHECK(info.heap_sector_size >= (size-4));
|
CHECK(info.heap_sector_size >= (size-64));
|
||||||
CHECK(!heap_have_failed());
|
CHECK(!heap_have_failed());
|
||||||
CHECK(ns_dyn_mem_alloc(10));
|
CHECK(ns_dyn_mem_alloc(10));
|
||||||
free(heap);
|
free(heap);
|
||||||
|
@ -68,7 +68,7 @@ TEST(dynmem, diff_alignment)
|
||||||
for (int i=0; i<16; i++) {
|
for (int i=0; i<16; i++) {
|
||||||
ptr++; size--;
|
ptr++; size--;
|
||||||
ns_dyn_mem_init(ptr, size, &heap_fail_callback, &info);
|
ns_dyn_mem_init(ptr, size, &heap_fail_callback, &info);
|
||||||
CHECK(info.heap_sector_size >= (size-4));
|
CHECK(info.heap_sector_size >= (size-64));
|
||||||
CHECK(!heap_have_failed());
|
CHECK(!heap_have_failed());
|
||||||
}
|
}
|
||||||
free(heap);
|
free(heap);
|
||||||
|
@ -137,7 +137,7 @@ TEST(dynmem, ns_dyn_mem_temporary_alloc)
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(dynmem, test_both_allocs_with_hole_usage) {
|
TEST(dynmem, test_both_allocs_with_hole_usage) {
|
||||||
uint16_t size = 48;
|
uint16_t size = 112;
|
||||||
mem_stat_t info;
|
mem_stat_t info;
|
||||||
void *p[size];
|
void *p[size];
|
||||||
uint8_t *heap = (uint8_t*)malloc(size);
|
uint8_t *heap = (uint8_t*)malloc(size);
|
||||||
|
@ -273,7 +273,7 @@ TEST(dynmem, diff_sizes)
|
||||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||||
CHECK(!heap_have_failed());
|
CHECK(!heap_have_failed());
|
||||||
int i;
|
int i;
|
||||||
for (i=1; i<(size-8); i++) {
|
for (i=1; i<(size-64); i++) {
|
||||||
p = ns_dyn_mem_temporary_alloc(i);
|
p = ns_dyn_mem_temporary_alloc(i);
|
||||||
CHECK(p);
|
CHECK(p);
|
||||||
ns_dyn_mem_free(p);
|
ns_dyn_mem_free(p);
|
||||||
|
@ -413,7 +413,7 @@ TEST(dynmem, not_negative_stats)
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(dynmem, test_invalid_pointer_freed) {
|
TEST(dynmem, test_invalid_pointer_freed) {
|
||||||
uint16_t size = 28;
|
uint16_t size = 92;
|
||||||
uint8_t *heap = (uint8_t*)malloc(size);
|
uint8_t *heap = (uint8_t*)malloc(size);
|
||||||
CHECK(NULL != heap);
|
CHECK(NULL != heap);
|
||||||
reset_heap_error();
|
reset_heap_error();
|
||||||
|
@ -472,7 +472,7 @@ TEST(dynmem, test_free_corrupted_next_block) {
|
||||||
|
|
||||||
//NOTE! This test must be last!
|
//NOTE! This test must be last!
|
||||||
TEST(dynmem, uninitialized_test){
|
TEST(dynmem, uninitialized_test){
|
||||||
ns_dyn_mem_alloc(4);
|
void *p = ns_dyn_mem_alloc(4);
|
||||||
uint8_t buf[1];
|
ns_dyn_mem_free(p);
|
||||||
ns_dyn_mem_free(&buf);
|
CHECK(p == NULL);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue