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