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