mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			Merge commit '084b722d1c3fa00e29d7ded181aaabbcc3f1f793'
* commit '084b722d1c3fa00e29d7ded181aaabbcc3f1f793': Squashed 'connectivity/libraries/nanostack-libservice/' changes from 67d7b93ec6..a526cc3f41pull/14169/head
						commit
						6354a1e8dc
					
				| 
						 | 
				
			
			@ -5,6 +5,7 @@ source/libip6string/ip6tos.c \
 | 
			
		|||
source/libip6string/stoip6.c \
 | 
			
		||||
source/libList/ns_list.c \
 | 
			
		||||
source/nsdynmemLIB/nsdynmemLIB.c \
 | 
			
		||||
source/nsdynmemtracker/nsdynmem_tracker_lib.c \
 | 
			
		||||
source/nvmHelper/ns_nvm_helper.c \
 | 
			
		||||
 | 
			
		||||
LIB := libservice.a
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,6 +37,9 @@ extern "C" {
 | 
			
		|||
typedef size_t ns_mem_block_size_t; //external interface unsigned heap block size type
 | 
			
		||||
typedef size_t ns_mem_heap_size_t; //total heap size type.
 | 
			
		||||
 | 
			
		||||
// Can be used to enable tracking of dynamic memory allocations
 | 
			
		||||
#include "nsdynmem_tracker.h"
 | 
			
		||||
 | 
			
		||||
/*!
 | 
			
		||||
 * \enum heap_fail_t
 | 
			
		||||
 * \brief Dynamically heap system failure call back event types.
 | 
			
		||||
| 
						 | 
				
			
			@ -64,7 +67,6 @@ typedef struct mem_stat_t {
 | 
			
		|||
    uint32_t heap_alloc_fail_cnt;               /**< Counter for Heap allocation fail. */
 | 
			
		||||
} mem_stat_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef struct ns_mem_book ns_mem_book_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -99,7 +101,9 @@ extern int ns_dyn_mem_region_add(void *region_ptr, ns_mem_heap_size_t region_siz
 | 
			
		|||
  * \return 0, Free OK
 | 
			
		||||
  * \return <0, Free Fail
 | 
			
		||||
  */
 | 
			
		||||
#if NSDYNMEM_TRACKER_ENABLED!=1
 | 
			
		||||
extern void ns_dyn_mem_free(void *heap_ptr);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * \brief Allocate temporary data.
 | 
			
		||||
| 
						 | 
				
			
			@ -111,7 +115,9 @@ extern void ns_dyn_mem_free(void *heap_ptr);
 | 
			
		|||
  * \return 0, Allocate Fail
 | 
			
		||||
  * \return >0, Pointer to allocated data sector.
 | 
			
		||||
  */
 | 
			
		||||
#if NSDYNMEM_TRACKER_ENABLED!=1
 | 
			
		||||
extern void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * \brief Allocate long period data.
 | 
			
		||||
| 
						 | 
				
			
			@ -123,7 +129,9 @@ extern void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size);
 | 
			
		|||
  * \return 0, Allocate Fail
 | 
			
		||||
  * \return >0, Pointer to allocated data sector.
 | 
			
		||||
  */
 | 
			
		||||
#if NSDYNMEM_TRACKER_ENABLED!=1
 | 
			
		||||
extern void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  * \brief Get pointer to the current mem_stat_t set via ns_dyn_mem_init.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2020 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.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \file nsdynmem_tracker.h
 | 
			
		||||
 * \brief Dynamical Memory Tracker definitions to override the default NS dynamic memory functionality
 | 
			
		||||
 * Provides tracking and tracing of dynamic memory blocks
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef NSDYNMEM_TRACKER_H_
 | 
			
		||||
#define NSDYNMEM_TRACKER_H_
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if NSDYNMEM_TRACKER_ENABLED==1
 | 
			
		||||
 | 
			
		||||
#define ns_dyn_mem_free(block) ns_dyn_mem_tracker_dyn_mem_free(block, __func__, __LINE__)
 | 
			
		||||
#define ns_dyn_mem_temporary_alloc(alloc_size) ns_dyn_mem_tracker_dyn_mem_temporary_alloc(alloc_size, __func__, __LINE__)
 | 
			
		||||
#define ns_dyn_mem_alloc(alloc_size) ns_dyn_mem_tracker_dyn_mem_alloc(alloc_size, __func__, __LINE__)
 | 
			
		||||
 | 
			
		||||
void *ns_dyn_mem_tracker_dyn_mem_alloc(ns_mem_heap_size_t alloc_size, const char *function, uint32_t line);
 | 
			
		||||
void *ns_dyn_mem_tracker_dyn_mem_temporary_alloc(ns_mem_heap_size_t alloc_size, const char *function, uint32_t line);
 | 
			
		||||
void ns_dyn_mem_tracker_dyn_mem_free(void *block, const char *function, uint32_t line);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* NSDYNMEM_TRACKER_H_ */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,104 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2020 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.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \file nsdynmem_tracker_lib.h
 | 
			
		||||
 * \brief Dynamical Memory Tracker library API
 | 
			
		||||
 * Provides tracking and tracing of dynamic memory blocks
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef NSDYNMEM_TRACKER_LIB_H_
 | 
			
		||||
#define NSDYNMEM_TRACKER_LIB_H_
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if NSDYNMEM_TRACKER_ENABLED==1
 | 
			
		||||
 | 
			
		||||
// Memory block structure with caller information
 | 
			
		||||
typedef struct ns_dyn_mem_tracker_lib_mem_blocks_s {
 | 
			
		||||
    void *block;                   /**< Allocated memory block */
 | 
			
		||||
    void *caller_addr;             /**< Caller address */
 | 
			
		||||
    uint32_t size;                 /**< Allocation size */
 | 
			
		||||
    uint32_t total_size;           /**< Total allocation size for all allocations */
 | 
			
		||||
    uint32_t lifetime;             /**< Memory block lifetime in steps (e.g. seconds) */
 | 
			
		||||
    uint32_t ref_count;            /**< Reference count */
 | 
			
		||||
    const char *function;          /**< Caller function */
 | 
			
		||||
    uint16_t line;                 /**< Caller line in module */
 | 
			
		||||
    bool permanent : 1;            /**< Permanent memory block */
 | 
			
		||||
    bool permanent_printed : 1;    /**< Permanent memory block printed */
 | 
			
		||||
} ns_dyn_mem_tracker_lib_mem_blocks_t;
 | 
			
		||||
 | 
			
		||||
// Extended memory block structure that is used if same caller allocates multiple memory blocks
 | 
			
		||||
typedef struct ns_dyn_mem_tracker_lib_mem_blocks_ext_s {
 | 
			
		||||
    void *block;                   /**< Allocated memory block */
 | 
			
		||||
    void *caller_addr;             /**< Caller address */
 | 
			
		||||
    uint32_t size;                 /**< Allocation size */
 | 
			
		||||
} ns_dyn_mem_tracker_lib_mem_blocks_ext_t;
 | 
			
		||||
 | 
			
		||||
// Allocator information structure
 | 
			
		||||
typedef struct ns_dyn_mem_tracker_lib_allocators_s {
 | 
			
		||||
    void *caller_addr;             /**< Caller address */
 | 
			
		||||
    uint32_t alloc_count;          /**< Number of allocations */
 | 
			
		||||
    uint32_t total_memory;         /**< Total memory used by allocations */
 | 
			
		||||
    uint32_t min_lifetime;         /**< Shortest lifetime among the allocations */
 | 
			
		||||
    const char *function;          /**< Function name string */
 | 
			
		||||
    uint16_t line;                 /**< Module line */
 | 
			
		||||
} ns_dyn_mem_tracker_lib_allocators_t;
 | 
			
		||||
 | 
			
		||||
// Memory block array allocator / array size increase allocator
 | 
			
		||||
typedef ns_dyn_mem_tracker_lib_mem_blocks_t *ns_dyn_mem_tracker_lib_alloc_mem_blocks(ns_dyn_mem_tracker_lib_mem_blocks_t *blocks, uint16_t *mem_blocks_count);
 | 
			
		||||
// Extended memory block array allocator / array size increase allocator
 | 
			
		||||
typedef ns_dyn_mem_tracker_lib_mem_blocks_ext_t *ns_dyn_mem_tracker_lib_alloc_mem_blocks_ext(ns_dyn_mem_tracker_lib_mem_blocks_ext_t *blocks, uint32_t *mem_blocks_count);
 | 
			
		||||
// Extended memory block array index hash function to get memory block (allocation/search start) index from block address
 | 
			
		||||
typedef uint32_t ns_dyn_mem_tracker_lib_mem_block_index_hash(void *block, uint32_t ext_mem_blocks_count);
 | 
			
		||||
 | 
			
		||||
typedef struct ns_dyn_mem_tracker_lib_conf_s {
 | 
			
		||||
    ns_dyn_mem_tracker_lib_mem_blocks_t *mem_blocks;                    /**< Memory blocks array, if NULL calls allocator on init */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_mem_blocks_ext_t *ext_mem_blocks;            /**< Extended memory blocks array, if NULL calls allocator on init */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *top_allocators;                /**< Top allocators array */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *permanent_allocators;          /**< Permanent allocators */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *to_permanent_allocators;       /**< To permanent allocators */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *max_snap_shot_allocators;      /**< Snap shot of maximum memory used by allocators */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_alloc_mem_blocks *alloc_mem_blocks;          /**< Memory block array allocator / array size increase allocator */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_alloc_mem_blocks_ext *ext_alloc_mem_blocks;  /**< Extended memory block array allocator / array size increase allocator */
 | 
			
		||||
    ns_dyn_mem_tracker_lib_mem_block_index_hash *block_index_hash;      /**< Hash function to get memory block index from block address */
 | 
			
		||||
    uint32_t allocated_memory;                                          /**< Currently allocated memory */
 | 
			
		||||
    uint16_t mem_blocks_count;                                          /**< Number of entries in memory blocks array */
 | 
			
		||||
    uint32_t ext_mem_blocks_count;                                      /**< Number of entries in extended memory blocks array */
 | 
			
		||||
    uint16_t last_mem_block_index;                                      /**< Last memory block in memory blocks array */
 | 
			
		||||
    uint16_t top_allocators_count;                                      /**< Top allocators array count */
 | 
			
		||||
    uint16_t permanent_allocators_count;                                /**< Permanent allocators array count */
 | 
			
		||||
    uint16_t to_permanent_allocators_count;                             /**< To permanent allocators array count */
 | 
			
		||||
    uint16_t max_snap_shot_allocators_count;                            /**< Snap shot of maximum memory used by allocators array count */
 | 
			
		||||
    uint16_t to_permanent_steps_count;                                  /**< How many steps before moving block to permanent allocators list */
 | 
			
		||||
} ns_dyn_mem_tracker_lib_conf_t;
 | 
			
		||||
 | 
			
		||||
int8_t ns_dyn_mem_tracker_lib_alloc(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, const char *function, uint32_t line, void *block, uint32_t alloc_size);
 | 
			
		||||
int8_t ns_dyn_mem_tracker_lib_free(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, const char *function, uint32_t line, void *block);
 | 
			
		||||
void ns_dyn_mem_tracker_lib_step(ns_dyn_mem_tracker_lib_conf_t *conf);
 | 
			
		||||
int8_t ns_dyn_mem_tracker_lib_allocator_lists_update(ns_dyn_mem_tracker_lib_conf_t *conf);
 | 
			
		||||
void ns_dyn_mem_tracker_lib_max_snap_shot_update(ns_dyn_mem_tracker_lib_conf_t *conf);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* NSDYNMEM_TRACKER_LIB_H_ */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,11 @@
 | 
			
		|||
{
 | 
			
		||||
    "name": "nanostack-libservice",
 | 
			
		||||
    "macros": ["NSDYNMEM_TRACKER_ENABLED=MBED_CONF_NANOSTACK_LIBSERVICE_NSDYNMEM_TRACKER_ENABLED"],
 | 
			
		||||
    "config": {
 | 
			
		||||
        "present": 1
 | 
			
		||||
        "present": 1,
 | 
			
		||||
        "nsdynmem-tracker-enabled": {
 | 
			
		||||
            "help": "Use to enable dynamic memory tracker",
 | 
			
		||||
            "value": 0
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@
 | 
			
		|||
 */
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#undef NSDYNMEM_TRACKER_ENABLED
 | 
			
		||||
#include "nsdynmemLIB.h"
 | 
			
		||||
#include "platform/arm_hal_interrupt.h"
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +48,7 @@ struct ns_mem_book {
 | 
			
		|||
    ns_mem_heap_size_t temporary_alloc_heap_limit;   /* Amount of reserved heap temporary alloc can't exceed */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static mem_stat_t default_stats;
 | 
			
		||||
static ns_mem_book_t *default_book; // heap pointer for original "ns_" API use
 | 
			
		||||
 | 
			
		||||
// size of a hole_t in our word units
 | 
			
		||||
| 
						 | 
				
			
			@ -162,12 +164,14 @@ ns_mem_book_t *ns_mem_init(void *heap, ns_mem_heap_size_t h_size,
 | 
			
		|||
    ns_list_init(&book->holes_list);
 | 
			
		||||
    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
 | 
			
		||||
    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;
 | 
			
		||||
        book->mem_stat_info_ptr = info_ptr;
 | 
			
		||||
    } else {
 | 
			
		||||
        book->mem_stat_info_ptr = &default_stats;
 | 
			
		||||
    }
 | 
			
		||||
    //RESET Memory by Heap Len
 | 
			
		||||
    memset(book->mem_stat_info_ptr, 0, sizeof(mem_stat_t));
 | 
			
		||||
    book->mem_stat_info_ptr->heap_sector_size = book->heap_size;
 | 
			
		||||
    book->temporary_alloc_heap_limit = book->heap_size / 100 * (100 - TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD);
 | 
			
		||||
#endif
 | 
			
		||||
    //There really is no support to standard malloc in this library anymore
 | 
			
		||||
| 
						 | 
				
			
			@ -234,9 +238,7 @@ int ns_mem_region_add(ns_mem_book_t *book, void *region_ptr, ns_mem_heap_size_t
 | 
			
		|||
    // 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;
 | 
			
		||||
    }
 | 
			
		||||
    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);
 | 
			
		||||
| 
						 | 
				
			
			@ -265,8 +267,8 @@ int ns_mem_set_temporary_alloc_free_heap_threshold(ns_mem_book_t *book, uint8_t
 | 
			
		|||
#ifndef STANDARD_MALLOC
 | 
			
		||||
    ns_mem_heap_size_t heap_limit = 0;
 | 
			
		||||
 | 
			
		||||
    if (!book || !book->mem_stat_info_ptr) {
 | 
			
		||||
        // no book or mem_stats
 | 
			
		||||
    if (!book) {
 | 
			
		||||
        // no book
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -304,25 +306,25 @@ extern int ns_dyn_mem_set_temporary_alloc_free_heap_threshold(uint8_t free_heap_
 | 
			
		|||
#ifndef STANDARD_MALLOC
 | 
			
		||||
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) {
 | 
			
		||||
        switch (type) {
 | 
			
		||||
            case DEV_HEAP_ALLOC_OK:
 | 
			
		||||
                mem_stat_info_ptr->heap_sector_alloc_cnt++;
 | 
			
		||||
                mem_stat_info_ptr->heap_sector_allocated_bytes += size;
 | 
			
		||||
                if (mem_stat_info_ptr->heap_sector_allocated_bytes_max < mem_stat_info_ptr->heap_sector_allocated_bytes) {
 | 
			
		||||
                    mem_stat_info_ptr->heap_sector_allocated_bytes_max = mem_stat_info_ptr->heap_sector_allocated_bytes;
 | 
			
		||||
                }
 | 
			
		||||
                mem_stat_info_ptr->heap_alloc_total_bytes += size;
 | 
			
		||||
                break;
 | 
			
		||||
            case DEV_HEAP_ALLOC_FAIL:
 | 
			
		||||
                mem_stat_info_ptr->heap_alloc_fail_cnt++;
 | 
			
		||||
                break;
 | 
			
		||||
            case DEV_HEAP_FREE:
 | 
			
		||||
                mem_stat_info_ptr->heap_sector_alloc_cnt--;
 | 
			
		||||
                mem_stat_info_ptr->heap_sector_allocated_bytes -= size;
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    switch (type) {
 | 
			
		||||
        case DEV_HEAP_ALLOC_OK:
 | 
			
		||||
            mem_stat_info_ptr->heap_sector_alloc_cnt++;
 | 
			
		||||
            mem_stat_info_ptr->heap_sector_allocated_bytes += size;
 | 
			
		||||
            if (mem_stat_info_ptr->heap_sector_allocated_bytes_max < mem_stat_info_ptr->heap_sector_allocated_bytes) {
 | 
			
		||||
                mem_stat_info_ptr->heap_sector_allocated_bytes_max = mem_stat_info_ptr->heap_sector_allocated_bytes;
 | 
			
		||||
            }
 | 
			
		||||
            mem_stat_info_ptr->heap_alloc_total_bytes += size;
 | 
			
		||||
            break;
 | 
			
		||||
        case DEV_HEAP_ALLOC_FAIL:
 | 
			
		||||
            mem_stat_info_ptr->heap_alloc_fail_cnt++;
 | 
			
		||||
            break;
 | 
			
		||||
        case DEV_HEAP_FREE:
 | 
			
		||||
            mem_stat_info_ptr->heap_sector_alloc_cnt--;
 | 
			
		||||
            mem_stat_info_ptr->heap_sector_allocated_bytes -= size;
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ns_mem_word_size_t convert_allocation_size(ns_mem_book_t *book, ns_mem_block_size_t requested_bytes)
 | 
			
		||||
| 
						 | 
				
			
			@ -363,7 +365,7 @@ static void *ns_mem_internal_alloc(ns_mem_book_t *book, const ns_mem_block_size_
 | 
			
		|||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (book->mem_stat_info_ptr && direction == 1) {
 | 
			
		||||
    if (direction == 1) {
 | 
			
		||||
        if (book->mem_stat_info_ptr->heap_sector_allocated_bytes > book->temporary_alloc_heap_limit) {
 | 
			
		||||
            /* Not enough heap for temporary memory allocation */
 | 
			
		||||
            dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -441,14 +443,14 @@ static void *ns_mem_internal_alloc(ns_mem_book_t *book, const ns_mem_block_size_
 | 
			
		|||
    block_ptr[1 + data_size] = data_size;
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
    if (book->mem_stat_info_ptr) {
 | 
			
		||||
        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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
    platform_exit_critical();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -619,10 +621,8 @@ void ns_mem_free(ns_mem_book_t *book, void *block)
 | 
			
		|||
            heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
 | 
			
		||||
        } else {
 | 
			
		||||
            ns_mem_free_and_merge_with_adjacent_blocks(book, ptr, size);
 | 
			
		||||
            if (book->mem_stat_info_ptr) {
 | 
			
		||||
                //Update Free Counter
 | 
			
		||||
                dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_FREE, (size + 2) * sizeof(ns_mem_word_size_t));
 | 
			
		||||
            }
 | 
			
		||||
            //Update Free Counter
 | 
			
		||||
            dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_FREE, (size + 2) * sizeof(ns_mem_word_size_t));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,480 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2020 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.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include "ns_types.h"
 | 
			
		||||
#include "nsdynmem_tracker_lib.h"
 | 
			
		||||
#include "platform/arm_hal_interrupt.h"
 | 
			
		||||
#include "nsdynmemLIB.h"
 | 
			
		||||
 | 
			
		||||
#if NSDYNMEM_TRACKER_ENABLED==1
 | 
			
		||||
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_find_free_index(ns_dyn_mem_tracker_lib_conf_t *conf, uint16_t *index);
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_find_caller_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, uint16_t *caller_index);
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_find_block_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *block, uint16_t *block_index);
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_ext_find_free_index(ns_dyn_mem_tracker_lib_conf_t *conf, uint32_t start_index, uint32_t *free_index);
 | 
			
		||||
static void ns_dyn_mem_tracker_lib_permanent_printed_value_set(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, bool new_value);
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_ext_find_block_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *block, uint32_t start_index, uint32_t *block_index);
 | 
			
		||||
 | 
			
		||||
int8_t ns_dyn_mem_tracker_lib_alloc(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, const char *function, uint32_t line, void *block, uint32_t alloc_size)
 | 
			
		||||
{
 | 
			
		||||
    // Allocation failed
 | 
			
		||||
    if (block == NULL) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    platform_enter_critical();
 | 
			
		||||
 | 
			
		||||
    // If dynamic memory blocks are not set, calls allocator
 | 
			
		||||
    if (conf->mem_blocks == NULL) {
 | 
			
		||||
        conf->mem_blocks = conf->alloc_mem_blocks(conf->mem_blocks, &conf->mem_blocks_count);
 | 
			
		||||
        if (conf->mem_blocks == NULL) {
 | 
			
		||||
            platform_exit_critical();
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t caller_index = 0;
 | 
			
		||||
    if (ns_dyn_mem_tracker_lib_find_caller_index(conf, caller_addr, &caller_index) >= 0) {
 | 
			
		||||
        if (conf->ext_mem_blocks == NULL) {
 | 
			
		||||
            conf->ext_mem_blocks = conf->ext_alloc_mem_blocks(conf->ext_mem_blocks, &conf->ext_mem_blocks_count);
 | 
			
		||||
            if (conf->ext_mem_blocks == NULL) {
 | 
			
		||||
                platform_exit_critical();
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uint32_t free_index = 0;
 | 
			
		||||
        uint32_t start_index = 0;
 | 
			
		||||
        if (conf->block_index_hash != NULL) {
 | 
			
		||||
            start_index = conf->block_index_hash(block, conf->ext_mem_blocks_count);
 | 
			
		||||
        }
 | 
			
		||||
        if (ns_dyn_mem_tracker_lib_ext_find_free_index(conf, start_index, &free_index) < 0) {
 | 
			
		||||
            conf->ext_mem_blocks = conf->ext_alloc_mem_blocks(conf->ext_mem_blocks, &conf->ext_mem_blocks_count);
 | 
			
		||||
            if (conf->ext_mem_blocks == NULL) {
 | 
			
		||||
                platform_exit_critical();
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
            if (conf->block_index_hash != NULL) {
 | 
			
		||||
                start_index = conf->block_index_hash(block, conf->ext_mem_blocks_count);
 | 
			
		||||
            }
 | 
			
		||||
            if (ns_dyn_mem_tracker_lib_ext_find_free_index(conf, start_index, &free_index) < 0) {
 | 
			
		||||
                platform_exit_critical();
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Updates memory blocks array entry
 | 
			
		||||
        conf->mem_blocks[caller_index].ref_count++;
 | 
			
		||||
        conf->mem_blocks[caller_index].total_size += alloc_size;
 | 
			
		||||
        conf->mem_blocks[caller_index].lifetime = 0;
 | 
			
		||||
        conf->mem_blocks[caller_index].permanent = false;
 | 
			
		||||
        conf->mem_blocks[caller_index].permanent_printed = false;
 | 
			
		||||
 | 
			
		||||
        conf->ext_mem_blocks[free_index].block = block;
 | 
			
		||||
        conf->ext_mem_blocks[free_index].caller_addr = caller_addr;
 | 
			
		||||
        conf->ext_mem_blocks[free_index].size = alloc_size;
 | 
			
		||||
 | 
			
		||||
        conf->allocated_memory += alloc_size;
 | 
			
		||||
 | 
			
		||||
        platform_exit_critical();
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t free_index = 0;
 | 
			
		||||
    if (ns_dyn_mem_tracker_lib_find_free_index(conf, &free_index) < 0) {
 | 
			
		||||
        conf->mem_blocks = conf->alloc_mem_blocks(conf->mem_blocks, &conf->mem_blocks_count);
 | 
			
		||||
        if (conf->mem_blocks == NULL || (ns_dyn_mem_tracker_lib_find_free_index(conf, &free_index) < 0)) {
 | 
			
		||||
            platform_exit_critical();
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    conf->mem_blocks[free_index].block = block;
 | 
			
		||||
    conf->mem_blocks[free_index].caller_addr = caller_addr;
 | 
			
		||||
    conf->mem_blocks[free_index].size = alloc_size;
 | 
			
		||||
    conf->mem_blocks[free_index].total_size = alloc_size;
 | 
			
		||||
    conf->mem_blocks[free_index].lifetime = 0;
 | 
			
		||||
    conf->mem_blocks[free_index].ref_count = 1;
 | 
			
		||||
    conf->mem_blocks[free_index].function = function;
 | 
			
		||||
    conf->mem_blocks[free_index].line = line;
 | 
			
		||||
    conf->mem_blocks[free_index].permanent = false;
 | 
			
		||||
    conf->mem_blocks[free_index].permanent_printed = false;
 | 
			
		||||
 | 
			
		||||
    if (free_index > conf->last_mem_block_index) {
 | 
			
		||||
        conf->last_mem_block_index = free_index;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    conf->allocated_memory += alloc_size;
 | 
			
		||||
 | 
			
		||||
    platform_exit_critical();
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int8_t ns_dyn_mem_tracker_lib_free(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, const char *function, uint32_t line, void *block)
 | 
			
		||||
{
 | 
			
		||||
    (void) function;
 | 
			
		||||
    (void) line;
 | 
			
		||||
    (void) caller_addr;
 | 
			
		||||
 | 
			
		||||
    // No memory block or no allocations made
 | 
			
		||||
    if (block == NULL || conf->mem_blocks == NULL) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    platform_enter_critical();
 | 
			
		||||
 | 
			
		||||
    uint16_t block_index = 0;
 | 
			
		||||
    if (ns_dyn_mem_tracker_lib_find_block_index(conf, block, &block_index) >= 0) {
 | 
			
		||||
        // If last block for allocator clears the allocator
 | 
			
		||||
        if (conf->mem_blocks[block_index].ref_count <= 1) {
 | 
			
		||||
            conf->mem_blocks[block_index].ref_count = 0;
 | 
			
		||||
            conf->mem_blocks[block_index].caller_addr = NULL;
 | 
			
		||||
            conf->mem_blocks[block_index].total_size = 0;
 | 
			
		||||
            conf->mem_blocks[block_index].function = NULL;
 | 
			
		||||
            conf->mem_blocks[block_index].line = 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Other blocks exists
 | 
			
		||||
            conf->mem_blocks[block_index].ref_count--;
 | 
			
		||||
            conf->mem_blocks[block_index].total_size -= conf->mem_blocks[block_index].size;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        conf->allocated_memory -= conf->mem_blocks[block_index].size;
 | 
			
		||||
 | 
			
		||||
        // Clears block specific fields
 | 
			
		||||
        conf->mem_blocks[block_index].block = NULL;
 | 
			
		||||
        conf->mem_blocks[block_index].size = 0;
 | 
			
		||||
        // Resets lifetime and permanent settings
 | 
			
		||||
        conf->mem_blocks[block_index].lifetime = 0;
 | 
			
		||||
        conf->mem_blocks[block_index].permanent = false;
 | 
			
		||||
        conf->mem_blocks[block_index].permanent_printed = false;
 | 
			
		||||
 | 
			
		||||
        platform_exit_critical();
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (conf->ext_mem_blocks == NULL) {
 | 
			
		||||
        platform_exit_critical();
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint32_t ext_block_index = 0;
 | 
			
		||||
    uint32_t start_index = 0;
 | 
			
		||||
    if (conf->block_index_hash != NULL) {
 | 
			
		||||
        start_index = conf->block_index_hash(block, conf->ext_mem_blocks_count);
 | 
			
		||||
    }
 | 
			
		||||
    if (ns_dyn_mem_tracker_lib_ext_find_block_index(conf, block, start_index, &ext_block_index) < 0) {
 | 
			
		||||
        platform_exit_critical();
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void *ext_caller_addr = conf->ext_mem_blocks[ext_block_index].caller_addr;
 | 
			
		||||
 | 
			
		||||
    uint16_t caller_index;
 | 
			
		||||
    if (ns_dyn_mem_tracker_lib_find_caller_index(conf, ext_caller_addr, &caller_index) < 0) {
 | 
			
		||||
        platform_exit_critical();
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    conf->mem_blocks[caller_index].ref_count--;
 | 
			
		||||
    conf->mem_blocks[caller_index].total_size -= conf->ext_mem_blocks[ext_block_index].size;
 | 
			
		||||
 | 
			
		||||
    conf->allocated_memory -= conf->ext_mem_blocks[ext_block_index].size;
 | 
			
		||||
 | 
			
		||||
    // Clears extended block
 | 
			
		||||
    conf->ext_mem_blocks[ext_block_index].block = NULL;
 | 
			
		||||
    conf->ext_mem_blocks[ext_block_index].caller_addr = NULL;
 | 
			
		||||
    conf->ext_mem_blocks[ext_block_index].size = 0;
 | 
			
		||||
 | 
			
		||||
    // Resets lifetime and permanent settings
 | 
			
		||||
    conf->mem_blocks[block_index].lifetime = 0;
 | 
			
		||||
    conf->mem_blocks[block_index].permanent = false;
 | 
			
		||||
    conf->mem_blocks[block_index].permanent_printed = false;
 | 
			
		||||
 | 
			
		||||
    // If last block for allocator clears the allocator
 | 
			
		||||
    if (conf->mem_blocks[block_index].ref_count == 0) {
 | 
			
		||||
        conf->mem_blocks[block_index].block = NULL;
 | 
			
		||||
        conf->mem_blocks[block_index].caller_addr = NULL;
 | 
			
		||||
        conf->mem_blocks[block_index].size = 0;
 | 
			
		||||
        conf->mem_blocks[block_index].total_size = 0;
 | 
			
		||||
        conf->mem_blocks[block_index].function = NULL;
 | 
			
		||||
        conf->mem_blocks[block_index].line = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    platform_exit_critical();
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ns_dyn_mem_tracker_lib_step(ns_dyn_mem_tracker_lib_conf_t *conf)
 | 
			
		||||
{
 | 
			
		||||
    platform_enter_critical();
 | 
			
		||||
 | 
			
		||||
    if (conf->mem_blocks_count != 0) {
 | 
			
		||||
        for (uint32_t index = 0; index <= conf->last_mem_block_index; index++) {
 | 
			
		||||
            if (conf->mem_blocks[index].block != NULL) {
 | 
			
		||||
                conf->mem_blocks[index].lifetime++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    platform_exit_critical();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int8_t ns_dyn_mem_tracker_lib_allocator_lists_update(ns_dyn_mem_tracker_lib_conf_t *conf)
 | 
			
		||||
{
 | 
			
		||||
    platform_enter_critical();
 | 
			
		||||
 | 
			
		||||
    ns_dyn_mem_tracker_lib_mem_blocks_t *blocks = conf->mem_blocks;
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *top_allocators = conf->top_allocators;
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *permanent_allocators = conf->permanent_allocators;
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *to_permanent_allocators = conf->to_permanent_allocators;
 | 
			
		||||
 | 
			
		||||
    uint16_t top_allocators_count = conf->top_allocators_count;
 | 
			
		||||
    uint16_t permanent_allocators_count = conf->permanent_allocators_count;
 | 
			
		||||
    uint16_t to_permanent_allocators_count = conf->to_permanent_allocators_count;
 | 
			
		||||
 | 
			
		||||
    memset(top_allocators, 0, top_allocators_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t));
 | 
			
		||||
    memset(permanent_allocators, 0, permanent_allocators_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t));
 | 
			
		||||
    memset(to_permanent_allocators, 0, to_permanent_allocators_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t));
 | 
			
		||||
 | 
			
		||||
    // Maximum set as permanent in one go
 | 
			
		||||
    uint8_t to_permanent_count = 0;
 | 
			
		||||
 | 
			
		||||
    // Maximum to print of permanent entries
 | 
			
		||||
    uint8_t permanent_count = 0;
 | 
			
		||||
 | 
			
		||||
    for (uint32_t index = 0; index <= conf->last_mem_block_index; index++) {
 | 
			
		||||
        if (blocks[index].block != NULL) {
 | 
			
		||||
            void *caller_addr = blocks[index].caller_addr;
 | 
			
		||||
 | 
			
		||||
            // Checks if caller address has already been counted
 | 
			
		||||
            bool next = false;
 | 
			
		||||
            for (uint32_t list_index = 0; list_index < top_allocators_count; list_index++) {
 | 
			
		||||
                if (top_allocators[list_index].caller_addr == caller_addr) {
 | 
			
		||||
                    next = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (next) {
 | 
			
		||||
                // Already on list, continue
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Checks whether all reference are marked permanent
 | 
			
		||||
            if (blocks[index].permanent) {
 | 
			
		||||
                if (!blocks[index].permanent_printed && permanent_count < permanent_allocators_count) {
 | 
			
		||||
                    permanent_allocators[permanent_count].caller_addr = caller_addr;
 | 
			
		||||
                    permanent_allocators[permanent_count].alloc_count = blocks[index].ref_count;
 | 
			
		||||
                    permanent_allocators[permanent_count].total_memory = blocks[index].total_size;
 | 
			
		||||
                    permanent_allocators[permanent_count].min_lifetime = blocks[index].lifetime;
 | 
			
		||||
                    permanent_allocators[permanent_count].function = blocks[index].function;
 | 
			
		||||
                    permanent_allocators[permanent_count].line = blocks[index].line;
 | 
			
		||||
 | 
			
		||||
                    permanent_count++;
 | 
			
		||||
                    blocks[index].permanent_printed = true;
 | 
			
		||||
                }
 | 
			
		||||
                continue;
 | 
			
		||||
            } else {
 | 
			
		||||
                // Checks whether lifetime threshold has been reached, traces and skips
 | 
			
		||||
                if (blocks[index].lifetime > conf->to_permanent_steps_count && to_permanent_count < to_permanent_allocators_count) {
 | 
			
		||||
                    blocks[index].permanent = true;
 | 
			
		||||
 | 
			
		||||
                    to_permanent_allocators[to_permanent_count].caller_addr = caller_addr;
 | 
			
		||||
                    to_permanent_allocators[to_permanent_count].alloc_count = blocks[index].ref_count;
 | 
			
		||||
                    to_permanent_allocators[to_permanent_count].total_memory = blocks[index].total_size;
 | 
			
		||||
                    to_permanent_allocators[to_permanent_count].min_lifetime = blocks[index].lifetime;
 | 
			
		||||
                    to_permanent_allocators[to_permanent_count].function = blocks[index].function;
 | 
			
		||||
                    to_permanent_allocators[to_permanent_count].line = blocks[index].line;
 | 
			
		||||
 | 
			
		||||
                    to_permanent_count++;
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Add to list if allocation count is larger than entry on the list
 | 
			
		||||
            for (uint16_t list_index = 0; list_index < top_allocators_count; list_index++) {
 | 
			
		||||
                if (blocks[index].ref_count >= top_allocators[list_index].alloc_count) {
 | 
			
		||||
                    if (list_index != (top_allocators_count - 1)) {
 | 
			
		||||
                        uint8_t index_count = (top_allocators_count - list_index - 1);
 | 
			
		||||
                        uint32_t size = index_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t);
 | 
			
		||||
                        memmove(&top_allocators[list_index + 1], &top_allocators[list_index], size);
 | 
			
		||||
                    }
 | 
			
		||||
                    top_allocators[list_index].caller_addr = caller_addr;
 | 
			
		||||
                    top_allocators[list_index].alloc_count = blocks[index].ref_count;
 | 
			
		||||
                    top_allocators[list_index].total_memory = blocks[index].total_size;
 | 
			
		||||
                    top_allocators[list_index].min_lifetime = blocks[index].lifetime;
 | 
			
		||||
                    top_allocators[list_index].function = blocks[index].function;
 | 
			
		||||
                    top_allocators[list_index].line = blocks[index].line;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (permanent_count < permanent_allocators_count) {
 | 
			
		||||
        ns_dyn_mem_tracker_lib_permanent_printed_value_set(conf, NULL, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    platform_exit_critical();
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ns_dyn_mem_tracker_lib_max_snap_shot_update(ns_dyn_mem_tracker_lib_conf_t *conf)
 | 
			
		||||
{
 | 
			
		||||
    platform_enter_critical();
 | 
			
		||||
 | 
			
		||||
    ns_dyn_mem_tracker_lib_mem_blocks_t *blocks = conf->mem_blocks;
 | 
			
		||||
    ns_dyn_mem_tracker_lib_allocators_t *max_snap_shot_allocators = conf->max_snap_shot_allocators;
 | 
			
		||||
 | 
			
		||||
    uint16_t max_snap_shot_allocators_count = conf->max_snap_shot_allocators_count;
 | 
			
		||||
 | 
			
		||||
    memset(max_snap_shot_allocators, 0, max_snap_shot_allocators_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t));
 | 
			
		||||
 | 
			
		||||
    for (uint32_t index = 0; index <= conf->last_mem_block_index; index++) {
 | 
			
		||||
        if (blocks[index].block != NULL) {
 | 
			
		||||
            void *caller_addr = blocks[index].caller_addr;
 | 
			
		||||
 | 
			
		||||
            // Checks if caller address has already been counted
 | 
			
		||||
            bool next = false;
 | 
			
		||||
            for (uint16_t list_index = 0; list_index < max_snap_shot_allocators_count; list_index++) {
 | 
			
		||||
                if (max_snap_shot_allocators[list_index].caller_addr == caller_addr) {
 | 
			
		||||
                    next = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (next) {
 | 
			
		||||
                // Already on list, continue
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Add to list if allocation count is larger than entry on the list
 | 
			
		||||
            for (uint16_t list_index = 0; list_index < max_snap_shot_allocators_count; list_index++) {
 | 
			
		||||
                if (blocks[index].total_size >= max_snap_shot_allocators[list_index].total_memory) {
 | 
			
		||||
                    if (list_index != (max_snap_shot_allocators_count - 1)) {
 | 
			
		||||
                        uint8_t index_count = (max_snap_shot_allocators_count - list_index - 1);
 | 
			
		||||
                        uint32_t size = index_count * sizeof(ns_dyn_mem_tracker_lib_allocators_t);
 | 
			
		||||
                        memmove(&max_snap_shot_allocators[list_index + 1], &max_snap_shot_allocators[list_index], size);
 | 
			
		||||
                    }
 | 
			
		||||
                    max_snap_shot_allocators[list_index].caller_addr = blocks[index].caller_addr;
 | 
			
		||||
                    max_snap_shot_allocators[list_index].alloc_count = blocks[index].ref_count;
 | 
			
		||||
                    max_snap_shot_allocators[list_index].total_memory = blocks[index].total_size;
 | 
			
		||||
                    max_snap_shot_allocators[list_index].min_lifetime = blocks[index].lifetime;
 | 
			
		||||
                    max_snap_shot_allocators[list_index].function = blocks[index].function;
 | 
			
		||||
                    max_snap_shot_allocators[list_index].line = blocks[index].line;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    platform_exit_critical();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ns_dyn_mem_tracker_lib_permanent_printed_value_set(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, bool new_value)
 | 
			
		||||
{
 | 
			
		||||
    /* Search for all the references to the caller address from the allocation info and
 | 
			
		||||
       set block permanent value */
 | 
			
		||||
    for (uint16_t search_index = 0; search_index <= conf->last_mem_block_index; search_index++) {
 | 
			
		||||
        if (caller_addr == NULL || conf->mem_blocks[search_index].caller_addr == caller_addr) {
 | 
			
		||||
            conf->mem_blocks[search_index].permanent_printed = new_value;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_find_free_index(ns_dyn_mem_tracker_lib_conf_t *conf, uint16_t *free_index)
 | 
			
		||||
{
 | 
			
		||||
    for (uint16_t index = 0; index < conf->mem_blocks_count; index++) {
 | 
			
		||||
        if (conf->mem_blocks[index].caller_addr == NULL) {
 | 
			
		||||
            *free_index = index;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_find_caller_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *caller_addr, uint16_t *caller_index)
 | 
			
		||||
{
 | 
			
		||||
    for (uint16_t index = 0; index <= conf->last_mem_block_index; index++) {
 | 
			
		||||
        if (conf->mem_blocks[index].caller_addr == caller_addr) {
 | 
			
		||||
            *caller_index = index;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_find_block_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *block, uint16_t *block_index)
 | 
			
		||||
{
 | 
			
		||||
    for (uint16_t index = 0; index <= conf->last_mem_block_index; index++) {
 | 
			
		||||
        if (conf->mem_blocks[index].block == block) {
 | 
			
		||||
            *block_index = index;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_ext_find_free_index(ns_dyn_mem_tracker_lib_conf_t *conf, uint32_t start_index, uint32_t *free_index)
 | 
			
		||||
{
 | 
			
		||||
    for (uint32_t index = start_index; index < conf->ext_mem_blocks_count; index++) {
 | 
			
		||||
        if (conf->ext_mem_blocks[index].caller_addr == NULL) {
 | 
			
		||||
            *free_index = index;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (start_index == 0) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (uint32_t index = 0; index < start_index; index++) {
 | 
			
		||||
        if (conf->ext_mem_blocks[index].caller_addr == NULL) {
 | 
			
		||||
            *free_index = index;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int8_t ns_dyn_mem_tracker_lib_ext_find_block_index(ns_dyn_mem_tracker_lib_conf_t *conf, void *block, uint32_t start_index, uint32_t *block_index)
 | 
			
		||||
{
 | 
			
		||||
    for (uint32_t index = start_index; index < conf->ext_mem_blocks_count; index++) {
 | 
			
		||||
        if (conf->ext_mem_blocks[index].block == block) {
 | 
			
		||||
            *block_index = index;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (start_index == 0) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (uint32_t index = 0; index < start_index; index++) {
 | 
			
		||||
        if (conf->ext_mem_blocks[index].block == block) {
 | 
			
		||||
            *block_index = index;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -400,12 +400,12 @@ TEST(dynmem, ns_dyn_mem_temporary_alloc_with_heap_threshold)
 | 
			
		|||
    CHECK(info.heap_sector_alloc_cnt == 0);
 | 
			
		||||
    free(heap);
 | 
			
		||||
 | 
			
		||||
    // Test6, feature is disabled if info is not set
 | 
			
		||||
    // Test6, feature is disabled if info is coming anyway
 | 
			
		||||
    heap = (uint8_t *)malloc(size);
 | 
			
		||||
    CHECK(NULL != heap);
 | 
			
		||||
    ns_dyn_mem_init(heap, size, &heap_fail_callback, NULL);
 | 
			
		||||
    ret_val = ns_dyn_mem_set_temporary_alloc_free_heap_threshold(0, 0);
 | 
			
		||||
    CHECK(ret_val == -1);
 | 
			
		||||
    CHECK(ret_val == 0);
 | 
			
		||||
    CHECK(!heap_have_failed());
 | 
			
		||||
    free(heap);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue