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.
Fork of mbed-dev by
mbed_alloc_wrappers.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2016 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "platform/mbed_mem_trace.h" 00018 #include "platform/mbed_stats.h" 00019 #include "platform/mbed_toolchain.h" 00020 #include "platform/SingletonPtr.h" 00021 #include "platform/PlatformMutex.h" 00022 #include <stddef.h> 00023 #include <stdio.h> 00024 #include <string.h> 00025 #include <stdlib.h> 00026 00027 /* There are two memory tracers in mbed OS: 00028 00029 - the first can be used to detect the maximum heap usage at runtime. It is 00030 activated by defining the MBED_HEAP_STATS_ENABLED macro. 00031 - the second can be used to trace each memory call by automatically invoking 00032 a callback on each memory operation (see hal/api/mbed_mem_trace.h). It is 00033 activated by defining the MBED_MEM_TRACING_ENABLED macro. 00034 00035 Both tracers can be activated and deactivated in any combination. If both tracers 00036 are active, the second one (MBED_MEM_TRACING_ENABLED) will trace the first one's 00037 (MBED_HEAP_STATS_ENABLED) memory calls.*/ 00038 00039 /******************************************************************************/ 00040 /* Implementation of the runtime max heap usage checker */ 00041 /******************************************************************************/ 00042 00043 /* Size must be a multiple of 8 to keep alignment */ 00044 typedef struct { 00045 uint32_t size; 00046 uint32_t pad; 00047 } alloc_info_t; 00048 00049 #ifdef MBED_HEAP_STATS_ENABLED 00050 static SingletonPtr<PlatformMutex> malloc_stats_mutex; 00051 static mbed_stats_heap_t heap_stats = {0, 0, 0, 0, 0}; 00052 #endif 00053 00054 void mbed_stats_heap_get(mbed_stats_heap_t *stats) 00055 { 00056 #ifdef MBED_HEAP_STATS_ENABLED 00057 extern uint32_t mbed_heap_size; 00058 heap_stats.reserved_size = mbed_heap_size; 00059 00060 malloc_stats_mutex->lock(); 00061 memcpy(stats, &heap_stats, sizeof(mbed_stats_heap_t)); 00062 malloc_stats_mutex->unlock(); 00063 #else 00064 memset(stats, 0, sizeof(mbed_stats_heap_t)); 00065 #endif 00066 } 00067 00068 /******************************************************************************/ 00069 /* GCC memory allocation wrappers */ 00070 /******************************************************************************/ 00071 00072 #if defined(TOOLCHAIN_GCC) 00073 00074 #ifdef FEATURE_UVISOR 00075 #include "uvisor-lib/uvisor-lib.h" 00076 #endif/* FEATURE_UVISOR */ 00077 00078 extern "C" { 00079 void *__real__malloc_r(struct _reent *r, size_t size); 00080 void *__real__memalign_r(struct _reent *r, size_t alignment, size_t bytes); 00081 void *__real__realloc_r(struct _reent *r, void *ptr, size_t size); 00082 void __real__free_r(struct _reent *r, void *ptr); 00083 void *__real__calloc_r(struct _reent *r, size_t nmemb, size_t size); 00084 void *malloc_wrapper(struct _reent *r, size_t size, void *caller); 00085 void free_wrapper(struct _reent *r, void *ptr, void *caller); 00086 } 00087 00088 // TODO: memory tracing doesn't work with uVisor enabled. 00089 #if !defined(FEATURE_UVISOR) 00090 00091 extern "C" void *__wrap__malloc_r(struct _reent *r, size_t size) 00092 { 00093 return malloc_wrapper(r, size, MBED_CALLER_ADDR()); 00094 } 00095 00096 extern "C" void *malloc_wrapper(struct _reent *r, size_t size, void *caller) 00097 { 00098 void *ptr = NULL; 00099 #ifdef MBED_MEM_TRACING_ENABLED 00100 mbed_mem_trace_lock(); 00101 #endif 00102 #ifdef MBED_HEAP_STATS_ENABLED 00103 malloc_stats_mutex->lock(); 00104 alloc_info_t *alloc_info = (alloc_info_t *)__real__malloc_r(r, size + sizeof(alloc_info_t)); 00105 if (alloc_info != NULL) { 00106 alloc_info->size = size; 00107 ptr = (void *)(alloc_info + 1); 00108 heap_stats.current_size += size; 00109 heap_stats.total_size += size; 00110 heap_stats.alloc_cnt += 1; 00111 if (heap_stats.current_size > heap_stats.max_size) { 00112 heap_stats.max_size = heap_stats.current_size; 00113 } 00114 } else { 00115 heap_stats.alloc_fail_cnt += 1; 00116 } 00117 malloc_stats_mutex->unlock(); 00118 #else // #ifdef MBED_HEAP_STATS_ENABLED 00119 ptr = __real__malloc_r(r, size); 00120 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00121 #ifdef MBED_MEM_TRACING_ENABLED 00122 mbed_mem_trace_malloc(ptr, size, caller); 00123 mbed_mem_trace_unlock(); 00124 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00125 return ptr; 00126 } 00127 00128 extern "C" void *__wrap__realloc_r(struct _reent *r, void *ptr, size_t size) 00129 { 00130 void *new_ptr = NULL; 00131 #ifdef MBED_MEM_TRACING_ENABLED 00132 mbed_mem_trace_lock(); 00133 #endif 00134 #ifdef MBED_HEAP_STATS_ENABLED 00135 // Implement realloc_r with malloc and free. 00136 // The function realloc_r can't be used here directly since 00137 // it can call into __wrap__malloc_r (returns ptr + 4) or 00138 // resize memory directly (returns ptr + 0). 00139 00140 // Note - no lock needed since malloc and free are thread safe 00141 00142 // Get old size 00143 uint32_t old_size = 0; 00144 if (ptr != NULL) { 00145 alloc_info_t *alloc_info = ((alloc_info_t *)ptr) - 1; 00146 old_size = alloc_info->size; 00147 } 00148 00149 // Allocate space 00150 if (size != 0) { 00151 new_ptr = malloc(size); 00152 } 00153 00154 // If the new buffer has been allocated copy the data to it 00155 // and free the old buffer 00156 if (new_ptr != NULL) { 00157 uint32_t copy_size = (old_size < size) ? old_size : size; 00158 memcpy(new_ptr, (void *)ptr, copy_size); 00159 free(ptr); 00160 } 00161 #else // #ifdef MBED_HEAP_STATS_ENABLED 00162 new_ptr = __real__realloc_r(r, ptr, size); 00163 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00164 #ifdef MBED_MEM_TRACING_ENABLED 00165 mbed_mem_trace_realloc(new_ptr, ptr, size, MBED_CALLER_ADDR()); 00166 mbed_mem_trace_unlock(); 00167 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00168 return new_ptr; 00169 } 00170 00171 extern "C" void __wrap__free_r(struct _reent *r, void *ptr) 00172 { 00173 free_wrapper(r, ptr, MBED_CALLER_ADDR()); 00174 } 00175 00176 extern "C" void free_wrapper(struct _reent *r, void *ptr, void *caller) 00177 { 00178 #ifdef MBED_MEM_TRACING_ENABLED 00179 mbed_mem_trace_lock(); 00180 #endif 00181 #ifdef MBED_HEAP_STATS_ENABLED 00182 malloc_stats_mutex->lock(); 00183 alloc_info_t *alloc_info = NULL; 00184 if (ptr != NULL) { 00185 alloc_info = ((alloc_info_t *)ptr) - 1; 00186 heap_stats.current_size -= alloc_info->size; 00187 heap_stats.alloc_cnt -= 1; 00188 } 00189 __real__free_r(r, (void *)alloc_info); 00190 malloc_stats_mutex->unlock(); 00191 #else // #ifdef MBED_HEAP_STATS_ENABLED 00192 __real__free_r(r, ptr); 00193 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00194 #ifdef MBED_MEM_TRACING_ENABLED 00195 mbed_mem_trace_free(ptr, caller); 00196 mbed_mem_trace_unlock(); 00197 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00198 } 00199 00200 extern "C" void *__wrap__calloc_r(struct _reent *r, size_t nmemb, size_t size) 00201 { 00202 void *ptr = NULL; 00203 #ifdef MBED_MEM_TRACING_ENABLED 00204 mbed_mem_trace_lock(); 00205 #endif 00206 #ifdef MBED_HEAP_STATS_ENABLED 00207 // Note - no lock needed since malloc is thread safe 00208 00209 ptr = malloc(nmemb * size); 00210 if (ptr != NULL) { 00211 memset(ptr, 0, nmemb * size); 00212 } 00213 #else // #ifdef MBED_HEAP_STATS_ENABLED 00214 ptr = __real__calloc_r(r, nmemb, size); 00215 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00216 #ifdef MBED_MEM_TRACING_ENABLED 00217 mbed_mem_trace_calloc(ptr, nmemb, size, MBED_CALLER_ADDR()); 00218 mbed_mem_trace_unlock(); 00219 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00220 return ptr; 00221 } 00222 00223 extern "C" void *__wrap__memalign_r(struct _reent *r, size_t alignment, size_t bytes) 00224 { 00225 return __real__memalign_r(r, alignment, bytes); 00226 } 00227 00228 #endif // if !defined(FEATURE_UVISOR) 00229 00230 00231 /******************************************************************************/ 00232 /* ARMCC / IAR memory allocation wrappers */ 00233 /******************************************************************************/ 00234 00235 #elif defined(TOOLCHAIN_ARM) || defined(__ICCARM__) 00236 00237 #if defined(TOOLCHAIN_ARM) 00238 #define SUPER_MALLOC $Super$$malloc 00239 #define SUB_MALLOC $Sub$$malloc 00240 #define SUPER_REALLOC $Super$$realloc 00241 #define SUB_REALLOC $Sub$$realloc 00242 #define SUPER_CALLOC $Super$$calloc 00243 #define SUB_CALLOC $Sub$$calloc 00244 #define SUPER_FREE $Super$$free 00245 #define SUB_FREE $Sub$$free 00246 #elif defined(__ICCARM__) 00247 #define SUPER_MALLOC $Super$$__iar_dlmalloc 00248 #define SUB_MALLOC $Sub$$__iar_dlmalloc 00249 #define SUPER_REALLOC $Super$$__iar_dlrealloc 00250 #define SUB_REALLOC $Sub$$__iar_dlrealloc 00251 #define SUPER_CALLOC $Super$$__iar_dlcalloc 00252 #define SUB_CALLOC $Sub$$__iar_dlcalloc 00253 #define SUPER_FREE $Super$$__iar_dlfree 00254 #define SUB_FREE $Sub$$__iar_dlfree 00255 #endif 00256 00257 /* Enable hooking of memory function only if tracing is also enabled */ 00258 #if defined(MBED_MEM_TRACING_ENABLED) || defined(MBED_HEAP_STATS_ENABLED) 00259 00260 extern "C" { 00261 void *SUPER_MALLOC(size_t size); 00262 void *SUPER_REALLOC(void *ptr, size_t size); 00263 void *SUPER_CALLOC(size_t nmemb, size_t size); 00264 void SUPER_FREE(void *ptr); 00265 void *malloc_wrapper(size_t size, void *caller); 00266 void free_wrapper(void *ptr, void *caller); 00267 } 00268 00269 00270 extern "C" void *SUB_MALLOC(size_t size) 00271 { 00272 return malloc_wrapper(size, MBED_CALLER_ADDR()); 00273 } 00274 00275 extern "C" void *malloc_wrapper(size_t size, void *caller) 00276 { 00277 void *ptr = NULL; 00278 #ifdef MBED_MEM_TRACING_ENABLED 00279 mbed_mem_trace_lock(); 00280 #endif 00281 #ifdef MBED_HEAP_STATS_ENABLED 00282 malloc_stats_mutex->lock(); 00283 alloc_info_t *alloc_info = (alloc_info_t *)SUPER_MALLOC(size + sizeof(alloc_info_t)); 00284 if (alloc_info != NULL) { 00285 alloc_info->size = size; 00286 ptr = (void *)(alloc_info + 1); 00287 heap_stats.current_size += size; 00288 heap_stats.total_size += size; 00289 heap_stats.alloc_cnt += 1; 00290 if (heap_stats.current_size > heap_stats.max_size) { 00291 heap_stats.max_size = heap_stats.current_size; 00292 } 00293 } else { 00294 heap_stats.alloc_fail_cnt += 1; 00295 } 00296 malloc_stats_mutex->unlock(); 00297 #else // #ifdef MBED_HEAP_STATS_ENABLED 00298 ptr = SUPER_MALLOC(size); 00299 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00300 #ifdef MBED_MEM_TRACING_ENABLED 00301 mbed_mem_trace_malloc(ptr, size, caller); 00302 mbed_mem_trace_unlock(); 00303 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00304 return ptr; 00305 } 00306 00307 00308 extern "C" void *SUB_REALLOC(void *ptr, size_t size) 00309 { 00310 void *new_ptr = NULL; 00311 #ifdef MBED_MEM_TRACING_ENABLED 00312 mbed_mem_trace_lock(); 00313 #endif 00314 #ifdef MBED_HEAP_STATS_ENABLED 00315 // Note - no lock needed since malloc and free are thread safe 00316 00317 // Get old size 00318 uint32_t old_size = 0; 00319 if (ptr != NULL) { 00320 alloc_info_t *alloc_info = ((alloc_info_t *)ptr) - 1; 00321 old_size = alloc_info->size; 00322 } 00323 00324 // Allocate space 00325 if (size != 0) { 00326 new_ptr = malloc(size); 00327 } 00328 00329 // If the new buffer has been allocated copy the data to it 00330 // and free the old buffer 00331 if (new_ptr != NULL) { 00332 uint32_t copy_size = (old_size < size) ? old_size : size; 00333 memcpy(new_ptr, (void *)ptr, copy_size); 00334 free(ptr); 00335 } 00336 #else // #ifdef MBED_HEAP_STATS_ENABLED 00337 new_ptr = SUPER_REALLOC(ptr, size); 00338 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00339 #ifdef MBED_MEM_TRACING_ENABLED 00340 mbed_mem_trace_realloc(new_ptr, ptr, size, MBED_CALLER_ADDR()); 00341 mbed_mem_trace_unlock(); 00342 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00343 return new_ptr; 00344 } 00345 00346 extern "C" void *SUB_CALLOC(size_t nmemb, size_t size) 00347 { 00348 void *ptr = NULL; 00349 #ifdef MBED_MEM_TRACING_ENABLED 00350 mbed_mem_trace_lock(); 00351 #endif 00352 #ifdef MBED_HEAP_STATS_ENABLED 00353 // Note - no lock needed since malloc is thread safe 00354 ptr = malloc(nmemb * size); 00355 if (ptr != NULL) { 00356 memset(ptr, 0, nmemb * size); 00357 } 00358 #else // #ifdef MBED_HEAP_STATS_ENABLED 00359 ptr = SUPER_CALLOC(nmemb, size); 00360 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00361 #ifdef MBED_MEM_TRACING_ENABLED 00362 mbed_mem_trace_calloc(ptr, nmemb, size, MBED_CALLER_ADDR()); 00363 mbed_mem_trace_unlock(); 00364 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00365 return ptr; 00366 } 00367 00368 extern "C" void SUB_FREE(void *ptr) 00369 { 00370 free_wrapper(ptr, MBED_CALLER_ADDR()); 00371 } 00372 00373 extern "C" void free_wrapper(void *ptr, void *caller) 00374 { 00375 #ifdef MBED_MEM_TRACING_ENABLED 00376 mbed_mem_trace_lock(); 00377 #endif 00378 #ifdef MBED_HEAP_STATS_ENABLED 00379 malloc_stats_mutex->lock(); 00380 alloc_info_t *alloc_info = NULL; 00381 if (ptr != NULL) { 00382 alloc_info = ((alloc_info_t *)ptr) - 1; 00383 heap_stats.current_size -= alloc_info->size; 00384 heap_stats.alloc_cnt -= 1; 00385 } 00386 SUPER_FREE((void *)alloc_info); 00387 malloc_stats_mutex->unlock(); 00388 #else // #ifdef MBED_HEAP_STATS_ENABLED 00389 SUPER_FREE(ptr); 00390 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00391 #ifdef MBED_MEM_TRACING_ENABLED 00392 mbed_mem_trace_free(ptr, caller); 00393 mbed_mem_trace_unlock(); 00394 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00395 } 00396 00397 #endif // #if defined(MBED_MEM_TRACING_ENABLED) || defined(MBED_HEAP_STATS_ENABLED) 00398 00399 /******************************************************************************/ 00400 /* Allocation wrappers for other toolchains are not supported yet */ 00401 /******************************************************************************/ 00402 00403 #else 00404 00405 #ifdef MBED_MEM_TRACING_ENABLED 00406 #error Memory tracing is not supported with the current toolchain. 00407 #endif 00408 00409 #ifdef MBED_HEAP_STATS_ENABLED 00410 #error Heap statistics are not supported with the current toolchain. 00411 #endif 00412 00413 #endif // #if defined(TOOLCHAIN_GCC)
Generated on Tue Jul 12 2022 19:10:21 by
1.7.2
