From 8730005927c6e12a78957c2eda92dc5a9698cdea Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Fri, 5 Jul 2019 10:44:37 +0300 Subject: [PATCH] Squashed 'features/frameworks/nanostack-libservice/' changes from dd98c37..9af7568 9af7568 Merge pull request #87 from ARMmbed/sync_with_mbedos 5c16e57 (via Mbed OS) ns_list: avoid UINT_FAST8_MAX 36b4ace nsdynmenlib API to add memory region to heap (#86) git-subtree-dir: features/frameworks/nanostack-libservice git-subtree-split: 9af756886f082ef8a26372fae5a337203395457f --- mbed-client-libservice/ns_list.h | 2 +- mbed-client-libservice/nsdynmemLIB.h | 50 +++- source/nsdynmemLIB/nsdynmemLIB.c | 169 +++++++++++-- .../unittest/nsdynmem/dynmemtest.cpp | 224 ++++++++++++++++-- 4 files changed, 406 insertions(+), 39 deletions(-) diff --git a/mbed-client-libservice/ns_list.h b/mbed-client-libservice/ns_list.h index 0030d56dea6..a4799fb4f36 100644 --- a/mbed-client-libservice/ns_list.h +++ b/mbed-client-libservice/ns_list.h @@ -148,7 +148,7 @@ union \ { \ ns_list_t slist; \ NS_FUNNY_COMPARE_OK \ - NS_STATIC_ASSERT(link_offset <= UINT_FAST8_MAX, "link offset too large") \ + NS_STATIC_ASSERT(link_offset <= (ns_list_offset_t) -1, "link offset too large") \ NS_FUNNY_COMPARE_RESTORE \ char (*offset)[link_offset + 1]; \ entry_type *type; \ diff --git a/mbed-client-libservice/nsdynmemLIB.h b/mbed-client-libservice/nsdynmemLIB.h index c8f6baede1d..bf0056ba1a7 100644 --- a/mbed-client-libservice/nsdynmemLIB.h +++ b/mbed-client-libservice/nsdynmemLIB.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018 ARM Limited. All rights reserved. + * Copyright (c) 2014-2019 ARM Limited. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -71,11 +71,25 @@ typedef struct ns_mem_book ns_mem_book_t; * \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 + * \param h_size size of the heap buffer + * \param passed_fptr pointer to heap error callback function + * \param info_ptr Pointer to mem_stat_t for memory statistics. Can be NULL. + * * \return None */ -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); +extern void ns_dyn_mem_init(void *heap_ptr, ns_mem_heap_size_t h_size, void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr); +/** + * \brief Add memory region to initialized heap. + * + * This method adds memory region to already initialized heap. + * Method will reset temporary heap threshold to the default value. + * + * \param region_ptr Pointer to memory region to be added + * \param region_size size of the region buffer + * \return 0 on success, <0 in case of errors. + */ +extern int ns_dyn_mem_region_add(void *region_ptr, ns_mem_heap_size_t region_size); /** * \brief Free allocated memory. @@ -86,6 +100,7 @@ extern void ns_dyn_mem_init(void *heap, ns_mem_heap_size_t h_size, void (*passed * \return <0, Free Fail */ extern void ns_dyn_mem_free(void *heap_ptr); + /** * \brief Allocate temporary data. * @@ -97,6 +112,7 @@ extern void ns_dyn_mem_free(void *heap_ptr); * \return >0, Pointer to allocated data sector. */ extern void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size); + /** * \brief Allocate long period data. * @@ -118,7 +134,7 @@ extern void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size); * Note: the caller may not modify the returned structure. * * \return NULL, no mem_stat_t was given on initialization - * \return !=0, Pointer to mem_stat_t. + * \return Pointer to mem_stat_t or NULL. */ extern const mem_stat_t *ns_dyn_mem_get_mem_stat(void); @@ -139,11 +155,27 @@ extern int ns_dyn_mem_set_temporary_alloc_free_heap_threshold(uint8_t free_heap_ /** * \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. + * \param heap_ptr Pointer to dynamically heap buffer. + * \param h_size size of the heap buffer. + * \param passed_fptr pointer to heap error callback function. + * \param info_ptr Pointer to mem_stat_t for memory statistics. Can be NULL. + * \return 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); +extern ns_mem_book_t *ns_mem_init(void *heap_ptr, ns_mem_heap_size_t h_size, void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr); + +/** + * \brief Add memory region to initialized heap. + * + * This method adds memory region to already initialized heap. + * Method will reset temporary heap threshold to the default value. + * + * \param book Address of book keeping structure. + * \param region_ptr Pointer to memory region buffer. + * \param region_size size of the memory region to add + * + * \return 0 on success, <0 in case of errors. + */ +extern int ns_mem_region_add(ns_mem_book_t *book, void *region_ptr, ns_mem_heap_size_t region_size); /** * \brief Free allocated memory. @@ -155,6 +187,7 @@ extern ns_mem_book_t *ns_mem_init(void *heap, ns_mem_heap_size_t h_size, void (* * \return <0, Free Fail */ extern void ns_mem_free(ns_mem_book_t *book, void *heap_ptr); + /** * \brief Allocate temporary data. * @@ -167,6 +200,7 @@ extern void ns_mem_free(ns_mem_book_t *book, void *heap_ptr); * \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. * diff --git a/source/nsdynmemLIB/nsdynmemLIB.c b/source/nsdynmemLIB/nsdynmemLIB.c index 6b0485ebad4..5f913d5758a 100644 --- a/source/nsdynmemLIB/nsdynmemLIB.c +++ b/source/nsdynmemLIB/nsdynmemLIB.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018 ARM Limited. All rights reserved. + * Copyright (c) 2014-2019 ARM Limited. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -33,10 +33,13 @@ typedef struct { typedef int ns_mem_word_size_t; // internal signed heap block size type +// Amount of memory regions +#define REGION_COUNT 3 + /* struct for book keeping variables */ struct ns_mem_book { - ns_mem_word_size_t *heap_main; - ns_mem_word_size_t *heap_main_end; + ns_mem_word_size_t *heap_main[REGION_COUNT]; + ns_mem_word_size_t *heap_main_end[REGION_COUNT]; mem_stat_t *mem_stat_info_ptr; void (*heap_failure_callback)(heap_fail_t); NS_LIST_HEAD(hole_t, link) holes_list; @@ -68,7 +71,37 @@ static void heap_failure(ns_mem_book_t *book, heap_fail_t reason) } } -#endif +static int ns_dyn_mem_region_find(ns_mem_book_t *book, ns_mem_word_size_t *block_ptr, ns_mem_word_size_t size) +{ + int index; + for (index = 0; index < REGION_COUNT; index++) { + if (book->heap_main[index] != 0) { + if ((block_ptr >= book->heap_main[index]) && + (block_ptr < book->heap_main_end[index]) && + ((block_ptr + size) < book->heap_main_end[index])) { + return index; + } + } + } + + return -1; +} + +static int ns_dyn_mem_region_save(ns_mem_book_t *book, ns_mem_word_size_t *region_start_ptr, ns_mem_word_size_t region_size) +{ + for (int i = 1; i < REGION_COUNT; i++) { + if (book->heap_main[i] == 0) { + book->heap_main[i] = region_start_ptr; + book->heap_main_end[i] = book->heap_main[i] + region_size; + return 0; + } + } + + return -1; +} + + +#endif //STANDARD_MALLOC 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) @@ -76,6 +109,11 @@ void ns_dyn_mem_init(void *heap, ns_mem_heap_size_t h_size, default_book = ns_mem_init(heap, h_size, passed_fptr, info_ptr); } +int ns_dyn_mem_region_add(void *region_ptr, ns_mem_heap_size_t region_size) +{ + return ns_mem_region_add(default_book, region_ptr, region_size); +} + const mem_stat_t *ns_dyn_mem_get_mem_stat(void) { #ifndef STANDARD_MALLOC @@ -85,7 +123,6 @@ const mem_stat_t *ns_dyn_mem_get_mem_stat(void) #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) @@ -107,19 +144,23 @@ ns_mem_book_t *ns_mem_init(void *heap, ns_mem_heap_size_t h_size, 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 + memset(book->heap_main, 0, REGION_COUNT * sizeof(ns_mem_word_size_t *)); + memset(book->heap_main_end, 0, REGION_COUNT * sizeof(ns_mem_word_size_t *)); + + book->heap_main[0] = (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 = book->heap_main[0]; *ptr = -(temp_int); ptr += (temp_int + 1); *ptr = -(temp_int); - book->heap_main_end = ptr; + book->heap_main_end[0] = ptr; ns_list_init(&book->holes_list); - ns_list_add_to_start(&book->holes_list, hole_from_block_start(book->heap_main)); + ns_list_add_to_start(&book->holes_list, hole_from_block_start(book->heap_main[0])); book->mem_stat_info_ptr = info_ptr; //RESET Memory by Hea Len @@ -135,6 +176,81 @@ ns_mem_book_t *ns_mem_init(void *heap, ns_mem_heap_size_t h_size, return book; } +int ns_mem_region_add(ns_mem_book_t *book, void *region_ptr, ns_mem_heap_size_t region_size) +{ +#ifndef STANDARD_MALLOC + if (!book || !region_ptr || region_size < 3 * sizeof(ns_mem_word_size_t)) { + return -1; + } + + ns_mem_word_size_t *block_ptr; + ns_mem_word_size_t temp_int; + + /* Do memory alignment */ + temp_int = ((uintptr_t)region_ptr % sizeof(ns_mem_word_size_t)); + if (temp_int) { + region_ptr = (uint8_t *) region_ptr + (sizeof(ns_mem_word_size_t) - temp_int); + region_size -= (sizeof(ns_mem_word_size_t) - temp_int); + } + + /* Make correction for total length */ + temp_int = (region_size % sizeof(ns_mem_word_size_t)); + if (temp_int) { + region_size -= (sizeof(ns_mem_word_size_t) - temp_int); + } + + // Create hole from new heap memory + temp_int = (region_size / sizeof(ns_mem_word_size_t)); + temp_int -= 2; + block_ptr = region_ptr; + *block_ptr = -(temp_int); + block_ptr += (temp_int + 1); // now block_ptr points to end of block + *block_ptr = -(temp_int); + + // find place for the new hole from the holes list + hole_t *hole_to_add = hole_from_block_start(region_ptr); + hole_t *previous_hole = NULL; + ns_list_foreach(hole_t, hole_in_list_ptr, &book->holes_list) { + if (hole_in_list_ptr < hole_to_add) { + previous_hole = hole_in_list_ptr; + } else if (hole_in_list_ptr == hole_to_add) { + // trying to add memory block that is already in the list! + return -2; + } + } + + // save region + if (ns_dyn_mem_region_save(book, region_ptr, (region_size / (sizeof(ns_mem_word_size_t))) - 1) != 0) { + return -3; + } + + // Add new hole to the list + if (previous_hole) { + ns_list_add_after(&book->holes_list, previous_hole, hole_to_add); + } else { + ns_list_add_to_start(&book->holes_list, hole_to_add); + } + + // adjust total heap size with new hole + book->heap_size += region_size; + + if (book->mem_stat_info_ptr) { + book->mem_stat_info_ptr->heap_sector_size = book->heap_size; + } + + // adjust temporary allocation limits to match new heap + book->temporary_alloc_heap_limit = book->heap_size / 100 * (100 - TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD); + + return 0; +#else + (void) book; + (void) region_ptr; + (void) region_size; + + return -1; +#endif +} + const mem_stat_t *ns_mem_get_mem_stat(ns_mem_book_t *heap) { #ifndef STANDARD_MALLOC @@ -211,7 +327,7 @@ static void dev_stat_update(mem_stat_t *mem_stat_info_ptr, mem_stat_update_t typ static ns_mem_word_size_t convert_allocation_size(ns_mem_book_t *book, ns_mem_block_size_t requested_bytes) { - if (book->heap_main == 0) { + if (book->heap_main[0] == 0) { heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_UNITIALIZED); } else if (requested_bytes < 1) { heap_failure(book, NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID); @@ -329,7 +445,6 @@ static void *ns_mem_internal_alloc(ns_mem_book_t *book, const ns_mem_block_size_ if (block_ptr) { //Update Allocate OK dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_OK, (data_size + 2) * sizeof(ns_mem_word_size_t)); - } else { //Update Allocate Fail, second parameter is used for stats dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0); @@ -381,12 +496,25 @@ static void ns_mem_free_and_merge_with_adjacent_blocks(ns_mem_book_t *book, ns_m hole_t *existing_end = NULL; ns_mem_word_size_t *start = cur_block; ns_mem_word_size_t *end = cur_block + data_size + 1; + ns_mem_word_size_t *region_start; + ns_mem_word_size_t *region_end; + + int region_index = ns_dyn_mem_region_find(book, cur_block, data_size); + if (region_index >= 0) { + region_start = book->heap_main[region_index]; + region_end = book->heap_main_end[region_index]; + } else { + heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED); + // can't find region for the block, return + return; + } + //invalidate current block *start = -data_size; *end = -data_size; ns_mem_word_size_t merged_data_size = data_size; - if (start != book->heap_main) { + if (start != region_start) { if (*(start - 1) < 0) { ns_mem_word_size_t *block_end = start - 1; ns_mem_word_size_t block_size = 1 + (-*block_end) + 1; @@ -401,7 +529,7 @@ static void ns_mem_free_and_merge_with_adjacent_blocks(ns_mem_book_t *book, ns_m } } - if (end != book->heap_main_end) { + if (end != region_end) { if (*(end + 1) < 0) { ns_mem_word_size_t *block_start = end + 1; ns_mem_word_size_t block_size = 1 + (-*block_start) + 1; @@ -457,6 +585,16 @@ static void ns_mem_free_and_merge_with_adjacent_blocks(ns_mem_book_t *book, ns_m } #endif +static bool pointer_address_validate(ns_mem_book_t *book, ns_mem_word_size_t *ptr, ns_mem_word_size_t size) +{ + + if (ns_dyn_mem_region_find(book, ptr, size) >= 0) { + return true; + } + + return false; +} + void ns_mem_free(ns_mem_book_t *book, void *block) { #ifndef STANDARD_MALLOC @@ -472,9 +610,7 @@ void ns_mem_free(ns_mem_book_t *book, void *block) ptr --; //Read Current Size size = *ptr; - if (ptr < book->heap_main || ptr >= book->heap_main_end) { - heap_failure(book, NS_DYN_MEM_POINTER_NOT_VALID); - } else if ((ptr + size) >= book->heap_main_end) { + if (!pointer_address_validate(book, ptr, size)) { heap_failure(book, NS_DYN_MEM_POINTER_NOT_VALID); } else if (size < 0) { heap_failure(book, NS_DYN_MEM_DOUBLE_FREE); @@ -489,6 +625,7 @@ void ns_mem_free(ns_mem_book_t *book, void *block) } } } + platform_exit_critical(); #else platform_enter_critical(); diff --git a/test/libService/unittest/nsdynmem/dynmemtest.cpp b/test/libService/unittest/nsdynmem/dynmemtest.cpp index 1426b98ded5..1face7ca2a6 100644 --- a/test/libService/unittest/nsdynmem/dynmemtest.cpp +++ b/test/libService/unittest/nsdynmem/dynmemtest.cpp @@ -17,8 +17,17 @@ #include "nsdynmemLIB.h" #include #include +#include #include "error_callback.h" +// hardcoded amount of regions, keep in sync with nsdynmemlib "REGION_COUNT" +#define NS_MEM_REGION_CNT (3) +// size of nsdynmemlib book keeping data ns_mem_book_t +#define NS_MEM_BOOK_SIZE (64 + (NS_MEM_REGION_CNT-1)*2*sizeof(ns_mem_heap_size_t)) +#define NS_MEM_BOOK_SIZE_WITH_HOLE (NS_MEM_BOOK_SIZE + 2*sizeof(ns_mem_heap_size_t)) + +int ret_val; + TEST_GROUP(dynmem) { void setup() { @@ -37,7 +46,7 @@ TEST(dynmem, init) mem_stat_t info; reset_heap_error(); ns_dyn_mem_init(heap, size, &heap_fail_callback, &info); - CHECK(info.heap_sector_size >= (size - 72)); + CHECK(info.heap_sector_size == (size - NS_MEM_BOOK_SIZE)); CHECK(!heap_have_failed()); CHECK(ns_dyn_mem_get_mem_stat() == &info); free(heap); @@ -50,7 +59,7 @@ TEST(dynmem, different_sizes) mem_stat_t info; uint8_t *heap = (uint8_t *)malloc(size); ns_dyn_mem_init(heap, size, &heap_fail_callback, &info); - CHECK(info.heap_sector_size >= (size - 72)); + CHECK(info.heap_sector_size >= (size - NS_MEM_BOOK_SIZE_WITH_HOLE)); CHECK(!heap_have_failed()); CHECK(ns_dyn_mem_alloc(10)); free(heap); @@ -69,12 +78,196 @@ TEST(dynmem, diff_alignment) ptr++; size--; ns_dyn_mem_init(ptr, size, &heap_fail_callback, &info); - CHECK(info.heap_sector_size >= (size - 72)); + CHECK(info.heap_sector_size >= (size - NS_MEM_BOOK_SIZE_WITH_HOLE)); CHECK(!heap_have_failed()); } free(heap); } +TEST(dynmem, heap_add_region_api) +{ +#if (NS_MEM_REGION_CNT > 1) + uint16_t size = 1000; + uint8_t *heap = (uint8_t *)malloc(size); + uint8_t *heap2add = (uint8_t *)malloc(size); + uint8_t *heap2add2 = (uint8_t *)malloc(size); + + mem_stat_t info; + + reset_heap_error(); + ns_dyn_mem_init(heap, size, &heap_fail_callback, &info); + CHECK(info.heap_sector_size == (size - NS_MEM_BOOK_SIZE)) + + // param error, return <0 + ret_val = ns_dyn_mem_region_add(NULL, size); + CHECK(0 != ret_val); + + // param error, return <0 + ret_val = ns_dyn_mem_region_add(heap2add, 0); + CHECK(0 != ret_val); + + // param error, return <0 + ret_val = ns_dyn_mem_region_add(heap2add, 8); + CHECK(0 != ret_val); + + // All OK - success, 1 reserved for bookkeeping + ret_val = ns_dyn_mem_region_add(heap2add, size); + CHECK(0 == ret_val); + + CHECK(!heap_have_failed()); + CHECK(ns_dyn_mem_get_mem_stat() == &info); + CHECK(info.heap_sector_size == (2 * size - NS_MEM_BOOK_SIZE)) + + // All OK - add more memory again success + ret_val = ns_dyn_mem_region_add(heap2add2, size); + CHECK(0 == ret_val); + CHECK(info.heap_sector_size == (3 * size - NS_MEM_BOOK_SIZE)) + + free(heap); + free(heap2add); + free(heap2add2); +#endif +} + +TEST(dynmem, heap_add_region) +{ +#if (NS_MEM_REGION_CNT > 1 && NS_MEM_REGION_CNT < 4) + uint16_t size = 200; + uint8_t *heap = (uint8_t *)malloc(size); + uint8_t *heap_add1 = (uint8_t *)malloc(size); + uint8_t *heap_add2 = (uint8_t *)malloc(size); + uint8_t *heap_add3 = (uint8_t *)malloc(size); + void *p[size * 4]; + + mem_stat_t info; + + reset_heap_error(); + ns_dyn_mem_init(heap, size, &heap_fail_callback, &info); + CHECK(info.heap_sector_size == (size - NS_MEM_BOOK_SIZE)) + + ret_val = ns_dyn_mem_region_add(heap_add1, size); + CHECK(0 == ret_val); + + // region already added, therefore fails + ret_val = ns_dyn_mem_region_add(heap_add1, size); + CHECK(0 != ret_val); + + ret_val = ns_dyn_mem_region_add(heap_add3, size); + CHECK(0 == ret_val); + + // There is room for 2 additional regions , therfore fails + ret_val = ns_dyn_mem_region_add(heap_add2, size); + CHECK(0 != ret_val); + + CHECK(info.heap_sector_size == (3 * size - NS_MEM_BOOK_SIZE)) + + CHECK(!heap_have_failed()); + int block_size = 10; + + int i; + for (i = 0; i < size * 3; i++) { + p[i] = ns_dyn_mem_alloc(block_size); + if (p[i]) { + memset(p[i], 0xb0, block_size); + } else { + break; + } + } + CHECK(!heap_have_failed()); + CHECK(info.heap_alloc_fail_cnt == 1); + CHECK(info.heap_sector_alloc_cnt == i); + CHECK(info.heap_sector_allocated_bytes == info.heap_sector_allocated_bytes_max); + + for (; i >= 0; i--) { + ns_dyn_mem_free(p[i]); + } + CHECK(!heap_have_failed()); + CHECK(info.heap_sector_alloc_cnt == 0); + + free(heap); + free(heap_add1); + free(heap_add2); + free(heap_add3); +#endif +} + +TEST(dynmem, heap_add_region_randomized) +{ + /** + * Test: + * - multiple regions + * - regions are not from continous + * - all memory allocated from heap + * - blocks are deallocated in random order + */ +#if (NS_MEM_REGION_CNT > 1) + uint32_t size = 200000; + uint8_t *heap_ptr[NS_MEM_REGION_CNT]; // heap memory regions + void *ptrs[size * NS_MEM_REGION_CNT / 4] = {0}; // allocated memory pointers + mem_stat_t info; + uint8_t *gap_between_regions = NULL; + + for (int cnt = 0; cnt < NS_MEM_REGION_CNT; cnt++) { + heap_ptr[cnt] = (uint8_t *)malloc(size); + if (gap_between_regions) { + free(gap_between_regions); + } + gap_between_regions = (uint8_t *)malloc(size / 3); + } + free(gap_between_regions); + + reset_heap_error(); + ns_dyn_mem_init(heap_ptr[0], size, &heap_fail_callback, &info); + CHECK(info.heap_sector_size == (size - NS_MEM_BOOK_SIZE)) + + for (int cnt = NS_MEM_REGION_CNT - 1; cnt > 0; cnt--) { + ret_val = ns_dyn_mem_region_add(heap_ptr[cnt], size); + CHECK(0 == ret_val); + } + + CHECK(info.heap_sector_size == (NS_MEM_REGION_CNT * size - NS_MEM_BOOK_SIZE)) + + CHECK(!heap_have_failed()); + + srand(time(NULL)); + int block_size; + int i; + for (i = 0; i < size * NS_MEM_REGION_CNT; i++) { + // allocate huge amount of small blocks until allocation fails + block_size = (rand() % 4) + 1; + ptrs[i] = ns_dyn_mem_alloc(block_size); + if (ptrs[i]) { + memset(ptrs[i], 0xb0, block_size); + } else { + break; + } + } + CHECK(!heap_have_failed()); + CHECK(info.heap_alloc_fail_cnt == 1); + CHECK(info.heap_sector_alloc_cnt == i); + CHECK(info.heap_sector_allocated_bytes == info.heap_sector_allocated_bytes_max); + + // free allocated memmory blocks in random order + int block_id; + do { + block_id = (rand() % i); + if (ptrs[block_id] != NULL) { + ns_dyn_mem_free(ptrs[block_id]); + ptrs[block_id] = NULL; + } + } while (info.heap_sector_alloc_cnt != 0); + + + CHECK(!heap_have_failed()); + CHECK(info.heap_sector_alloc_cnt == 0); + CHECK(info.heap_sector_allocated_bytes == 0); + + for (int cnt = 0; cnt < NS_MEM_REGION_CNT; cnt++) { + free(heap_ptr[cnt]); + } +#endif +} + TEST(dynmem, ns_dyn_mem_alloc) { uint16_t size = 1000; @@ -90,7 +283,10 @@ TEST(dynmem, ns_dyn_mem_alloc) int i; for (i = 0; i < size; i++) { p[i] = ns_dyn_mem_alloc(block); - if (!p[i]) { + + if (p[i]) { + memset(p[i], 0xb0, block); + } else { break; } } @@ -152,17 +348,17 @@ TEST(dynmem, ns_dyn_mem_temporary_alloc_with_heap_threshold) CHECK(!heap_have_failed()); // test1: temporary alloc will fail if there is less than 5% heap free - p1 = ns_dyn_mem_temporary_alloc((size - 72) * 0.96); + p1 = ns_dyn_mem_temporary_alloc((size - NS_MEM_BOOK_SIZE_WITH_HOLE) * 0.96); CHECK(!heap_have_failed()); CHECK(p1); - p2 = ns_dyn_mem_temporary_alloc((size - 72) * 0.02); + p2 = ns_dyn_mem_temporary_alloc((size - NS_MEM_BOOK_SIZE_WITH_HOLE) * 0.02); CHECK(p2 == NULL); CHECK(!heap_have_failed()); CHECK(info.heap_alloc_fail_cnt == 1); // Test2, disable threshold feature and try p2 allocation again ns_dyn_mem_set_temporary_alloc_free_heap_threshold(0, 0); - p2 = ns_dyn_mem_temporary_alloc((size - 72) * 0.02); + p2 = ns_dyn_mem_temporary_alloc((size - NS_MEM_BOOK_SIZE_WITH_HOLE) * 0.02); CHECK(!heap_have_failed()); CHECK(p2); ns_dyn_mem_free(p1); @@ -172,9 +368,9 @@ TEST(dynmem, ns_dyn_mem_temporary_alloc_with_heap_threshold) // Test3, enable feature by free heap percentage ns_dyn_mem_set_temporary_alloc_free_heap_threshold(40, 0); - p1 = ns_dyn_mem_temporary_alloc((size - 72) * 0.65); + p1 = ns_dyn_mem_temporary_alloc((size - NS_MEM_BOOK_SIZE_WITH_HOLE) * 0.65); CHECK(p1); - p2 = ns_dyn_mem_temporary_alloc((size - 72) * 0.10); + p2 = ns_dyn_mem_temporary_alloc((size - NS_MEM_BOOK_SIZE_WITH_HOLE) * 0.10); CHECK(p2 == NULL); ns_dyn_mem_free(p1); CHECK(!heap_have_failed()); @@ -183,7 +379,7 @@ TEST(dynmem, ns_dyn_mem_temporary_alloc_with_heap_threshold) // Test4, enable feature by free heap amount ns_dyn_mem_set_temporary_alloc_free_heap_threshold(0, 200); - p1 = ns_dyn_mem_temporary_alloc(size - 72 - 100 /*828 bytes */); + p1 = ns_dyn_mem_temporary_alloc(size - NS_MEM_BOOK_SIZE_WITH_HOLE - 100); CHECK(p1); p2 = ns_dyn_mem_temporary_alloc(1); CHECK(p2 == NULL); @@ -216,7 +412,7 @@ TEST(dynmem, ns_dyn_mem_temporary_alloc_with_heap_threshold) TEST(dynmem, test_both_allocs_with_hole_usage) { - uint16_t size = 112; + uint16_t size = NS_MEM_BOOK_SIZE_WITH_HOLE + 15 + 5; mem_stat_t info; void *p[size]; uint8_t *heap = (uint8_t *)malloc(size); @@ -322,7 +518,7 @@ TEST(dynmem, corrupted_memory) TEST(dynmem, no_big_enough_sector) { - uint16_t size = 112; + uint16_t size = NS_MEM_BOOK_SIZE_WITH_HOLE + (5 * 8); mem_stat_t info; uint8_t *heap = (uint8_t *)malloc(size); uint8_t *ptr = heap; @@ -354,7 +550,7 @@ TEST(dynmem, diff_sizes) ns_dyn_mem_init(heap, size, &heap_fail_callback, &info); CHECK(!heap_have_failed()); int i; - for (i = 1; i < (size - 72); i++) { + for (i = 1; i < (size - NS_MEM_BOOK_SIZE_WITH_HOLE); i++) { p = ns_dyn_mem_temporary_alloc(i); CHECK(p); ns_dyn_mem_free(p); @@ -495,7 +691,7 @@ TEST(dynmem, not_negative_stats) TEST(dynmem, test_invalid_pointer_freed) { - uint16_t size = 92; + uint16_t size = 1000; uint8_t *heap = (uint8_t *)malloc(size); CHECK(NULL != heap); reset_heap_error();