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