leo hendrickson / Mbed OS example-Ethernet-mbed-Cloud-connect
Committer:
leothedragon
Date:
Tue May 04 08:55:12 2021 +0000
Revision:
0:8f0bb79ddd48
nmn

Who changed what in which revision?

UserRevisionLine numberNew contents of line
leothedragon 0:8f0bb79ddd48 1 /*
leothedragon 0:8f0bb79ddd48 2 * Copyright (c) 2014-2018 ARM Limited. All rights reserved.
leothedragon 0:8f0bb79ddd48 3 * SPDX-License-Identifier: Apache-2.0
leothedragon 0:8f0bb79ddd48 4 * Licensed under the Apache License, Version 2.0 (the License); you may
leothedragon 0:8f0bb79ddd48 5 * not use this file except in compliance with the License.
leothedragon 0:8f0bb79ddd48 6 * You may obtain a copy of the License at
leothedragon 0:8f0bb79ddd48 7 *
leothedragon 0:8f0bb79ddd48 8 * http://www.apache.org/licenses/LICENSE-2.0
leothedragon 0:8f0bb79ddd48 9 *
leothedragon 0:8f0bb79ddd48 10 * Unless required by applicable law or agreed to in writing, software
leothedragon 0:8f0bb79ddd48 11 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
leothedragon 0:8f0bb79ddd48 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
leothedragon 0:8f0bb79ddd48 13 * See the License for the specific language governing permissions and
leothedragon 0:8f0bb79ddd48 14 * limitations under the License.
leothedragon 0:8f0bb79ddd48 15 */
leothedragon 0:8f0bb79ddd48 16 #include <stdint.h>
leothedragon 0:8f0bb79ddd48 17 #include <string.h>
leothedragon 0:8f0bb79ddd48 18 #include "nsdynmemLIB.h"
leothedragon 0:8f0bb79ddd48 19 #include "platform/arm_hal_interrupt.h"
leothedragon 0:8f0bb79ddd48 20 #include <stdlib.h>
leothedragon 0:8f0bb79ddd48 21 #include "ns_list.h"
leothedragon 0:8f0bb79ddd48 22
leothedragon 0:8f0bb79ddd48 23 #ifndef STANDARD_MALLOC
leothedragon 0:8f0bb79ddd48 24 typedef enum mem_stat_update_t {
leothedragon 0:8f0bb79ddd48 25 DEV_HEAP_ALLOC_OK,
leothedragon 0:8f0bb79ddd48 26 DEV_HEAP_ALLOC_FAIL,
leothedragon 0:8f0bb79ddd48 27 DEV_HEAP_FREE,
leothedragon 0:8f0bb79ddd48 28 } mem_stat_update_t;
leothedragon 0:8f0bb79ddd48 29
leothedragon 0:8f0bb79ddd48 30 typedef struct {
leothedragon 0:8f0bb79ddd48 31 ns_list_link_t link;
leothedragon 0:8f0bb79ddd48 32 } hole_t;
leothedragon 0:8f0bb79ddd48 33
leothedragon 0:8f0bb79ddd48 34 typedef int ns_mem_word_size_t; // internal signed heap block size type
leothedragon 0:8f0bb79ddd48 35
leothedragon 0:8f0bb79ddd48 36 /* struct for book keeping variables */
leothedragon 0:8f0bb79ddd48 37 struct ns_mem_book {
leothedragon 0:8f0bb79ddd48 38 ns_mem_word_size_t *heap_main;
leothedragon 0:8f0bb79ddd48 39 ns_mem_word_size_t *heap_main_end;
leothedragon 0:8f0bb79ddd48 40 mem_stat_t *mem_stat_info_ptr;
leothedragon 0:8f0bb79ddd48 41 void (*heap_failure_callback)(heap_fail_t);
leothedragon 0:8f0bb79ddd48 42 NS_LIST_HEAD(hole_t, link) holes_list;
leothedragon 0:8f0bb79ddd48 43 ns_mem_heap_size_t heap_size;
leothedragon 0:8f0bb79ddd48 44 ns_mem_heap_size_t temporary_alloc_heap_limit; /* Amount of reserved heap temporary alloc can't exceed */
leothedragon 0:8f0bb79ddd48 45 };
leothedragon 0:8f0bb79ddd48 46
leothedragon 0:8f0bb79ddd48 47 static ns_mem_book_t *default_book; // heap pointer for original "ns_" API use
leothedragon 0:8f0bb79ddd48 48
leothedragon 0:8f0bb79ddd48 49 // size of a hole_t in our word units
leothedragon 0:8f0bb79ddd48 50 #define HOLE_T_SIZE ((ns_mem_word_size_t) ((sizeof(hole_t) + sizeof(ns_mem_word_size_t) - 1) / sizeof(ns_mem_word_size_t)))
leothedragon 0:8f0bb79ddd48 51
leothedragon 0:8f0bb79ddd48 52 #define TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD 5 /* temporary allocations must leave 5% of the heap free */
leothedragon 0:8f0bb79ddd48 53
leothedragon 0:8f0bb79ddd48 54 static NS_INLINE hole_t *hole_from_block_start(ns_mem_word_size_t *start)
leothedragon 0:8f0bb79ddd48 55 {
leothedragon 0:8f0bb79ddd48 56 return (hole_t *)(start + 1);
leothedragon 0:8f0bb79ddd48 57 }
leothedragon 0:8f0bb79ddd48 58
leothedragon 0:8f0bb79ddd48 59 static NS_INLINE ns_mem_word_size_t *block_start_from_hole(hole_t *start)
leothedragon 0:8f0bb79ddd48 60 {
leothedragon 0:8f0bb79ddd48 61 return ((ns_mem_word_size_t *)start) - 1;
leothedragon 0:8f0bb79ddd48 62 }
leothedragon 0:8f0bb79ddd48 63
leothedragon 0:8f0bb79ddd48 64 static void heap_failure(ns_mem_book_t *book, heap_fail_t reason)
leothedragon 0:8f0bb79ddd48 65 {
leothedragon 0:8f0bb79ddd48 66 if (book->heap_failure_callback) {
leothedragon 0:8f0bb79ddd48 67 book->heap_failure_callback(reason);
leothedragon 0:8f0bb79ddd48 68 }
leothedragon 0:8f0bb79ddd48 69 }
leothedragon 0:8f0bb79ddd48 70
leothedragon 0:8f0bb79ddd48 71 #endif
leothedragon 0:8f0bb79ddd48 72
leothedragon 0:8f0bb79ddd48 73 void ns_dyn_mem_init(void *heap, ns_mem_heap_size_t h_size,
leothedragon 0:8f0bb79ddd48 74 void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr)
leothedragon 0:8f0bb79ddd48 75 {
leothedragon 0:8f0bb79ddd48 76 default_book = ns_mem_init(heap, h_size, passed_fptr, info_ptr);
leothedragon 0:8f0bb79ddd48 77 }
leothedragon 0:8f0bb79ddd48 78
leothedragon 0:8f0bb79ddd48 79 const mem_stat_t *ns_dyn_mem_get_mem_stat(void)
leothedragon 0:8f0bb79ddd48 80 {
leothedragon 0:8f0bb79ddd48 81 #ifndef STANDARD_MALLOC
leothedragon 0:8f0bb79ddd48 82 return ns_mem_get_mem_stat(default_book);
leothedragon 0:8f0bb79ddd48 83 #else
leothedragon 0:8f0bb79ddd48 84 return NULL;
leothedragon 0:8f0bb79ddd48 85 #endif
leothedragon 0:8f0bb79ddd48 86 }
leothedragon 0:8f0bb79ddd48 87
leothedragon 0:8f0bb79ddd48 88
leothedragon 0:8f0bb79ddd48 89 ns_mem_book_t *ns_mem_init(void *heap, ns_mem_heap_size_t h_size,
leothedragon 0:8f0bb79ddd48 90 void (*passed_fptr)(heap_fail_t),
leothedragon 0:8f0bb79ddd48 91 mem_stat_t *info_ptr)
leothedragon 0:8f0bb79ddd48 92 {
leothedragon 0:8f0bb79ddd48 93 #ifndef STANDARD_MALLOC
leothedragon 0:8f0bb79ddd48 94 ns_mem_book_t *book;
leothedragon 0:8f0bb79ddd48 95
leothedragon 0:8f0bb79ddd48 96 ns_mem_word_size_t *ptr;
leothedragon 0:8f0bb79ddd48 97 ns_mem_word_size_t temp_int;
leothedragon 0:8f0bb79ddd48 98 /* Do memory alignment */
leothedragon 0:8f0bb79ddd48 99 temp_int = ((uintptr_t)heap % sizeof(ns_mem_word_size_t));
leothedragon 0:8f0bb79ddd48 100 if (temp_int) {
leothedragon 0:8f0bb79ddd48 101 heap = (uint8_t *) heap + (sizeof(ns_mem_word_size_t) - temp_int);
leothedragon 0:8f0bb79ddd48 102 h_size -= (sizeof(ns_mem_word_size_t) - temp_int);
leothedragon 0:8f0bb79ddd48 103 }
leothedragon 0:8f0bb79ddd48 104
leothedragon 0:8f0bb79ddd48 105 /* Make correction for total length also */
leothedragon 0:8f0bb79ddd48 106 temp_int = (h_size % sizeof(ns_mem_word_size_t));
leothedragon 0:8f0bb79ddd48 107 if (temp_int) {
leothedragon 0:8f0bb79ddd48 108 h_size -= (sizeof(ns_mem_word_size_t) - temp_int);
leothedragon 0:8f0bb79ddd48 109 }
leothedragon 0:8f0bb79ddd48 110 book = heap;
leothedragon 0:8f0bb79ddd48 111 book->heap_main = (ns_mem_word_size_t *) & (book[1]); // SET Heap Pointer
leothedragon 0:8f0bb79ddd48 112 book->heap_size = h_size - sizeof(ns_mem_book_t); //Set Heap Size
leothedragon 0:8f0bb79ddd48 113 temp_int = (book->heap_size / sizeof(ns_mem_word_size_t));
leothedragon 0:8f0bb79ddd48 114 temp_int -= 2;
leothedragon 0:8f0bb79ddd48 115 ptr = book->heap_main;
leothedragon 0:8f0bb79ddd48 116 *ptr = -(temp_int);
leothedragon 0:8f0bb79ddd48 117 ptr += (temp_int + 1);
leothedragon 0:8f0bb79ddd48 118 *ptr = -(temp_int);
leothedragon 0:8f0bb79ddd48 119 book->heap_main_end = ptr;
leothedragon 0:8f0bb79ddd48 120
leothedragon 0:8f0bb79ddd48 121 ns_list_init(&book->holes_list);
leothedragon 0:8f0bb79ddd48 122 ns_list_add_to_start(&book->holes_list, hole_from_block_start(book->heap_main));
leothedragon 0:8f0bb79ddd48 123
leothedragon 0:8f0bb79ddd48 124 book->mem_stat_info_ptr = info_ptr;
leothedragon 0:8f0bb79ddd48 125 //RESET Memory by Hea Len
leothedragon 0:8f0bb79ddd48 126 if (info_ptr) {
leothedragon 0:8f0bb79ddd48 127 memset(book->mem_stat_info_ptr, 0, sizeof(mem_stat_t));
leothedragon 0:8f0bb79ddd48 128 book->mem_stat_info_ptr->heap_sector_size = book->heap_size;
leothedragon 0:8f0bb79ddd48 129 }
leothedragon 0:8f0bb79ddd48 130 book->temporary_alloc_heap_limit = book->heap_size / 100 * (100 - TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD);
leothedragon 0:8f0bb79ddd48 131 #endif
leothedragon 0:8f0bb79ddd48 132 //There really is no support to standard malloc in this library anymore
leothedragon 0:8f0bb79ddd48 133 book->heap_failure_callback = passed_fptr;
leothedragon 0:8f0bb79ddd48 134
leothedragon 0:8f0bb79ddd48 135 return book;
leothedragon 0:8f0bb79ddd48 136 }
leothedragon 0:8f0bb79ddd48 137
leothedragon 0:8f0bb79ddd48 138 const mem_stat_t *ns_mem_get_mem_stat(ns_mem_book_t *heap)
leothedragon 0:8f0bb79ddd48 139 {
leothedragon 0:8f0bb79ddd48 140 #ifndef STANDARD_MALLOC
leothedragon 0:8f0bb79ddd48 141 return heap->mem_stat_info_ptr;
leothedragon 0:8f0bb79ddd48 142 #else
leothedragon 0:8f0bb79ddd48 143 return NULL;
leothedragon 0:8f0bb79ddd48 144 #endif
leothedragon 0:8f0bb79ddd48 145 }
leothedragon 0:8f0bb79ddd48 146
leothedragon 0:8f0bb79ddd48 147 int ns_mem_set_temporary_alloc_free_heap_threshold(ns_mem_book_t *book, uint8_t free_heap_percentage, ns_mem_heap_size_t free_heap_amount)
leothedragon 0:8f0bb79ddd48 148 {
leothedragon 0:8f0bb79ddd48 149 #ifndef STANDARD_MALLOC
leothedragon 0:8f0bb79ddd48 150 ns_mem_heap_size_t heap_limit = 0;
leothedragon 0:8f0bb79ddd48 151
leothedragon 0:8f0bb79ddd48 152 if (!book || !book->mem_stat_info_ptr) {
leothedragon 0:8f0bb79ddd48 153 // no book or mem_stats
leothedragon 0:8f0bb79ddd48 154 return -1;
leothedragon 0:8f0bb79ddd48 155 }
leothedragon 0:8f0bb79ddd48 156
leothedragon 0:8f0bb79ddd48 157 if (free_heap_amount && free_heap_amount < book->heap_size / 2) {
leothedragon 0:8f0bb79ddd48 158 heap_limit = book->heap_size - free_heap_amount;
leothedragon 0:8f0bb79ddd48 159 }
leothedragon 0:8f0bb79ddd48 160
leothedragon 0:8f0bb79ddd48 161 if (!free_heap_amount && free_heap_percentage && free_heap_percentage < 50) {
leothedragon 0:8f0bb79ddd48 162 heap_limit = book->heap_size / 100 * (100 - free_heap_percentage);
leothedragon 0:8f0bb79ddd48 163 }
leothedragon 0:8f0bb79ddd48 164
leothedragon 0:8f0bb79ddd48 165 if (free_heap_amount == 0 && free_heap_percentage == 0) {
leothedragon 0:8f0bb79ddd48 166 // feature disabled, allow whole heap to be reserved by temporary allo
leothedragon 0:8f0bb79ddd48 167 heap_limit = book->heap_size;
leothedragon 0:8f0bb79ddd48 168 }
leothedragon 0:8f0bb79ddd48 169
leothedragon 0:8f0bb79ddd48 170 if (heap_limit == 0) {
leothedragon 0:8f0bb79ddd48 171 // illegal heap parameters
leothedragon 0:8f0bb79ddd48 172 return -2;
leothedragon 0:8f0bb79ddd48 173 }
leothedragon 0:8f0bb79ddd48 174
leothedragon 0:8f0bb79ddd48 175 book->temporary_alloc_heap_limit = heap_limit;
leothedragon 0:8f0bb79ddd48 176
leothedragon 0:8f0bb79ddd48 177 return 0;
leothedragon 0:8f0bb79ddd48 178 #else
leothedragon 0:8f0bb79ddd48 179 return -3;
leothedragon 0:8f0bb79ddd48 180 #endif
leothedragon 0:8f0bb79ddd48 181 }
leothedragon 0:8f0bb79ddd48 182
leothedragon 0:8f0bb79ddd48 183 extern int ns_dyn_mem_set_temporary_alloc_free_heap_threshold(uint8_t free_heap_percentage, ns_mem_heap_size_t free_heap_amount)
leothedragon 0:8f0bb79ddd48 184 {
leothedragon 0:8f0bb79ddd48 185 return ns_mem_set_temporary_alloc_free_heap_threshold(default_book, free_heap_percentage, free_heap_amount);
leothedragon 0:8f0bb79ddd48 186 }
leothedragon 0:8f0bb79ddd48 187
leothedragon 0:8f0bb79ddd48 188 #ifndef STANDARD_MALLOC
leothedragon 0:8f0bb79ddd48 189 static void dev_stat_update(mem_stat_t *mem_stat_info_ptr, mem_stat_update_t type, ns_mem_block_size_t size)
leothedragon 0:8f0bb79ddd48 190 {
leothedragon 0:8f0bb79ddd48 191 if (mem_stat_info_ptr) {
leothedragon 0:8f0bb79ddd48 192 switch (type) {
leothedragon 0:8f0bb79ddd48 193 case DEV_HEAP_ALLOC_OK:
leothedragon 0:8f0bb79ddd48 194 mem_stat_info_ptr->heap_sector_alloc_cnt++;
leothedragon 0:8f0bb79ddd48 195 mem_stat_info_ptr->heap_sector_allocated_bytes += size;
leothedragon 0:8f0bb79ddd48 196 if (mem_stat_info_ptr->heap_sector_allocated_bytes_max < mem_stat_info_ptr->heap_sector_allocated_bytes) {
leothedragon 0:8f0bb79ddd48 197 mem_stat_info_ptr->heap_sector_allocated_bytes_max = mem_stat_info_ptr->heap_sector_allocated_bytes;
leothedragon 0:8f0bb79ddd48 198 }
leothedragon 0:8f0bb79ddd48 199 mem_stat_info_ptr->heap_alloc_total_bytes += size;
leothedragon 0:8f0bb79ddd48 200 break;
leothedragon 0:8f0bb79ddd48 201 case DEV_HEAP_ALLOC_FAIL:
leothedragon 0:8f0bb79ddd48 202 mem_stat_info_ptr->heap_alloc_fail_cnt++;
leothedragon 0:8f0bb79ddd48 203 break;
leothedragon 0:8f0bb79ddd48 204 case DEV_HEAP_FREE:
leothedragon 0:8f0bb79ddd48 205 mem_stat_info_ptr->heap_sector_alloc_cnt--;
leothedragon 0:8f0bb79ddd48 206 mem_stat_info_ptr->heap_sector_allocated_bytes -= size;
leothedragon 0:8f0bb79ddd48 207 break;
leothedragon 0:8f0bb79ddd48 208 }
leothedragon 0:8f0bb79ddd48 209 }
leothedragon 0:8f0bb79ddd48 210 }
leothedragon 0:8f0bb79ddd48 211
leothedragon 0:8f0bb79ddd48 212 static ns_mem_word_size_t convert_allocation_size(ns_mem_book_t *book, ns_mem_block_size_t requested_bytes)
leothedragon 0:8f0bb79ddd48 213 {
leothedragon 0:8f0bb79ddd48 214 if (book->heap_main == 0) {
leothedragon 0:8f0bb79ddd48 215 heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_UNITIALIZED);
leothedragon 0:8f0bb79ddd48 216 } else if (requested_bytes < 1) {
leothedragon 0:8f0bb79ddd48 217 heap_failure(book, NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID);
leothedragon 0:8f0bb79ddd48 218 } else if (requested_bytes > (book->heap_size - 2 * sizeof(ns_mem_word_size_t))) {
leothedragon 0:8f0bb79ddd48 219 heap_failure(book, NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID);
leothedragon 0:8f0bb79ddd48 220 }
leothedragon 0:8f0bb79ddd48 221 return (requested_bytes + sizeof(ns_mem_word_size_t) - 1) / sizeof(ns_mem_word_size_t);
leothedragon 0:8f0bb79ddd48 222 }
leothedragon 0:8f0bb79ddd48 223
leothedragon 0:8f0bb79ddd48 224 // Checks that block length indicators are valid
leothedragon 0:8f0bb79ddd48 225 // Block has format: Size of data area [1 word] | data area [abs(size) words]| Size of data area [1 word]
leothedragon 0:8f0bb79ddd48 226 // If Size is negative it means area is unallocated
leothedragon 0:8f0bb79ddd48 227 static int8_t ns_mem_block_validate(ns_mem_word_size_t *block_start)
leothedragon 0:8f0bb79ddd48 228 {
leothedragon 0:8f0bb79ddd48 229 int8_t ret_val = -1;
leothedragon 0:8f0bb79ddd48 230 ns_mem_word_size_t *end = block_start;
leothedragon 0:8f0bb79ddd48 231 ns_mem_word_size_t size_start = *end;
leothedragon 0:8f0bb79ddd48 232 end += (1 + abs(size_start));
leothedragon 0:8f0bb79ddd48 233 if (size_start != 0 && size_start == *end) {
leothedragon 0:8f0bb79ddd48 234 ret_val = 0;
leothedragon 0:8f0bb79ddd48 235 }
leothedragon 0:8f0bb79ddd48 236 return ret_val;
leothedragon 0:8f0bb79ddd48 237 }
leothedragon 0:8f0bb79ddd48 238 #endif
leothedragon 0:8f0bb79ddd48 239
leothedragon 0:8f0bb79ddd48 240 // For direction, use 1 for direction up and -1 for down
leothedragon 0:8f0bb79ddd48 241 static void *ns_mem_internal_alloc(ns_mem_book_t *book, const ns_mem_block_size_t alloc_size, int direction)
leothedragon 0:8f0bb79ddd48 242 {
leothedragon 0:8f0bb79ddd48 243 #ifndef STANDARD_MALLOC
leothedragon 0:8f0bb79ddd48 244 if (!book) {
leothedragon 0:8f0bb79ddd48 245 /* We can not do anything except return NULL because we can't find book
leothedragon 0:8f0bb79ddd48 246 keeping block */
leothedragon 0:8f0bb79ddd48 247 return NULL;
leothedragon 0:8f0bb79ddd48 248 }
leothedragon 0:8f0bb79ddd48 249
leothedragon 0:8f0bb79ddd48 250 if (book->mem_stat_info_ptr && direction == 1) {
leothedragon 0:8f0bb79ddd48 251 if (book->mem_stat_info_ptr->heap_sector_allocated_bytes > book->temporary_alloc_heap_limit) {
leothedragon 0:8f0bb79ddd48 252 /* Not enough heap for temporary memory allocation */
leothedragon 0:8f0bb79ddd48 253 dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0);
leothedragon 0:8f0bb79ddd48 254 return NULL;
leothedragon 0:8f0bb79ddd48 255 }
leothedragon 0:8f0bb79ddd48 256 }
leothedragon 0:8f0bb79ddd48 257
leothedragon 0:8f0bb79ddd48 258 ns_mem_word_size_t *block_ptr = NULL;
leothedragon 0:8f0bb79ddd48 259
leothedragon 0:8f0bb79ddd48 260 platform_enter_critical();
leothedragon 0:8f0bb79ddd48 261
leothedragon 0:8f0bb79ddd48 262 ns_mem_word_size_t data_size = convert_allocation_size(book, alloc_size);
leothedragon 0:8f0bb79ddd48 263 if (!data_size) {
leothedragon 0:8f0bb79ddd48 264 goto done;
leothedragon 0:8f0bb79ddd48 265 }
leothedragon 0:8f0bb79ddd48 266
leothedragon 0:8f0bb79ddd48 267 // ns_list_foreach, either forwards or backwards, result to ptr
leothedragon 0:8f0bb79ddd48 268 for (hole_t *cur_hole = direction > 0 ? ns_list_get_first(&book->holes_list)
leothedragon 0:8f0bb79ddd48 269 : ns_list_get_last(&book->holes_list);
leothedragon 0:8f0bb79ddd48 270 cur_hole;
leothedragon 0:8f0bb79ddd48 271 cur_hole = direction > 0 ? ns_list_get_next(&book->holes_list, cur_hole)
leothedragon 0:8f0bb79ddd48 272 : ns_list_get_previous(&book->holes_list, cur_hole)
leothedragon 0:8f0bb79ddd48 273 ) {
leothedragon 0:8f0bb79ddd48 274 ns_mem_word_size_t *p = block_start_from_hole(cur_hole);
leothedragon 0:8f0bb79ddd48 275 if (ns_mem_block_validate(p) != 0 || *p >= 0) {
leothedragon 0:8f0bb79ddd48 276 //Validation failed, or this supposed hole has positive (allocated) size
leothedragon 0:8f0bb79ddd48 277 heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
leothedragon 0:8f0bb79ddd48 278 break;
leothedragon 0:8f0bb79ddd48 279 }
leothedragon 0:8f0bb79ddd48 280 if (-*p >= data_size) {
leothedragon 0:8f0bb79ddd48 281 // Found a big enough block
leothedragon 0:8f0bb79ddd48 282 block_ptr = p;
leothedragon 0:8f0bb79ddd48 283 break;
leothedragon 0:8f0bb79ddd48 284 }
leothedragon 0:8f0bb79ddd48 285 }
leothedragon 0:8f0bb79ddd48 286
leothedragon 0:8f0bb79ddd48 287 if (!block_ptr) {
leothedragon 0:8f0bb79ddd48 288 goto done;
leothedragon 0:8f0bb79ddd48 289 }
leothedragon 0:8f0bb79ddd48 290
leothedragon 0:8f0bb79ddd48 291 // Separate declaration from initialization to keep IAR happy as the gotos skip this block.
leothedragon 0:8f0bb79ddd48 292 ns_mem_word_size_t block_data_size;
leothedragon 0:8f0bb79ddd48 293 block_data_size = -*block_ptr;
leothedragon 0:8f0bb79ddd48 294 if (block_data_size >= (data_size + 2 + HOLE_T_SIZE)) {
leothedragon 0:8f0bb79ddd48 295 ns_mem_word_size_t hole_size = block_data_size - data_size - 2;
leothedragon 0:8f0bb79ddd48 296 ns_mem_word_size_t *hole_ptr;
leothedragon 0:8f0bb79ddd48 297 //There is enough room for a new hole so create it first
leothedragon 0:8f0bb79ddd48 298 if (direction > 0) {
leothedragon 0:8f0bb79ddd48 299 hole_ptr = block_ptr + 1 + data_size + 1;
leothedragon 0:8f0bb79ddd48 300 // Hole will be left at end of area.
leothedragon 0:8f0bb79ddd48 301 // Would like to just replace this block_ptr with new descriptor, but
leothedragon 0:8f0bb79ddd48 302 // they could overlap, so ns_list_replace might fail
leothedragon 0:8f0bb79ddd48 303 //ns_list_replace(&holes_list, block_ptr, hole_from_block_start(hole_ptr));
leothedragon 0:8f0bb79ddd48 304 hole_t *before = ns_list_get_previous(&book->holes_list, hole_from_block_start(block_ptr));
leothedragon 0:8f0bb79ddd48 305 ns_list_remove(&book->holes_list, hole_from_block_start(block_ptr));
leothedragon 0:8f0bb79ddd48 306 if (before) {
leothedragon 0:8f0bb79ddd48 307 ns_list_add_after(&book->holes_list, before, hole_from_block_start(hole_ptr));
leothedragon 0:8f0bb79ddd48 308 } else {
leothedragon 0:8f0bb79ddd48 309 ns_list_add_to_start(&book->holes_list, hole_from_block_start(hole_ptr));
leothedragon 0:8f0bb79ddd48 310 }
leothedragon 0:8f0bb79ddd48 311 } else {
leothedragon 0:8f0bb79ddd48 312 hole_ptr = block_ptr;
leothedragon 0:8f0bb79ddd48 313 // Hole remains at start of area - keep existing descriptor in place.
leothedragon 0:8f0bb79ddd48 314 block_ptr += 1 + hole_size + 1;
leothedragon 0:8f0bb79ddd48 315 }
leothedragon 0:8f0bb79ddd48 316
leothedragon 0:8f0bb79ddd48 317 hole_ptr[0] = -hole_size;
leothedragon 0:8f0bb79ddd48 318 hole_ptr[1 + hole_size] = -hole_size;
leothedragon 0:8f0bb79ddd48 319 } else {
leothedragon 0:8f0bb79ddd48 320 // Not enough room for a left-over hole, so use the whole block
leothedragon 0:8f0bb79ddd48 321 data_size = block_data_size;
leothedragon 0:8f0bb79ddd48 322 ns_list_remove(&book->holes_list, hole_from_block_start(block_ptr));
leothedragon 0:8f0bb79ddd48 323 }
leothedragon 0:8f0bb79ddd48 324 block_ptr[0] = data_size;
leothedragon 0:8f0bb79ddd48 325 block_ptr[1 + data_size] = data_size;
leothedragon 0:8f0bb79ddd48 326
leothedragon 0:8f0bb79ddd48 327 done:
leothedragon 0:8f0bb79ddd48 328 if (book->mem_stat_info_ptr) {
leothedragon 0:8f0bb79ddd48 329 if (block_ptr) {
leothedragon 0:8f0bb79ddd48 330 //Update Allocate OK
leothedragon 0:8f0bb79ddd48 331 dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_OK, (data_size + 2) * sizeof(ns_mem_word_size_t));
leothedragon 0:8f0bb79ddd48 332
leothedragon 0:8f0bb79ddd48 333 } else {
leothedragon 0:8f0bb79ddd48 334 //Update Allocate Fail, second parameter is used for stats
leothedragon 0:8f0bb79ddd48 335 dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0);
leothedragon 0:8f0bb79ddd48 336 }
leothedragon 0:8f0bb79ddd48 337 }
leothedragon 0:8f0bb79ddd48 338 platform_exit_critical();
leothedragon 0:8f0bb79ddd48 339
leothedragon 0:8f0bb79ddd48 340 return block_ptr ? block_ptr + 1 : NULL;
leothedragon 0:8f0bb79ddd48 341 #else
leothedragon 0:8f0bb79ddd48 342 void *retval = NULL;
leothedragon 0:8f0bb79ddd48 343 if (alloc_size) {
leothedragon 0:8f0bb79ddd48 344 platform_enter_critical();
leothedragon 0:8f0bb79ddd48 345 retval = malloc(alloc_size);
leothedragon 0:8f0bb79ddd48 346 platform_exit_critical();
leothedragon 0:8f0bb79ddd48 347 }
leothedragon 0:8f0bb79ddd48 348 return retval;
leothedragon 0:8f0bb79ddd48 349 #endif
leothedragon 0:8f0bb79ddd48 350 }
leothedragon 0:8f0bb79ddd48 351
leothedragon 0:8f0bb79ddd48 352 void *ns_mem_alloc(ns_mem_book_t *heap, ns_mem_block_size_t alloc_size)
leothedragon 0:8f0bb79ddd48 353 {
leothedragon 0:8f0bb79ddd48 354 return ns_mem_internal_alloc(heap, alloc_size, -1);
leothedragon 0:8f0bb79ddd48 355 }
leothedragon 0:8f0bb79ddd48 356
leothedragon 0:8f0bb79ddd48 357 void *ns_mem_temporary_alloc(ns_mem_book_t *heap, ns_mem_block_size_t alloc_size)
leothedragon 0:8f0bb79ddd48 358 {
leothedragon 0:8f0bb79ddd48 359 return ns_mem_internal_alloc(heap, alloc_size, 1);
leothedragon 0:8f0bb79ddd48 360 }
leothedragon 0:8f0bb79ddd48 361
leothedragon 0:8f0bb79ddd48 362 void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size)
leothedragon 0:8f0bb79ddd48 363 {
leothedragon 0:8f0bb79ddd48 364 return ns_mem_alloc(default_book, alloc_size);
leothedragon 0:8f0bb79ddd48 365 }
leothedragon 0:8f0bb79ddd48 366
leothedragon 0:8f0bb79ddd48 367 void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size)
leothedragon 0:8f0bb79ddd48 368 {
leothedragon 0:8f0bb79ddd48 369 return ns_mem_temporary_alloc(default_book, alloc_size);
leothedragon 0:8f0bb79ddd48 370 }
leothedragon 0:8f0bb79ddd48 371
leothedragon 0:8f0bb79ddd48 372 #ifndef STANDARD_MALLOC
leothedragon 0:8f0bb79ddd48 373 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)
leothedragon 0:8f0bb79ddd48 374 {
leothedragon 0:8f0bb79ddd48 375 // Theory of operation: Block is always in form | Len | Data | Len |
leothedragon 0:8f0bb79ddd48 376 // So we need to check length of previous (if current not heap start)
leothedragon 0:8f0bb79ddd48 377 // and next (if current not heap end) blocks. Negative length means
leothedragon 0:8f0bb79ddd48 378 // free memory so we can merge freed block with those.
leothedragon 0:8f0bb79ddd48 379
leothedragon 0:8f0bb79ddd48 380 hole_t *existing_start = NULL;
leothedragon 0:8f0bb79ddd48 381 hole_t *existing_end = NULL;
leothedragon 0:8f0bb79ddd48 382 ns_mem_word_size_t *start = cur_block;
leothedragon 0:8f0bb79ddd48 383 ns_mem_word_size_t *end = cur_block + data_size + 1;
leothedragon 0:8f0bb79ddd48 384 //invalidate current block
leothedragon 0:8f0bb79ddd48 385 *start = -data_size;
leothedragon 0:8f0bb79ddd48 386 *end = -data_size;
leothedragon 0:8f0bb79ddd48 387 ns_mem_word_size_t merged_data_size = data_size;
leothedragon 0:8f0bb79ddd48 388
leothedragon 0:8f0bb79ddd48 389 if (start != book->heap_main) {
leothedragon 0:8f0bb79ddd48 390 if (*(start - 1) < 0) {
leothedragon 0:8f0bb79ddd48 391 ns_mem_word_size_t *block_end = start - 1;
leothedragon 0:8f0bb79ddd48 392 ns_mem_word_size_t block_size = 1 + (-*block_end) + 1;
leothedragon 0:8f0bb79ddd48 393 merged_data_size += block_size;
leothedragon 0:8f0bb79ddd48 394 start -= block_size;
leothedragon 0:8f0bb79ddd48 395 if (*start != *block_end) {
leothedragon 0:8f0bb79ddd48 396 heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
leothedragon 0:8f0bb79ddd48 397 }
leothedragon 0:8f0bb79ddd48 398 if (block_size >= 1 + HOLE_T_SIZE + 1) {
leothedragon 0:8f0bb79ddd48 399 existing_start = hole_from_block_start(start);
leothedragon 0:8f0bb79ddd48 400 }
leothedragon 0:8f0bb79ddd48 401 }
leothedragon 0:8f0bb79ddd48 402 }
leothedragon 0:8f0bb79ddd48 403
leothedragon 0:8f0bb79ddd48 404 if (end != book->heap_main_end) {
leothedragon 0:8f0bb79ddd48 405 if (*(end + 1) < 0) {
leothedragon 0:8f0bb79ddd48 406 ns_mem_word_size_t *block_start = end + 1;
leothedragon 0:8f0bb79ddd48 407 ns_mem_word_size_t block_size = 1 + (-*block_start) + 1;
leothedragon 0:8f0bb79ddd48 408 merged_data_size += block_size;
leothedragon 0:8f0bb79ddd48 409 end += block_size;
leothedragon 0:8f0bb79ddd48 410 if (*end != *block_start) {
leothedragon 0:8f0bb79ddd48 411 heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
leothedragon 0:8f0bb79ddd48 412 }
leothedragon 0:8f0bb79ddd48 413 if (block_size >= 1 + HOLE_T_SIZE + 1) {
leothedragon 0:8f0bb79ddd48 414 existing_end = hole_from_block_start(block_start);
leothedragon 0:8f0bb79ddd48 415 }
leothedragon 0:8f0bb79ddd48 416 }
leothedragon 0:8f0bb79ddd48 417 }
leothedragon 0:8f0bb79ddd48 418
leothedragon 0:8f0bb79ddd48 419 hole_t *to_add = hole_from_block_start(start);
leothedragon 0:8f0bb79ddd48 420 hole_t *before = NULL;
leothedragon 0:8f0bb79ddd48 421 if (existing_end) {
leothedragon 0:8f0bb79ddd48 422 // Extending hole described by "existing_end" downwards.
leothedragon 0:8f0bb79ddd48 423 // Will replace with descriptor at bottom of merged block.
leothedragon 0:8f0bb79ddd48 424 // (Can't use ns_list_replace, because of danger of overlap)
leothedragon 0:8f0bb79ddd48 425 // Optimisation - note our position for insertion below.
leothedragon 0:8f0bb79ddd48 426 before = ns_list_get_next(&book->holes_list, existing_end);
leothedragon 0:8f0bb79ddd48 427 ns_list_remove(&book->holes_list, existing_end);
leothedragon 0:8f0bb79ddd48 428 }
leothedragon 0:8f0bb79ddd48 429 if (existing_start) {
leothedragon 0:8f0bb79ddd48 430 // Extending hole described by "existing_start" upwards.
leothedragon 0:8f0bb79ddd48 431 // No need to modify that descriptor - it remains at the bottom
leothedragon 0:8f0bb79ddd48 432 // of the merged block to describe it.
leothedragon 0:8f0bb79ddd48 433 } else {
leothedragon 0:8f0bb79ddd48 434 // Didn't find adjacent descriptors, but may still
leothedragon 0:8f0bb79ddd48 435 // be merging with small blocks without descriptors.
leothedragon 0:8f0bb79ddd48 436 if (merged_data_size >= HOLE_T_SIZE) {
leothedragon 0:8f0bb79ddd48 437 // Locate hole position in list, if we don't already know
leothedragon 0:8f0bb79ddd48 438 // from merging with the block above.
leothedragon 0:8f0bb79ddd48 439 if (!existing_end) {
leothedragon 0:8f0bb79ddd48 440 ns_list_foreach(hole_t, ptr, &book->holes_list) {
leothedragon 0:8f0bb79ddd48 441 if (ptr > to_add) {
leothedragon 0:8f0bb79ddd48 442 before = ptr;
leothedragon 0:8f0bb79ddd48 443 break;
leothedragon 0:8f0bb79ddd48 444 }
leothedragon 0:8f0bb79ddd48 445 }
leothedragon 0:8f0bb79ddd48 446 }
leothedragon 0:8f0bb79ddd48 447 if (before) {
leothedragon 0:8f0bb79ddd48 448 ns_list_add_before(&book->holes_list, before, to_add);
leothedragon 0:8f0bb79ddd48 449 } else {
leothedragon 0:8f0bb79ddd48 450 ns_list_add_to_end(&book->holes_list, to_add);
leothedragon 0:8f0bb79ddd48 451 }
leothedragon 0:8f0bb79ddd48 452
leothedragon 0:8f0bb79ddd48 453 }
leothedragon 0:8f0bb79ddd48 454 }
leothedragon 0:8f0bb79ddd48 455 *start = -merged_data_size;
leothedragon 0:8f0bb79ddd48 456 *end = -merged_data_size;
leothedragon 0:8f0bb79ddd48 457 }
leothedragon 0:8f0bb79ddd48 458 #endif
leothedragon 0:8f0bb79ddd48 459
leothedragon 0:8f0bb79ddd48 460 void ns_mem_free(ns_mem_book_t *book, void *block)
leothedragon 0:8f0bb79ddd48 461 {
leothedragon 0:8f0bb79ddd48 462 #ifndef STANDARD_MALLOC
leothedragon 0:8f0bb79ddd48 463
leothedragon 0:8f0bb79ddd48 464 if (!block) {
leothedragon 0:8f0bb79ddd48 465 return;
leothedragon 0:8f0bb79ddd48 466 }
leothedragon 0:8f0bb79ddd48 467
leothedragon 0:8f0bb79ddd48 468 ns_mem_word_size_t *ptr = block;
leothedragon 0:8f0bb79ddd48 469 ns_mem_word_size_t size;
leothedragon 0:8f0bb79ddd48 470
leothedragon 0:8f0bb79ddd48 471 platform_enter_critical();
leothedragon 0:8f0bb79ddd48 472 ptr --;
leothedragon 0:8f0bb79ddd48 473 //Read Current Size
leothedragon 0:8f0bb79ddd48 474 size = *ptr;
leothedragon 0:8f0bb79ddd48 475 if (ptr < book->heap_main || ptr >= book->heap_main_end) {
leothedragon 0:8f0bb79ddd48 476 heap_failure(book, NS_DYN_MEM_POINTER_NOT_VALID);
leothedragon 0:8f0bb79ddd48 477 } else if ((ptr + size) >= book->heap_main_end) {
leothedragon 0:8f0bb79ddd48 478 heap_failure(book, NS_DYN_MEM_POINTER_NOT_VALID);
leothedragon 0:8f0bb79ddd48 479 } else if (size < 0) {
leothedragon 0:8f0bb79ddd48 480 heap_failure(book, NS_DYN_MEM_DOUBLE_FREE);
leothedragon 0:8f0bb79ddd48 481 } else {
leothedragon 0:8f0bb79ddd48 482 if (ns_mem_block_validate(ptr) != 0) {
leothedragon 0:8f0bb79ddd48 483 heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
leothedragon 0:8f0bb79ddd48 484 } else {
leothedragon 0:8f0bb79ddd48 485 ns_mem_free_and_merge_with_adjacent_blocks(book, ptr, size);
leothedragon 0:8f0bb79ddd48 486 if (book->mem_stat_info_ptr) {
leothedragon 0:8f0bb79ddd48 487 //Update Free Counter
leothedragon 0:8f0bb79ddd48 488 dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_FREE, (size + 2) * sizeof(ns_mem_word_size_t));
leothedragon 0:8f0bb79ddd48 489 }
leothedragon 0:8f0bb79ddd48 490 }
leothedragon 0:8f0bb79ddd48 491 }
leothedragon 0:8f0bb79ddd48 492 platform_exit_critical();
leothedragon 0:8f0bb79ddd48 493 #else
leothedragon 0:8f0bb79ddd48 494 platform_enter_critical();
leothedragon 0:8f0bb79ddd48 495 free(block);
leothedragon 0:8f0bb79ddd48 496 platform_exit_critical();
leothedragon 0:8f0bb79ddd48 497 #endif
leothedragon 0:8f0bb79ddd48 498 }
leothedragon 0:8f0bb79ddd48 499
leothedragon 0:8f0bb79ddd48 500 void ns_dyn_mem_free(void *block)
leothedragon 0:8f0bb79ddd48 501 {
leothedragon 0:8f0bb79ddd48 502 ns_mem_free(default_book, block);
leothedragon 0:8f0bb79ddd48 503 }