Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
features/frameworks/nanostack-libservice/source/nsdynmemLIB/nsdynmemLIB.c@0:5b88d5760320, 2019-12-17 (annotated)
- Committer:
- kenjiArai
- Date:
- Tue Dec 17 23:23:45 2019 +0000
- Revision:
- 0:5b88d5760320
mbed-os5 only for TYBLE16
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kenjiArai | 0:5b88d5760320 | 1 | /* |
kenjiArai | 0:5b88d5760320 | 2 | * Copyright (c) 2014-2019 ARM Limited. All rights reserved. |
kenjiArai | 0:5b88d5760320 | 3 | * SPDX-License-Identifier: Apache-2.0 |
kenjiArai | 0:5b88d5760320 | 4 | * Licensed under the Apache License, Version 2.0 (the License); you may |
kenjiArai | 0:5b88d5760320 | 5 | * not use this file except in compliance with the License. |
kenjiArai | 0:5b88d5760320 | 6 | * You may obtain a copy of the License at |
kenjiArai | 0:5b88d5760320 | 7 | * |
kenjiArai | 0:5b88d5760320 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
kenjiArai | 0:5b88d5760320 | 9 | * |
kenjiArai | 0:5b88d5760320 | 10 | * Unless required by applicable law or agreed to in writing, software |
kenjiArai | 0:5b88d5760320 | 11 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT |
kenjiArai | 0:5b88d5760320 | 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
kenjiArai | 0:5b88d5760320 | 13 | * See the License for the specific language governing permissions and |
kenjiArai | 0:5b88d5760320 | 14 | * limitations under the License. |
kenjiArai | 0:5b88d5760320 | 15 | */ |
kenjiArai | 0:5b88d5760320 | 16 | #include <stdint.h> |
kenjiArai | 0:5b88d5760320 | 17 | #include <string.h> |
kenjiArai | 0:5b88d5760320 | 18 | #include "nsdynmemLIB.h" |
kenjiArai | 0:5b88d5760320 | 19 | #include "platform/arm_hal_interrupt.h" |
kenjiArai | 0:5b88d5760320 | 20 | #include <stdlib.h> |
kenjiArai | 0:5b88d5760320 | 21 | #include "ns_list.h" |
kenjiArai | 0:5b88d5760320 | 22 | |
kenjiArai | 0:5b88d5760320 | 23 | #ifndef STANDARD_MALLOC |
kenjiArai | 0:5b88d5760320 | 24 | typedef enum mem_stat_update_t { |
kenjiArai | 0:5b88d5760320 | 25 | DEV_HEAP_ALLOC_OK, |
kenjiArai | 0:5b88d5760320 | 26 | DEV_HEAP_ALLOC_FAIL, |
kenjiArai | 0:5b88d5760320 | 27 | DEV_HEAP_FREE, |
kenjiArai | 0:5b88d5760320 | 28 | } mem_stat_update_t; |
kenjiArai | 0:5b88d5760320 | 29 | |
kenjiArai | 0:5b88d5760320 | 30 | typedef struct { |
kenjiArai | 0:5b88d5760320 | 31 | ns_list_link_t link; |
kenjiArai | 0:5b88d5760320 | 32 | } hole_t; |
kenjiArai | 0:5b88d5760320 | 33 | |
kenjiArai | 0:5b88d5760320 | 34 | typedef int ns_mem_word_size_t; // internal signed heap block size type |
kenjiArai | 0:5b88d5760320 | 35 | |
kenjiArai | 0:5b88d5760320 | 36 | // Amount of memory regions |
kenjiArai | 0:5b88d5760320 | 37 | #define REGION_COUNT 3 |
kenjiArai | 0:5b88d5760320 | 38 | |
kenjiArai | 0:5b88d5760320 | 39 | /* struct for book keeping variables */ |
kenjiArai | 0:5b88d5760320 | 40 | struct ns_mem_book { |
kenjiArai | 0:5b88d5760320 | 41 | ns_mem_word_size_t *heap_main[REGION_COUNT]; |
kenjiArai | 0:5b88d5760320 | 42 | ns_mem_word_size_t *heap_main_end[REGION_COUNT]; |
kenjiArai | 0:5b88d5760320 | 43 | mem_stat_t *mem_stat_info_ptr; |
kenjiArai | 0:5b88d5760320 | 44 | void (*heap_failure_callback)(heap_fail_t); |
kenjiArai | 0:5b88d5760320 | 45 | NS_LIST_HEAD(hole_t, link) holes_list; |
kenjiArai | 0:5b88d5760320 | 46 | ns_mem_heap_size_t heap_size; |
kenjiArai | 0:5b88d5760320 | 47 | ns_mem_heap_size_t temporary_alloc_heap_limit; /* Amount of reserved heap temporary alloc can't exceed */ |
kenjiArai | 0:5b88d5760320 | 48 | }; |
kenjiArai | 0:5b88d5760320 | 49 | |
kenjiArai | 0:5b88d5760320 | 50 | static ns_mem_book_t *default_book; // heap pointer for original "ns_" API use |
kenjiArai | 0:5b88d5760320 | 51 | |
kenjiArai | 0:5b88d5760320 | 52 | // size of a hole_t in our word units |
kenjiArai | 0:5b88d5760320 | 53 | #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))) |
kenjiArai | 0:5b88d5760320 | 54 | |
kenjiArai | 0:5b88d5760320 | 55 | #define TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD 5 /* temporary allocations must leave 5% of the heap free */ |
kenjiArai | 0:5b88d5760320 | 56 | |
kenjiArai | 0:5b88d5760320 | 57 | static NS_INLINE hole_t *hole_from_block_start(ns_mem_word_size_t *start) |
kenjiArai | 0:5b88d5760320 | 58 | { |
kenjiArai | 0:5b88d5760320 | 59 | return (hole_t *)(start + 1); |
kenjiArai | 0:5b88d5760320 | 60 | } |
kenjiArai | 0:5b88d5760320 | 61 | |
kenjiArai | 0:5b88d5760320 | 62 | static NS_INLINE ns_mem_word_size_t *block_start_from_hole(hole_t *start) |
kenjiArai | 0:5b88d5760320 | 63 | { |
kenjiArai | 0:5b88d5760320 | 64 | return ((ns_mem_word_size_t *)start) - 1; |
kenjiArai | 0:5b88d5760320 | 65 | } |
kenjiArai | 0:5b88d5760320 | 66 | |
kenjiArai | 0:5b88d5760320 | 67 | static void heap_failure(ns_mem_book_t *book, heap_fail_t reason) |
kenjiArai | 0:5b88d5760320 | 68 | { |
kenjiArai | 0:5b88d5760320 | 69 | if (book->heap_failure_callback) { |
kenjiArai | 0:5b88d5760320 | 70 | book->heap_failure_callback(reason); |
kenjiArai | 0:5b88d5760320 | 71 | } |
kenjiArai | 0:5b88d5760320 | 72 | } |
kenjiArai | 0:5b88d5760320 | 73 | |
kenjiArai | 0:5b88d5760320 | 74 | 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) |
kenjiArai | 0:5b88d5760320 | 75 | { |
kenjiArai | 0:5b88d5760320 | 76 | int index; |
kenjiArai | 0:5b88d5760320 | 77 | for (index = 0; index < REGION_COUNT; index++) { |
kenjiArai | 0:5b88d5760320 | 78 | if (book->heap_main[index] != 0) { |
kenjiArai | 0:5b88d5760320 | 79 | if ((block_ptr >= book->heap_main[index]) && |
kenjiArai | 0:5b88d5760320 | 80 | (block_ptr < book->heap_main_end[index]) && |
kenjiArai | 0:5b88d5760320 | 81 | ((block_ptr + size) < book->heap_main_end[index])) { |
kenjiArai | 0:5b88d5760320 | 82 | return index; |
kenjiArai | 0:5b88d5760320 | 83 | } |
kenjiArai | 0:5b88d5760320 | 84 | } |
kenjiArai | 0:5b88d5760320 | 85 | } |
kenjiArai | 0:5b88d5760320 | 86 | |
kenjiArai | 0:5b88d5760320 | 87 | return -1; |
kenjiArai | 0:5b88d5760320 | 88 | } |
kenjiArai | 0:5b88d5760320 | 89 | |
kenjiArai | 0:5b88d5760320 | 90 | 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) |
kenjiArai | 0:5b88d5760320 | 91 | { |
kenjiArai | 0:5b88d5760320 | 92 | for (int i = 1; i < REGION_COUNT; i++) { |
kenjiArai | 0:5b88d5760320 | 93 | if (book->heap_main[i] == 0) { |
kenjiArai | 0:5b88d5760320 | 94 | book->heap_main[i] = region_start_ptr; |
kenjiArai | 0:5b88d5760320 | 95 | book->heap_main_end[i] = book->heap_main[i] + region_size; |
kenjiArai | 0:5b88d5760320 | 96 | return 0; |
kenjiArai | 0:5b88d5760320 | 97 | } |
kenjiArai | 0:5b88d5760320 | 98 | } |
kenjiArai | 0:5b88d5760320 | 99 | |
kenjiArai | 0:5b88d5760320 | 100 | return -1; |
kenjiArai | 0:5b88d5760320 | 101 | } |
kenjiArai | 0:5b88d5760320 | 102 | |
kenjiArai | 0:5b88d5760320 | 103 | |
kenjiArai | 0:5b88d5760320 | 104 | #endif //STANDARD_MALLOC |
kenjiArai | 0:5b88d5760320 | 105 | |
kenjiArai | 0:5b88d5760320 | 106 | void ns_dyn_mem_init(void *heap, ns_mem_heap_size_t h_size, |
kenjiArai | 0:5b88d5760320 | 107 | void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr) |
kenjiArai | 0:5b88d5760320 | 108 | { |
kenjiArai | 0:5b88d5760320 | 109 | default_book = ns_mem_init(heap, h_size, passed_fptr, info_ptr); |
kenjiArai | 0:5b88d5760320 | 110 | } |
kenjiArai | 0:5b88d5760320 | 111 | |
kenjiArai | 0:5b88d5760320 | 112 | int ns_dyn_mem_region_add(void *region_ptr, ns_mem_heap_size_t region_size) |
kenjiArai | 0:5b88d5760320 | 113 | { |
kenjiArai | 0:5b88d5760320 | 114 | return ns_mem_region_add(default_book, region_ptr, region_size); |
kenjiArai | 0:5b88d5760320 | 115 | } |
kenjiArai | 0:5b88d5760320 | 116 | |
kenjiArai | 0:5b88d5760320 | 117 | const mem_stat_t *ns_dyn_mem_get_mem_stat(void) |
kenjiArai | 0:5b88d5760320 | 118 | { |
kenjiArai | 0:5b88d5760320 | 119 | #ifndef STANDARD_MALLOC |
kenjiArai | 0:5b88d5760320 | 120 | return ns_mem_get_mem_stat(default_book); |
kenjiArai | 0:5b88d5760320 | 121 | #else |
kenjiArai | 0:5b88d5760320 | 122 | return NULL; |
kenjiArai | 0:5b88d5760320 | 123 | #endif |
kenjiArai | 0:5b88d5760320 | 124 | } |
kenjiArai | 0:5b88d5760320 | 125 | |
kenjiArai | 0:5b88d5760320 | 126 | ns_mem_book_t *ns_mem_init(void *heap, ns_mem_heap_size_t h_size, |
kenjiArai | 0:5b88d5760320 | 127 | void (*passed_fptr)(heap_fail_t), |
kenjiArai | 0:5b88d5760320 | 128 | mem_stat_t *info_ptr) |
kenjiArai | 0:5b88d5760320 | 129 | { |
kenjiArai | 0:5b88d5760320 | 130 | #ifndef STANDARD_MALLOC |
kenjiArai | 0:5b88d5760320 | 131 | ns_mem_book_t *book; |
kenjiArai | 0:5b88d5760320 | 132 | |
kenjiArai | 0:5b88d5760320 | 133 | ns_mem_word_size_t *ptr; |
kenjiArai | 0:5b88d5760320 | 134 | ns_mem_word_size_t temp_int; |
kenjiArai | 0:5b88d5760320 | 135 | /* Do memory alignment */ |
kenjiArai | 0:5b88d5760320 | 136 | temp_int = ((uintptr_t)heap % sizeof(ns_mem_word_size_t)); |
kenjiArai | 0:5b88d5760320 | 137 | if (temp_int) { |
kenjiArai | 0:5b88d5760320 | 138 | heap = (uint8_t *) heap + (sizeof(ns_mem_word_size_t) - temp_int); |
kenjiArai | 0:5b88d5760320 | 139 | h_size -= (sizeof(ns_mem_word_size_t) - temp_int); |
kenjiArai | 0:5b88d5760320 | 140 | } |
kenjiArai | 0:5b88d5760320 | 141 | |
kenjiArai | 0:5b88d5760320 | 142 | /* Make correction for total length also */ |
kenjiArai | 0:5b88d5760320 | 143 | temp_int = (h_size % sizeof(ns_mem_word_size_t)); |
kenjiArai | 0:5b88d5760320 | 144 | if (temp_int) { |
kenjiArai | 0:5b88d5760320 | 145 | h_size -= (sizeof(ns_mem_word_size_t) - temp_int); |
kenjiArai | 0:5b88d5760320 | 146 | } |
kenjiArai | 0:5b88d5760320 | 147 | |
kenjiArai | 0:5b88d5760320 | 148 | book = heap; |
kenjiArai | 0:5b88d5760320 | 149 | memset(book->heap_main, 0, REGION_COUNT * sizeof(ns_mem_word_size_t *)); |
kenjiArai | 0:5b88d5760320 | 150 | memset(book->heap_main_end, 0, REGION_COUNT * sizeof(ns_mem_word_size_t *)); |
kenjiArai | 0:5b88d5760320 | 151 | |
kenjiArai | 0:5b88d5760320 | 152 | book->heap_main[0] = (ns_mem_word_size_t *) & (book[1]); // SET Heap Pointer |
kenjiArai | 0:5b88d5760320 | 153 | book->heap_size = h_size - sizeof(ns_mem_book_t); //Set Heap Size |
kenjiArai | 0:5b88d5760320 | 154 | temp_int = (book->heap_size / sizeof(ns_mem_word_size_t)); |
kenjiArai | 0:5b88d5760320 | 155 | temp_int -= 2; |
kenjiArai | 0:5b88d5760320 | 156 | ptr = book->heap_main[0]; |
kenjiArai | 0:5b88d5760320 | 157 | *ptr = -(temp_int); |
kenjiArai | 0:5b88d5760320 | 158 | ptr += (temp_int + 1); |
kenjiArai | 0:5b88d5760320 | 159 | *ptr = -(temp_int); |
kenjiArai | 0:5b88d5760320 | 160 | book->heap_main_end[0] = ptr; |
kenjiArai | 0:5b88d5760320 | 161 | |
kenjiArai | 0:5b88d5760320 | 162 | ns_list_init(&book->holes_list); |
kenjiArai | 0:5b88d5760320 | 163 | ns_list_add_to_start(&book->holes_list, hole_from_block_start(book->heap_main[0])); |
kenjiArai | 0:5b88d5760320 | 164 | |
kenjiArai | 0:5b88d5760320 | 165 | book->mem_stat_info_ptr = info_ptr; |
kenjiArai | 0:5b88d5760320 | 166 | //RESET Memory by Hea Len |
kenjiArai | 0:5b88d5760320 | 167 | if (info_ptr) { |
kenjiArai | 0:5b88d5760320 | 168 | memset(book->mem_stat_info_ptr, 0, sizeof(mem_stat_t)); |
kenjiArai | 0:5b88d5760320 | 169 | book->mem_stat_info_ptr->heap_sector_size = book->heap_size; |
kenjiArai | 0:5b88d5760320 | 170 | } |
kenjiArai | 0:5b88d5760320 | 171 | book->temporary_alloc_heap_limit = book->heap_size / 100 * (100 - TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD); |
kenjiArai | 0:5b88d5760320 | 172 | #endif |
kenjiArai | 0:5b88d5760320 | 173 | //There really is no support to standard malloc in this library anymore |
kenjiArai | 0:5b88d5760320 | 174 | book->heap_failure_callback = passed_fptr; |
kenjiArai | 0:5b88d5760320 | 175 | |
kenjiArai | 0:5b88d5760320 | 176 | return book; |
kenjiArai | 0:5b88d5760320 | 177 | } |
kenjiArai | 0:5b88d5760320 | 178 | |
kenjiArai | 0:5b88d5760320 | 179 | int ns_mem_region_add(ns_mem_book_t *book, void *region_ptr, ns_mem_heap_size_t region_size) |
kenjiArai | 0:5b88d5760320 | 180 | { |
kenjiArai | 0:5b88d5760320 | 181 | #ifndef STANDARD_MALLOC |
kenjiArai | 0:5b88d5760320 | 182 | if (!book || !region_ptr || region_size < 3 * sizeof(ns_mem_word_size_t)) { |
kenjiArai | 0:5b88d5760320 | 183 | return -1; |
kenjiArai | 0:5b88d5760320 | 184 | } |
kenjiArai | 0:5b88d5760320 | 185 | |
kenjiArai | 0:5b88d5760320 | 186 | ns_mem_word_size_t *block_ptr; |
kenjiArai | 0:5b88d5760320 | 187 | ns_mem_word_size_t temp_int; |
kenjiArai | 0:5b88d5760320 | 188 | |
kenjiArai | 0:5b88d5760320 | 189 | /* Do memory alignment */ |
kenjiArai | 0:5b88d5760320 | 190 | temp_int = ((uintptr_t)region_ptr % sizeof(ns_mem_word_size_t)); |
kenjiArai | 0:5b88d5760320 | 191 | if (temp_int) { |
kenjiArai | 0:5b88d5760320 | 192 | region_ptr = (uint8_t *) region_ptr + (sizeof(ns_mem_word_size_t) - temp_int); |
kenjiArai | 0:5b88d5760320 | 193 | region_size -= (sizeof(ns_mem_word_size_t) - temp_int); |
kenjiArai | 0:5b88d5760320 | 194 | } |
kenjiArai | 0:5b88d5760320 | 195 | |
kenjiArai | 0:5b88d5760320 | 196 | /* Make correction for total length */ |
kenjiArai | 0:5b88d5760320 | 197 | temp_int = (region_size % sizeof(ns_mem_word_size_t)); |
kenjiArai | 0:5b88d5760320 | 198 | if (temp_int) { |
kenjiArai | 0:5b88d5760320 | 199 | region_size -= (sizeof(ns_mem_word_size_t) - temp_int); |
kenjiArai | 0:5b88d5760320 | 200 | } |
kenjiArai | 0:5b88d5760320 | 201 | |
kenjiArai | 0:5b88d5760320 | 202 | // Create hole from new heap memory |
kenjiArai | 0:5b88d5760320 | 203 | temp_int = (region_size / sizeof(ns_mem_word_size_t)); |
kenjiArai | 0:5b88d5760320 | 204 | temp_int -= 2; |
kenjiArai | 0:5b88d5760320 | 205 | block_ptr = region_ptr; |
kenjiArai | 0:5b88d5760320 | 206 | *block_ptr = -(temp_int); |
kenjiArai | 0:5b88d5760320 | 207 | block_ptr += (temp_int + 1); // now block_ptr points to end of block |
kenjiArai | 0:5b88d5760320 | 208 | *block_ptr = -(temp_int); |
kenjiArai | 0:5b88d5760320 | 209 | |
kenjiArai | 0:5b88d5760320 | 210 | // find place for the new hole from the holes list |
kenjiArai | 0:5b88d5760320 | 211 | hole_t *hole_to_add = hole_from_block_start(region_ptr); |
kenjiArai | 0:5b88d5760320 | 212 | hole_t *previous_hole = NULL; |
kenjiArai | 0:5b88d5760320 | 213 | ns_list_foreach(hole_t, hole_in_list_ptr, &book->holes_list) { |
kenjiArai | 0:5b88d5760320 | 214 | if (hole_in_list_ptr < hole_to_add) { |
kenjiArai | 0:5b88d5760320 | 215 | previous_hole = hole_in_list_ptr; |
kenjiArai | 0:5b88d5760320 | 216 | } else if (hole_in_list_ptr == hole_to_add) { |
kenjiArai | 0:5b88d5760320 | 217 | // trying to add memory block that is already in the list! |
kenjiArai | 0:5b88d5760320 | 218 | return -2; |
kenjiArai | 0:5b88d5760320 | 219 | } |
kenjiArai | 0:5b88d5760320 | 220 | } |
kenjiArai | 0:5b88d5760320 | 221 | |
kenjiArai | 0:5b88d5760320 | 222 | // save region |
kenjiArai | 0:5b88d5760320 | 223 | if (ns_dyn_mem_region_save(book, region_ptr, (region_size / (sizeof(ns_mem_word_size_t))) - 1) != 0) { |
kenjiArai | 0:5b88d5760320 | 224 | return -3; |
kenjiArai | 0:5b88d5760320 | 225 | } |
kenjiArai | 0:5b88d5760320 | 226 | |
kenjiArai | 0:5b88d5760320 | 227 | // Add new hole to the list |
kenjiArai | 0:5b88d5760320 | 228 | if (previous_hole) { |
kenjiArai | 0:5b88d5760320 | 229 | ns_list_add_after(&book->holes_list, previous_hole, hole_to_add); |
kenjiArai | 0:5b88d5760320 | 230 | } else { |
kenjiArai | 0:5b88d5760320 | 231 | ns_list_add_to_start(&book->holes_list, hole_to_add); |
kenjiArai | 0:5b88d5760320 | 232 | } |
kenjiArai | 0:5b88d5760320 | 233 | |
kenjiArai | 0:5b88d5760320 | 234 | // adjust total heap size with new hole |
kenjiArai | 0:5b88d5760320 | 235 | book->heap_size += region_size; |
kenjiArai | 0:5b88d5760320 | 236 | |
kenjiArai | 0:5b88d5760320 | 237 | if (book->mem_stat_info_ptr) { |
kenjiArai | 0:5b88d5760320 | 238 | book->mem_stat_info_ptr->heap_sector_size = book->heap_size; |
kenjiArai | 0:5b88d5760320 | 239 | } |
kenjiArai | 0:5b88d5760320 | 240 | |
kenjiArai | 0:5b88d5760320 | 241 | // adjust temporary allocation limits to match new heap |
kenjiArai | 0:5b88d5760320 | 242 | book->temporary_alloc_heap_limit = book->heap_size / 100 * (100 - TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD); |
kenjiArai | 0:5b88d5760320 | 243 | |
kenjiArai | 0:5b88d5760320 | 244 | return 0; |
kenjiArai | 0:5b88d5760320 | 245 | #else |
kenjiArai | 0:5b88d5760320 | 246 | (void) book; |
kenjiArai | 0:5b88d5760320 | 247 | (void) region_ptr; |
kenjiArai | 0:5b88d5760320 | 248 | (void) region_size; |
kenjiArai | 0:5b88d5760320 | 249 | |
kenjiArai | 0:5b88d5760320 | 250 | return -1; |
kenjiArai | 0:5b88d5760320 | 251 | #endif |
kenjiArai | 0:5b88d5760320 | 252 | } |
kenjiArai | 0:5b88d5760320 | 253 | |
kenjiArai | 0:5b88d5760320 | 254 | const mem_stat_t *ns_mem_get_mem_stat(ns_mem_book_t *heap) |
kenjiArai | 0:5b88d5760320 | 255 | { |
kenjiArai | 0:5b88d5760320 | 256 | #ifndef STANDARD_MALLOC |
kenjiArai | 0:5b88d5760320 | 257 | return heap->mem_stat_info_ptr; |
kenjiArai | 0:5b88d5760320 | 258 | #else |
kenjiArai | 0:5b88d5760320 | 259 | return NULL; |
kenjiArai | 0:5b88d5760320 | 260 | #endif |
kenjiArai | 0:5b88d5760320 | 261 | } |
kenjiArai | 0:5b88d5760320 | 262 | |
kenjiArai | 0:5b88d5760320 | 263 | 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) |
kenjiArai | 0:5b88d5760320 | 264 | { |
kenjiArai | 0:5b88d5760320 | 265 | #ifndef STANDARD_MALLOC |
kenjiArai | 0:5b88d5760320 | 266 | ns_mem_heap_size_t heap_limit = 0; |
kenjiArai | 0:5b88d5760320 | 267 | |
kenjiArai | 0:5b88d5760320 | 268 | if (!book || !book->mem_stat_info_ptr) { |
kenjiArai | 0:5b88d5760320 | 269 | // no book or mem_stats |
kenjiArai | 0:5b88d5760320 | 270 | return -1; |
kenjiArai | 0:5b88d5760320 | 271 | } |
kenjiArai | 0:5b88d5760320 | 272 | |
kenjiArai | 0:5b88d5760320 | 273 | if (free_heap_amount && free_heap_amount < book->heap_size / 2) { |
kenjiArai | 0:5b88d5760320 | 274 | heap_limit = book->heap_size - free_heap_amount; |
kenjiArai | 0:5b88d5760320 | 275 | } |
kenjiArai | 0:5b88d5760320 | 276 | |
kenjiArai | 0:5b88d5760320 | 277 | if (!free_heap_amount && free_heap_percentage && free_heap_percentage < 50) { |
kenjiArai | 0:5b88d5760320 | 278 | heap_limit = book->heap_size / 100 * (100 - free_heap_percentage); |
kenjiArai | 0:5b88d5760320 | 279 | } |
kenjiArai | 0:5b88d5760320 | 280 | |
kenjiArai | 0:5b88d5760320 | 281 | if (free_heap_amount == 0 && free_heap_percentage == 0) { |
kenjiArai | 0:5b88d5760320 | 282 | // feature disabled, allow whole heap to be reserved by temporary allo |
kenjiArai | 0:5b88d5760320 | 283 | heap_limit = book->heap_size; |
kenjiArai | 0:5b88d5760320 | 284 | } |
kenjiArai | 0:5b88d5760320 | 285 | |
kenjiArai | 0:5b88d5760320 | 286 | if (heap_limit == 0) { |
kenjiArai | 0:5b88d5760320 | 287 | // illegal heap parameters |
kenjiArai | 0:5b88d5760320 | 288 | return -2; |
kenjiArai | 0:5b88d5760320 | 289 | } |
kenjiArai | 0:5b88d5760320 | 290 | |
kenjiArai | 0:5b88d5760320 | 291 | book->temporary_alloc_heap_limit = heap_limit; |
kenjiArai | 0:5b88d5760320 | 292 | |
kenjiArai | 0:5b88d5760320 | 293 | return 0; |
kenjiArai | 0:5b88d5760320 | 294 | #else |
kenjiArai | 0:5b88d5760320 | 295 | return -3; |
kenjiArai | 0:5b88d5760320 | 296 | #endif |
kenjiArai | 0:5b88d5760320 | 297 | } |
kenjiArai | 0:5b88d5760320 | 298 | |
kenjiArai | 0:5b88d5760320 | 299 | extern int ns_dyn_mem_set_temporary_alloc_free_heap_threshold(uint8_t free_heap_percentage, ns_mem_heap_size_t free_heap_amount) |
kenjiArai | 0:5b88d5760320 | 300 | { |
kenjiArai | 0:5b88d5760320 | 301 | return ns_mem_set_temporary_alloc_free_heap_threshold(default_book, free_heap_percentage, free_heap_amount); |
kenjiArai | 0:5b88d5760320 | 302 | } |
kenjiArai | 0:5b88d5760320 | 303 | |
kenjiArai | 0:5b88d5760320 | 304 | #ifndef STANDARD_MALLOC |
kenjiArai | 0:5b88d5760320 | 305 | static void dev_stat_update(mem_stat_t *mem_stat_info_ptr, mem_stat_update_t type, ns_mem_block_size_t size) |
kenjiArai | 0:5b88d5760320 | 306 | { |
kenjiArai | 0:5b88d5760320 | 307 | if (mem_stat_info_ptr) { |
kenjiArai | 0:5b88d5760320 | 308 | switch (type) { |
kenjiArai | 0:5b88d5760320 | 309 | case DEV_HEAP_ALLOC_OK: |
kenjiArai | 0:5b88d5760320 | 310 | mem_stat_info_ptr->heap_sector_alloc_cnt++; |
kenjiArai | 0:5b88d5760320 | 311 | mem_stat_info_ptr->heap_sector_allocated_bytes += size; |
kenjiArai | 0:5b88d5760320 | 312 | if (mem_stat_info_ptr->heap_sector_allocated_bytes_max < mem_stat_info_ptr->heap_sector_allocated_bytes) { |
kenjiArai | 0:5b88d5760320 | 313 | mem_stat_info_ptr->heap_sector_allocated_bytes_max = mem_stat_info_ptr->heap_sector_allocated_bytes; |
kenjiArai | 0:5b88d5760320 | 314 | } |
kenjiArai | 0:5b88d5760320 | 315 | mem_stat_info_ptr->heap_alloc_total_bytes += size; |
kenjiArai | 0:5b88d5760320 | 316 | break; |
kenjiArai | 0:5b88d5760320 | 317 | case DEV_HEAP_ALLOC_FAIL: |
kenjiArai | 0:5b88d5760320 | 318 | mem_stat_info_ptr->heap_alloc_fail_cnt++; |
kenjiArai | 0:5b88d5760320 | 319 | break; |
kenjiArai | 0:5b88d5760320 | 320 | case DEV_HEAP_FREE: |
kenjiArai | 0:5b88d5760320 | 321 | mem_stat_info_ptr->heap_sector_alloc_cnt--; |
kenjiArai | 0:5b88d5760320 | 322 | mem_stat_info_ptr->heap_sector_allocated_bytes -= size; |
kenjiArai | 0:5b88d5760320 | 323 | break; |
kenjiArai | 0:5b88d5760320 | 324 | } |
kenjiArai | 0:5b88d5760320 | 325 | } |
kenjiArai | 0:5b88d5760320 | 326 | } |
kenjiArai | 0:5b88d5760320 | 327 | |
kenjiArai | 0:5b88d5760320 | 328 | static ns_mem_word_size_t convert_allocation_size(ns_mem_book_t *book, ns_mem_block_size_t requested_bytes) |
kenjiArai | 0:5b88d5760320 | 329 | { |
kenjiArai | 0:5b88d5760320 | 330 | if (book->heap_main[0] == 0) { |
kenjiArai | 0:5b88d5760320 | 331 | heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_UNITIALIZED); |
kenjiArai | 0:5b88d5760320 | 332 | } else if (requested_bytes < 1) { |
kenjiArai | 0:5b88d5760320 | 333 | heap_failure(book, NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID); |
kenjiArai | 0:5b88d5760320 | 334 | } else if (requested_bytes > (book->heap_size - 2 * sizeof(ns_mem_word_size_t))) { |
kenjiArai | 0:5b88d5760320 | 335 | heap_failure(book, NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID); |
kenjiArai | 0:5b88d5760320 | 336 | } |
kenjiArai | 0:5b88d5760320 | 337 | return (requested_bytes + sizeof(ns_mem_word_size_t) - 1) / sizeof(ns_mem_word_size_t); |
kenjiArai | 0:5b88d5760320 | 338 | } |
kenjiArai | 0:5b88d5760320 | 339 | |
kenjiArai | 0:5b88d5760320 | 340 | // Checks that block length indicators are valid |
kenjiArai | 0:5b88d5760320 | 341 | // Block has format: Size of data area [1 word] | data area [abs(size) words]| Size of data area [1 word] |
kenjiArai | 0:5b88d5760320 | 342 | // If Size is negative it means area is unallocated |
kenjiArai | 0:5b88d5760320 | 343 | static int8_t ns_mem_block_validate(ns_mem_word_size_t *block_start) |
kenjiArai | 0:5b88d5760320 | 344 | { |
kenjiArai | 0:5b88d5760320 | 345 | int8_t ret_val = -1; |
kenjiArai | 0:5b88d5760320 | 346 | ns_mem_word_size_t *end = block_start; |
kenjiArai | 0:5b88d5760320 | 347 | ns_mem_word_size_t size_start = *end; |
kenjiArai | 0:5b88d5760320 | 348 | end += (1 + abs(size_start)); |
kenjiArai | 0:5b88d5760320 | 349 | if (size_start != 0 && size_start == *end) { |
kenjiArai | 0:5b88d5760320 | 350 | ret_val = 0; |
kenjiArai | 0:5b88d5760320 | 351 | } |
kenjiArai | 0:5b88d5760320 | 352 | return ret_val; |
kenjiArai | 0:5b88d5760320 | 353 | } |
kenjiArai | 0:5b88d5760320 | 354 | #endif |
kenjiArai | 0:5b88d5760320 | 355 | |
kenjiArai | 0:5b88d5760320 | 356 | // For direction, use 1 for direction up and -1 for down |
kenjiArai | 0:5b88d5760320 | 357 | static void *ns_mem_internal_alloc(ns_mem_book_t *book, const ns_mem_block_size_t alloc_size, int direction) |
kenjiArai | 0:5b88d5760320 | 358 | { |
kenjiArai | 0:5b88d5760320 | 359 | #ifndef STANDARD_MALLOC |
kenjiArai | 0:5b88d5760320 | 360 | if (!book) { |
kenjiArai | 0:5b88d5760320 | 361 | /* We can not do anything except return NULL because we can't find book |
kenjiArai | 0:5b88d5760320 | 362 | keeping block */ |
kenjiArai | 0:5b88d5760320 | 363 | return NULL; |
kenjiArai | 0:5b88d5760320 | 364 | } |
kenjiArai | 0:5b88d5760320 | 365 | |
kenjiArai | 0:5b88d5760320 | 366 | if (book->mem_stat_info_ptr && direction == 1) { |
kenjiArai | 0:5b88d5760320 | 367 | if (book->mem_stat_info_ptr->heap_sector_allocated_bytes > book->temporary_alloc_heap_limit) { |
kenjiArai | 0:5b88d5760320 | 368 | /* Not enough heap for temporary memory allocation */ |
kenjiArai | 0:5b88d5760320 | 369 | dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0); |
kenjiArai | 0:5b88d5760320 | 370 | return NULL; |
kenjiArai | 0:5b88d5760320 | 371 | } |
kenjiArai | 0:5b88d5760320 | 372 | } |
kenjiArai | 0:5b88d5760320 | 373 | |
kenjiArai | 0:5b88d5760320 | 374 | ns_mem_word_size_t *block_ptr = NULL; |
kenjiArai | 0:5b88d5760320 | 375 | |
kenjiArai | 0:5b88d5760320 | 376 | platform_enter_critical(); |
kenjiArai | 0:5b88d5760320 | 377 | |
kenjiArai | 0:5b88d5760320 | 378 | ns_mem_word_size_t data_size = convert_allocation_size(book, alloc_size); |
kenjiArai | 0:5b88d5760320 | 379 | if (!data_size) { |
kenjiArai | 0:5b88d5760320 | 380 | goto done; |
kenjiArai | 0:5b88d5760320 | 381 | } |
kenjiArai | 0:5b88d5760320 | 382 | |
kenjiArai | 0:5b88d5760320 | 383 | // ns_list_foreach, either forwards or backwards, result to ptr |
kenjiArai | 0:5b88d5760320 | 384 | for (hole_t *cur_hole = direction > 0 ? ns_list_get_first(&book->holes_list) |
kenjiArai | 0:5b88d5760320 | 385 | : ns_list_get_last(&book->holes_list); |
kenjiArai | 0:5b88d5760320 | 386 | cur_hole; |
kenjiArai | 0:5b88d5760320 | 387 | cur_hole = direction > 0 ? ns_list_get_next(&book->holes_list, cur_hole) |
kenjiArai | 0:5b88d5760320 | 388 | : ns_list_get_previous(&book->holes_list, cur_hole) |
kenjiArai | 0:5b88d5760320 | 389 | ) { |
kenjiArai | 0:5b88d5760320 | 390 | ns_mem_word_size_t *p = block_start_from_hole(cur_hole); |
kenjiArai | 0:5b88d5760320 | 391 | if (ns_mem_block_validate(p) != 0 || *p >= 0) { |
kenjiArai | 0:5b88d5760320 | 392 | //Validation failed, or this supposed hole has positive (allocated) size |
kenjiArai | 0:5b88d5760320 | 393 | heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED); |
kenjiArai | 0:5b88d5760320 | 394 | break; |
kenjiArai | 0:5b88d5760320 | 395 | } |
kenjiArai | 0:5b88d5760320 | 396 | if (-*p >= data_size) { |
kenjiArai | 0:5b88d5760320 | 397 | // Found a big enough block |
kenjiArai | 0:5b88d5760320 | 398 | block_ptr = p; |
kenjiArai | 0:5b88d5760320 | 399 | break; |
kenjiArai | 0:5b88d5760320 | 400 | } |
kenjiArai | 0:5b88d5760320 | 401 | } |
kenjiArai | 0:5b88d5760320 | 402 | |
kenjiArai | 0:5b88d5760320 | 403 | if (!block_ptr) { |
kenjiArai | 0:5b88d5760320 | 404 | goto done; |
kenjiArai | 0:5b88d5760320 | 405 | } |
kenjiArai | 0:5b88d5760320 | 406 | |
kenjiArai | 0:5b88d5760320 | 407 | // Separate declaration from initialization to keep IAR happy as the gotos skip this block. |
kenjiArai | 0:5b88d5760320 | 408 | ns_mem_word_size_t block_data_size; |
kenjiArai | 0:5b88d5760320 | 409 | block_data_size = -*block_ptr; |
kenjiArai | 0:5b88d5760320 | 410 | if (block_data_size >= (data_size + 2 + HOLE_T_SIZE)) { |
kenjiArai | 0:5b88d5760320 | 411 | ns_mem_word_size_t hole_size = block_data_size - data_size - 2; |
kenjiArai | 0:5b88d5760320 | 412 | ns_mem_word_size_t *hole_ptr; |
kenjiArai | 0:5b88d5760320 | 413 | //There is enough room for a new hole so create it first |
kenjiArai | 0:5b88d5760320 | 414 | if (direction > 0) { |
kenjiArai | 0:5b88d5760320 | 415 | hole_ptr = block_ptr + 1 + data_size + 1; |
kenjiArai | 0:5b88d5760320 | 416 | // Hole will be left at end of area. |
kenjiArai | 0:5b88d5760320 | 417 | // Would like to just replace this block_ptr with new descriptor, but |
kenjiArai | 0:5b88d5760320 | 418 | // they could overlap, so ns_list_replace might fail |
kenjiArai | 0:5b88d5760320 | 419 | //ns_list_replace(&holes_list, block_ptr, hole_from_block_start(hole_ptr)); |
kenjiArai | 0:5b88d5760320 | 420 | hole_t *before = ns_list_get_previous(&book->holes_list, hole_from_block_start(block_ptr)); |
kenjiArai | 0:5b88d5760320 | 421 | ns_list_remove(&book->holes_list, hole_from_block_start(block_ptr)); |
kenjiArai | 0:5b88d5760320 | 422 | if (before) { |
kenjiArai | 0:5b88d5760320 | 423 | ns_list_add_after(&book->holes_list, before, hole_from_block_start(hole_ptr)); |
kenjiArai | 0:5b88d5760320 | 424 | } else { |
kenjiArai | 0:5b88d5760320 | 425 | ns_list_add_to_start(&book->holes_list, hole_from_block_start(hole_ptr)); |
kenjiArai | 0:5b88d5760320 | 426 | } |
kenjiArai | 0:5b88d5760320 | 427 | } else { |
kenjiArai | 0:5b88d5760320 | 428 | hole_ptr = block_ptr; |
kenjiArai | 0:5b88d5760320 | 429 | // Hole remains at start of area - keep existing descriptor in place. |
kenjiArai | 0:5b88d5760320 | 430 | block_ptr += 1 + hole_size + 1; |
kenjiArai | 0:5b88d5760320 | 431 | } |
kenjiArai | 0:5b88d5760320 | 432 | |
kenjiArai | 0:5b88d5760320 | 433 | hole_ptr[0] = -hole_size; |
kenjiArai | 0:5b88d5760320 | 434 | hole_ptr[1 + hole_size] = -hole_size; |
kenjiArai | 0:5b88d5760320 | 435 | } else { |
kenjiArai | 0:5b88d5760320 | 436 | // Not enough room for a left-over hole, so use the whole block |
kenjiArai | 0:5b88d5760320 | 437 | data_size = block_data_size; |
kenjiArai | 0:5b88d5760320 | 438 | ns_list_remove(&book->holes_list, hole_from_block_start(block_ptr)); |
kenjiArai | 0:5b88d5760320 | 439 | } |
kenjiArai | 0:5b88d5760320 | 440 | block_ptr[0] = data_size; |
kenjiArai | 0:5b88d5760320 | 441 | block_ptr[1 + data_size] = data_size; |
kenjiArai | 0:5b88d5760320 | 442 | |
kenjiArai | 0:5b88d5760320 | 443 | done: |
kenjiArai | 0:5b88d5760320 | 444 | if (book->mem_stat_info_ptr) { |
kenjiArai | 0:5b88d5760320 | 445 | if (block_ptr) { |
kenjiArai | 0:5b88d5760320 | 446 | //Update Allocate OK |
kenjiArai | 0:5b88d5760320 | 447 | dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_OK, (data_size + 2) * sizeof(ns_mem_word_size_t)); |
kenjiArai | 0:5b88d5760320 | 448 | } else { |
kenjiArai | 0:5b88d5760320 | 449 | //Update Allocate Fail, second parameter is used for stats |
kenjiArai | 0:5b88d5760320 | 450 | dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0); |
kenjiArai | 0:5b88d5760320 | 451 | } |
kenjiArai | 0:5b88d5760320 | 452 | } |
kenjiArai | 0:5b88d5760320 | 453 | platform_exit_critical(); |
kenjiArai | 0:5b88d5760320 | 454 | |
kenjiArai | 0:5b88d5760320 | 455 | return block_ptr ? block_ptr + 1 : NULL; |
kenjiArai | 0:5b88d5760320 | 456 | #else |
kenjiArai | 0:5b88d5760320 | 457 | void *retval = NULL; |
kenjiArai | 0:5b88d5760320 | 458 | if (alloc_size) { |
kenjiArai | 0:5b88d5760320 | 459 | platform_enter_critical(); |
kenjiArai | 0:5b88d5760320 | 460 | retval = malloc(alloc_size); |
kenjiArai | 0:5b88d5760320 | 461 | platform_exit_critical(); |
kenjiArai | 0:5b88d5760320 | 462 | } |
kenjiArai | 0:5b88d5760320 | 463 | return retval; |
kenjiArai | 0:5b88d5760320 | 464 | #endif |
kenjiArai | 0:5b88d5760320 | 465 | } |
kenjiArai | 0:5b88d5760320 | 466 | |
kenjiArai | 0:5b88d5760320 | 467 | void *ns_mem_alloc(ns_mem_book_t *heap, ns_mem_block_size_t alloc_size) |
kenjiArai | 0:5b88d5760320 | 468 | { |
kenjiArai | 0:5b88d5760320 | 469 | return ns_mem_internal_alloc(heap, alloc_size, -1); |
kenjiArai | 0:5b88d5760320 | 470 | } |
kenjiArai | 0:5b88d5760320 | 471 | |
kenjiArai | 0:5b88d5760320 | 472 | void *ns_mem_temporary_alloc(ns_mem_book_t *heap, ns_mem_block_size_t alloc_size) |
kenjiArai | 0:5b88d5760320 | 473 | { |
kenjiArai | 0:5b88d5760320 | 474 | return ns_mem_internal_alloc(heap, alloc_size, 1); |
kenjiArai | 0:5b88d5760320 | 475 | } |
kenjiArai | 0:5b88d5760320 | 476 | |
kenjiArai | 0:5b88d5760320 | 477 | void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size) |
kenjiArai | 0:5b88d5760320 | 478 | { |
kenjiArai | 0:5b88d5760320 | 479 | return ns_mem_alloc(default_book, alloc_size); |
kenjiArai | 0:5b88d5760320 | 480 | } |
kenjiArai | 0:5b88d5760320 | 481 | |
kenjiArai | 0:5b88d5760320 | 482 | void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size) |
kenjiArai | 0:5b88d5760320 | 483 | { |
kenjiArai | 0:5b88d5760320 | 484 | return ns_mem_temporary_alloc(default_book, alloc_size); |
kenjiArai | 0:5b88d5760320 | 485 | } |
kenjiArai | 0:5b88d5760320 | 486 | |
kenjiArai | 0:5b88d5760320 | 487 | #ifndef STANDARD_MALLOC |
kenjiArai | 0:5b88d5760320 | 488 | 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) |
kenjiArai | 0:5b88d5760320 | 489 | { |
kenjiArai | 0:5b88d5760320 | 490 | // Theory of operation: Block is always in form | Len | Data | Len | |
kenjiArai | 0:5b88d5760320 | 491 | // So we need to check length of previous (if current not heap start) |
kenjiArai | 0:5b88d5760320 | 492 | // and next (if current not heap end) blocks. Negative length means |
kenjiArai | 0:5b88d5760320 | 493 | // free memory so we can merge freed block with those. |
kenjiArai | 0:5b88d5760320 | 494 | |
kenjiArai | 0:5b88d5760320 | 495 | hole_t *existing_start = NULL; |
kenjiArai | 0:5b88d5760320 | 496 | hole_t *existing_end = NULL; |
kenjiArai | 0:5b88d5760320 | 497 | ns_mem_word_size_t *start = cur_block; |
kenjiArai | 0:5b88d5760320 | 498 | ns_mem_word_size_t *end = cur_block + data_size + 1; |
kenjiArai | 0:5b88d5760320 | 499 | ns_mem_word_size_t *region_start; |
kenjiArai | 0:5b88d5760320 | 500 | ns_mem_word_size_t *region_end; |
kenjiArai | 0:5b88d5760320 | 501 | |
kenjiArai | 0:5b88d5760320 | 502 | int region_index = ns_dyn_mem_region_find(book, cur_block, data_size); |
kenjiArai | 0:5b88d5760320 | 503 | if (region_index >= 0) { |
kenjiArai | 0:5b88d5760320 | 504 | region_start = book->heap_main[region_index]; |
kenjiArai | 0:5b88d5760320 | 505 | region_end = book->heap_main_end[region_index]; |
kenjiArai | 0:5b88d5760320 | 506 | } else { |
kenjiArai | 0:5b88d5760320 | 507 | heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED); |
kenjiArai | 0:5b88d5760320 | 508 | // can't find region for the block, return |
kenjiArai | 0:5b88d5760320 | 509 | return; |
kenjiArai | 0:5b88d5760320 | 510 | } |
kenjiArai | 0:5b88d5760320 | 511 | |
kenjiArai | 0:5b88d5760320 | 512 | //invalidate current block |
kenjiArai | 0:5b88d5760320 | 513 | *start = -data_size; |
kenjiArai | 0:5b88d5760320 | 514 | *end = -data_size; |
kenjiArai | 0:5b88d5760320 | 515 | ns_mem_word_size_t merged_data_size = data_size; |
kenjiArai | 0:5b88d5760320 | 516 | |
kenjiArai | 0:5b88d5760320 | 517 | if (start != region_start) { |
kenjiArai | 0:5b88d5760320 | 518 | if (*(start - 1) < 0) { |
kenjiArai | 0:5b88d5760320 | 519 | ns_mem_word_size_t *block_end = start - 1; |
kenjiArai | 0:5b88d5760320 | 520 | ns_mem_word_size_t block_size = 1 + (-*block_end) + 1; |
kenjiArai | 0:5b88d5760320 | 521 | merged_data_size += block_size; |
kenjiArai | 0:5b88d5760320 | 522 | start -= block_size; |
kenjiArai | 0:5b88d5760320 | 523 | if (*start != *block_end) { |
kenjiArai | 0:5b88d5760320 | 524 | heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED); |
kenjiArai | 0:5b88d5760320 | 525 | } |
kenjiArai | 0:5b88d5760320 | 526 | if (block_size >= 1 + HOLE_T_SIZE + 1) { |
kenjiArai | 0:5b88d5760320 | 527 | existing_start = hole_from_block_start(start); |
kenjiArai | 0:5b88d5760320 | 528 | } |
kenjiArai | 0:5b88d5760320 | 529 | } |
kenjiArai | 0:5b88d5760320 | 530 | } |
kenjiArai | 0:5b88d5760320 | 531 | |
kenjiArai | 0:5b88d5760320 | 532 | if (end != region_end) { |
kenjiArai | 0:5b88d5760320 | 533 | if (*(end + 1) < 0) { |
kenjiArai | 0:5b88d5760320 | 534 | ns_mem_word_size_t *block_start = end + 1; |
kenjiArai | 0:5b88d5760320 | 535 | ns_mem_word_size_t block_size = 1 + (-*block_start) + 1; |
kenjiArai | 0:5b88d5760320 | 536 | merged_data_size += block_size; |
kenjiArai | 0:5b88d5760320 | 537 | end += block_size; |
kenjiArai | 0:5b88d5760320 | 538 | if (*end != *block_start) { |
kenjiArai | 0:5b88d5760320 | 539 | heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED); |
kenjiArai | 0:5b88d5760320 | 540 | } |
kenjiArai | 0:5b88d5760320 | 541 | if (block_size >= 1 + HOLE_T_SIZE + 1) { |
kenjiArai | 0:5b88d5760320 | 542 | existing_end = hole_from_block_start(block_start); |
kenjiArai | 0:5b88d5760320 | 543 | } |
kenjiArai | 0:5b88d5760320 | 544 | } |
kenjiArai | 0:5b88d5760320 | 545 | } |
kenjiArai | 0:5b88d5760320 | 546 | |
kenjiArai | 0:5b88d5760320 | 547 | hole_t *to_add = hole_from_block_start(start); |
kenjiArai | 0:5b88d5760320 | 548 | hole_t *before = NULL; |
kenjiArai | 0:5b88d5760320 | 549 | if (existing_end) { |
kenjiArai | 0:5b88d5760320 | 550 | // Extending hole described by "existing_end" downwards. |
kenjiArai | 0:5b88d5760320 | 551 | // Will replace with descriptor at bottom of merged block. |
kenjiArai | 0:5b88d5760320 | 552 | // (Can't use ns_list_replace, because of danger of overlap) |
kenjiArai | 0:5b88d5760320 | 553 | // Optimisation - note our position for insertion below. |
kenjiArai | 0:5b88d5760320 | 554 | before = ns_list_get_next(&book->holes_list, existing_end); |
kenjiArai | 0:5b88d5760320 | 555 | ns_list_remove(&book->holes_list, existing_end); |
kenjiArai | 0:5b88d5760320 | 556 | } |
kenjiArai | 0:5b88d5760320 | 557 | if (existing_start) { |
kenjiArai | 0:5b88d5760320 | 558 | // Extending hole described by "existing_start" upwards. |
kenjiArai | 0:5b88d5760320 | 559 | // No need to modify that descriptor - it remains at the bottom |
kenjiArai | 0:5b88d5760320 | 560 | // of the merged block to describe it. |
kenjiArai | 0:5b88d5760320 | 561 | } else { |
kenjiArai | 0:5b88d5760320 | 562 | // Didn't find adjacent descriptors, but may still |
kenjiArai | 0:5b88d5760320 | 563 | // be merging with small blocks without descriptors. |
kenjiArai | 0:5b88d5760320 | 564 | if (merged_data_size >= HOLE_T_SIZE) { |
kenjiArai | 0:5b88d5760320 | 565 | // Locate hole position in list, if we don't already know |
kenjiArai | 0:5b88d5760320 | 566 | // from merging with the block above. |
kenjiArai | 0:5b88d5760320 | 567 | if (!existing_end) { |
kenjiArai | 0:5b88d5760320 | 568 | ns_list_foreach(hole_t, ptr, &book->holes_list) { |
kenjiArai | 0:5b88d5760320 | 569 | if (ptr > to_add) { |
kenjiArai | 0:5b88d5760320 | 570 | before = ptr; |
kenjiArai | 0:5b88d5760320 | 571 | break; |
kenjiArai | 0:5b88d5760320 | 572 | } |
kenjiArai | 0:5b88d5760320 | 573 | } |
kenjiArai | 0:5b88d5760320 | 574 | } |
kenjiArai | 0:5b88d5760320 | 575 | if (before) { |
kenjiArai | 0:5b88d5760320 | 576 | ns_list_add_before(&book->holes_list, before, to_add); |
kenjiArai | 0:5b88d5760320 | 577 | } else { |
kenjiArai | 0:5b88d5760320 | 578 | ns_list_add_to_end(&book->holes_list, to_add); |
kenjiArai | 0:5b88d5760320 | 579 | } |
kenjiArai | 0:5b88d5760320 | 580 | |
kenjiArai | 0:5b88d5760320 | 581 | } |
kenjiArai | 0:5b88d5760320 | 582 | } |
kenjiArai | 0:5b88d5760320 | 583 | *start = -merged_data_size; |
kenjiArai | 0:5b88d5760320 | 584 | *end = -merged_data_size; |
kenjiArai | 0:5b88d5760320 | 585 | } |
kenjiArai | 0:5b88d5760320 | 586 | #endif |
kenjiArai | 0:5b88d5760320 | 587 | |
kenjiArai | 0:5b88d5760320 | 588 | static bool pointer_address_validate(ns_mem_book_t *book, ns_mem_word_size_t *ptr, ns_mem_word_size_t size) |
kenjiArai | 0:5b88d5760320 | 589 | { |
kenjiArai | 0:5b88d5760320 | 590 | |
kenjiArai | 0:5b88d5760320 | 591 | if (ns_dyn_mem_region_find(book, ptr, size) >= 0) { |
kenjiArai | 0:5b88d5760320 | 592 | return true; |
kenjiArai | 0:5b88d5760320 | 593 | } |
kenjiArai | 0:5b88d5760320 | 594 | |
kenjiArai | 0:5b88d5760320 | 595 | return false; |
kenjiArai | 0:5b88d5760320 | 596 | } |
kenjiArai | 0:5b88d5760320 | 597 | |
kenjiArai | 0:5b88d5760320 | 598 | void ns_mem_free(ns_mem_book_t *book, void *block) |
kenjiArai | 0:5b88d5760320 | 599 | { |
kenjiArai | 0:5b88d5760320 | 600 | #ifndef STANDARD_MALLOC |
kenjiArai | 0:5b88d5760320 | 601 | |
kenjiArai | 0:5b88d5760320 | 602 | if (!block) { |
kenjiArai | 0:5b88d5760320 | 603 | return; |
kenjiArai | 0:5b88d5760320 | 604 | } |
kenjiArai | 0:5b88d5760320 | 605 | |
kenjiArai | 0:5b88d5760320 | 606 | ns_mem_word_size_t *ptr = block; |
kenjiArai | 0:5b88d5760320 | 607 | ns_mem_word_size_t size; |
kenjiArai | 0:5b88d5760320 | 608 | |
kenjiArai | 0:5b88d5760320 | 609 | platform_enter_critical(); |
kenjiArai | 0:5b88d5760320 | 610 | ptr --; |
kenjiArai | 0:5b88d5760320 | 611 | //Read Current Size |
kenjiArai | 0:5b88d5760320 | 612 | size = *ptr; |
kenjiArai | 0:5b88d5760320 | 613 | if (!pointer_address_validate(book, ptr, size)) { |
kenjiArai | 0:5b88d5760320 | 614 | heap_failure(book, NS_DYN_MEM_POINTER_NOT_VALID); |
kenjiArai | 0:5b88d5760320 | 615 | } else if (size < 0) { |
kenjiArai | 0:5b88d5760320 | 616 | heap_failure(book, NS_DYN_MEM_DOUBLE_FREE); |
kenjiArai | 0:5b88d5760320 | 617 | } else { |
kenjiArai | 0:5b88d5760320 | 618 | if (ns_mem_block_validate(ptr) != 0) { |
kenjiArai | 0:5b88d5760320 | 619 | heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED); |
kenjiArai | 0:5b88d5760320 | 620 | } else { |
kenjiArai | 0:5b88d5760320 | 621 | ns_mem_free_and_merge_with_adjacent_blocks(book, ptr, size); |
kenjiArai | 0:5b88d5760320 | 622 | if (book->mem_stat_info_ptr) { |
kenjiArai | 0:5b88d5760320 | 623 | //Update Free Counter |
kenjiArai | 0:5b88d5760320 | 624 | dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_FREE, (size + 2) * sizeof(ns_mem_word_size_t)); |
kenjiArai | 0:5b88d5760320 | 625 | } |
kenjiArai | 0:5b88d5760320 | 626 | } |
kenjiArai | 0:5b88d5760320 | 627 | } |
kenjiArai | 0:5b88d5760320 | 628 | |
kenjiArai | 0:5b88d5760320 | 629 | platform_exit_critical(); |
kenjiArai | 0:5b88d5760320 | 630 | #else |
kenjiArai | 0:5b88d5760320 | 631 | platform_enter_critical(); |
kenjiArai | 0:5b88d5760320 | 632 | free(block); |
kenjiArai | 0:5b88d5760320 | 633 | platform_exit_critical(); |
kenjiArai | 0:5b88d5760320 | 634 | #endif |
kenjiArai | 0:5b88d5760320 | 635 | } |
kenjiArai | 0:5b88d5760320 | 636 | |
kenjiArai | 0:5b88d5760320 | 637 | void ns_dyn_mem_free(void *block) |
kenjiArai | 0:5b88d5760320 | 638 | { |
kenjiArai | 0:5b88d5760320 | 639 | ns_mem_free(default_book, block); |
kenjiArai | 0:5b88d5760320 | 640 | } |