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_MEM_TRACING_ENABLED 00050 static SingletonPtr<PlatformMutex> mem_trace_mutex; 00051 #endif 00052 #ifdef MBED_HEAP_STATS_ENABLED 00053 static SingletonPtr<PlatformMutex> malloc_stats_mutex; 00054 static mbed_stats_heap_t heap_stats = {0, 0, 0, 0, 0}; 00055 #endif 00056 00057 void mbed_stats_heap_get(mbed_stats_heap_t *stats) 00058 { 00059 #ifdef MBED_HEAP_STATS_ENABLED 00060 extern uint32_t mbed_heap_size; 00061 heap_stats.reserved_size = mbed_heap_size; 00062 00063 malloc_stats_mutex->lock(); 00064 memcpy(stats, &heap_stats, sizeof(mbed_stats_heap_t)); 00065 malloc_stats_mutex->unlock(); 00066 #else 00067 memset(stats, 0, sizeof(mbed_stats_heap_t)); 00068 #endif 00069 } 00070 00071 /******************************************************************************/ 00072 /* GCC memory allocation wrappers */ 00073 /******************************************************************************/ 00074 00075 #if defined(TOOLCHAIN_GCC) 00076 00077 #ifdef FEATURE_UVISOR 00078 #include "uvisor-lib/uvisor-lib.h" 00079 #endif/* FEATURE_UVISOR */ 00080 00081 extern "C" { 00082 void * __real__malloc_r(struct _reent * r, size_t size); 00083 void * __real__memalign_r(struct _reent * r, size_t alignment, size_t bytes); 00084 void * __real__realloc_r(struct _reent * r, void * ptr, size_t size); 00085 void __real__free_r(struct _reent * r, void * ptr); 00086 void* __real__calloc_r(struct _reent * r, size_t nmemb, size_t size); 00087 } 00088 00089 // TODO: memory tracing doesn't work with uVisor enabled. 00090 #if !defined(FEATURE_UVISOR) 00091 00092 extern "C" void * __wrap__malloc_r(struct _reent * r, size_t size) { 00093 void *ptr = NULL; 00094 #ifdef MBED_HEAP_STATS_ENABLED 00095 malloc_stats_mutex->lock(); 00096 alloc_info_t *alloc_info = (alloc_info_t*)__real__malloc_r(r, size + sizeof(alloc_info_t)); 00097 if (alloc_info != NULL) { 00098 alloc_info->size = size; 00099 ptr = (void*)(alloc_info + 1); 00100 heap_stats.current_size += size; 00101 heap_stats.total_size += size; 00102 heap_stats.alloc_cnt += 1; 00103 if (heap_stats.current_size > heap_stats.max_size) { 00104 heap_stats.max_size = heap_stats.current_size; 00105 } 00106 } else { 00107 heap_stats.alloc_fail_cnt += 1; 00108 } 00109 malloc_stats_mutex->unlock(); 00110 #else // #ifdef MBED_HEAP_STATS_ENABLED 00111 ptr = __real__malloc_r(r, size); 00112 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00113 #ifdef MBED_MEM_TRACING_ENABLED 00114 mem_trace_mutex->lock(); 00115 mbed_mem_trace_malloc(ptr, size, MBED_CALLER_ADDR()); 00116 mem_trace_mutex->unlock(); 00117 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00118 return ptr; 00119 } 00120 00121 extern "C" void * __wrap__realloc_r(struct _reent * r, void * ptr, size_t size) { 00122 void *new_ptr = NULL; 00123 #ifdef MBED_HEAP_STATS_ENABLED 00124 // Implement realloc_r with malloc and free. 00125 // The function realloc_r can't be used here directly since 00126 // it can call into __wrap__malloc_r (returns ptr + 4) or 00127 // resize memory directly (returns ptr + 0). 00128 00129 // Note - no lock needed since malloc and free are thread safe 00130 00131 // Get old size 00132 uint32_t old_size = 0; 00133 if (ptr != NULL) { 00134 alloc_info_t *alloc_info = ((alloc_info_t*)ptr) - 1; 00135 old_size = alloc_info->size; 00136 } 00137 00138 // Allocate space 00139 if (size != 0) { 00140 new_ptr = malloc(size); 00141 } 00142 00143 // If the new buffer has been allocated copy the data to it 00144 // and free the old buffer 00145 if (new_ptr != NULL) { 00146 uint32_t copy_size = (old_size < size) ? old_size : size; 00147 memcpy(new_ptr, (void*)ptr, copy_size); 00148 free(ptr); 00149 } 00150 #else // #ifdef MBED_HEAP_STATS_ENABLED 00151 new_ptr = __real__realloc_r(r, ptr, size); 00152 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00153 #ifdef MBED_MEM_TRACING_ENABLED 00154 mem_trace_mutex->lock(); 00155 mbed_mem_trace_realloc(new_ptr, ptr, size, MBED_CALLER_ADDR()); 00156 mem_trace_mutex->unlock(); 00157 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00158 return new_ptr; 00159 } 00160 00161 extern "C" void __wrap__free_r(struct _reent * r, void * ptr) { 00162 #ifdef MBED_HEAP_STATS_ENABLED 00163 malloc_stats_mutex->lock(); 00164 alloc_info_t *alloc_info = NULL; 00165 if (ptr != NULL) { 00166 alloc_info = ((alloc_info_t*)ptr) - 1; 00167 heap_stats.current_size -= alloc_info->size; 00168 heap_stats.alloc_cnt -= 1; 00169 } 00170 __real__free_r(r, (void*)alloc_info); 00171 malloc_stats_mutex->unlock(); 00172 #else // #ifdef MBED_HEAP_STATS_ENABLED 00173 __real__free_r(r, ptr); 00174 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00175 #ifdef MBED_MEM_TRACING_ENABLED 00176 mem_trace_mutex->lock(); 00177 mbed_mem_trace_free(ptr, MBED_CALLER_ADDR()); 00178 mem_trace_mutex->unlock(); 00179 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00180 } 00181 00182 extern "C" void * __wrap__calloc_r(struct _reent * r, size_t nmemb, size_t size) { 00183 void *ptr = NULL; 00184 #ifdef MBED_HEAP_STATS_ENABLED 00185 // Note - no lock needed since malloc is thread safe 00186 00187 ptr = malloc(nmemb * size); 00188 if (ptr != NULL) { 00189 memset(ptr, 0, nmemb * size); 00190 } 00191 #else // #ifdef MBED_HEAP_STATS_ENABLED 00192 ptr = __real__calloc_r(r, nmemb, size); 00193 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00194 #ifdef MBED_MEM_TRACING_ENABLED 00195 mem_trace_mutex->lock(); 00196 mbed_mem_trace_calloc(ptr, nmemb, size, MBED_CALLER_ADDR()); 00197 mem_trace_mutex->unlock(); 00198 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00199 return ptr; 00200 } 00201 00202 extern "C" void * __wrap__memalign_r(struct _reent * r, size_t alignment, size_t bytes) { 00203 return __real__memalign_r(r, alignment, bytes); 00204 } 00205 00206 #endif // if !defined(FEATURE_UVISOR) 00207 00208 00209 /******************************************************************************/ 00210 /* ARMCC / IAR memory allocation wrappers */ 00211 /******************************************************************************/ 00212 00213 #elif defined(TOOLCHAIN_ARM) || defined(__ICCARM__) 00214 00215 #if defined(TOOLCHAIN_ARM) 00216 #define SUPER_MALLOC $Super$$malloc 00217 #define SUB_MALLOC $Sub$$malloc 00218 #define SUPER_REALLOC $Super$$realloc 00219 #define SUB_REALLOC $Sub$$realloc 00220 #define SUPER_CALLOC $Super$$calloc 00221 #define SUB_CALLOC $Sub$$calloc 00222 #define SUPER_FREE $Super$$free 00223 #define SUB_FREE $Sub$$free 00224 #elif defined(__ICCARM__) 00225 #define SUPER_MALLOC $Super$$__iar_dlmalloc 00226 #define SUB_MALLOC $Sub$$__iar_dlmalloc 00227 #define SUPER_REALLOC $Super$$__iar_dlrealloc 00228 #define SUB_REALLOC $Sub$$__iar_dlrealloc 00229 #define SUPER_CALLOC $Super$$__iar_dlcalloc 00230 #define SUB_CALLOC $Sub$$__iar_dlcalloc 00231 #define SUPER_FREE $Super$$__iar_dlfree 00232 #define SUB_FREE $Sub$$__iar_dlfree 00233 #endif 00234 00235 /* Enable hooking of memory function only if tracing is also enabled */ 00236 #if defined(MBED_MEM_TRACING_ENABLED) || defined(MBED_HEAP_STATS_ENABLED) 00237 00238 extern "C" { 00239 void *SUPER_MALLOC(size_t size); 00240 void *SUPER_REALLOC(void *ptr, size_t size); 00241 void *SUPER_CALLOC(size_t nmemb, size_t size); 00242 void SUPER_FREE(void *ptr); 00243 } 00244 00245 extern "C" void* SUB_MALLOC(size_t size) { 00246 void *ptr = NULL; 00247 #ifdef MBED_HEAP_STATS_ENABLED 00248 malloc_stats_mutex->lock(); 00249 alloc_info_t *alloc_info = (alloc_info_t*)SUPER_MALLOC(size + sizeof(alloc_info_t)); 00250 if (alloc_info != NULL) { 00251 alloc_info->size = size; 00252 ptr = (void*)(alloc_info + 1); 00253 heap_stats.current_size += size; 00254 heap_stats.total_size += size; 00255 heap_stats.alloc_cnt += 1; 00256 if (heap_stats.current_size > heap_stats.max_size) { 00257 heap_stats.max_size = heap_stats.current_size; 00258 } 00259 } else { 00260 heap_stats.alloc_fail_cnt += 1; 00261 } 00262 malloc_stats_mutex->unlock(); 00263 #else // #ifdef MBED_HEAP_STATS_ENABLED 00264 ptr = SUPER_MALLOC(size); 00265 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00266 #ifdef MBED_MEM_TRACING_ENABLED 00267 mem_trace_mutex->lock(); 00268 mbed_mem_trace_malloc(ptr, size, MBED_CALLER_ADDR()); 00269 mem_trace_mutex->unlock(); 00270 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00271 return ptr; 00272 } 00273 00274 extern "C" void* SUB_REALLOC(void *ptr, size_t size) { 00275 void *new_ptr = NULL; 00276 #ifdef MBED_HEAP_STATS_ENABLED 00277 // Note - no lock needed since malloc and free are thread safe 00278 00279 // Get old size 00280 uint32_t old_size = 0; 00281 if (ptr != NULL) { 00282 alloc_info_t *alloc_info = ((alloc_info_t*)ptr) - 1; 00283 old_size = alloc_info->size; 00284 } 00285 00286 // Allocate space 00287 if (size != 0) { 00288 new_ptr = malloc(size); 00289 } 00290 00291 // If the new buffer has been allocated copy the data to it 00292 // and free the old buffer 00293 if (new_ptr != NULL) { 00294 uint32_t copy_size = (old_size < size) ? old_size : size; 00295 memcpy(new_ptr, (void*)ptr, copy_size); 00296 free(ptr); 00297 } 00298 #else // #ifdef MBED_HEAP_STATS_ENABLED 00299 new_ptr = SUPER_REALLOC(ptr, size); 00300 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00301 #ifdef MBED_MEM_TRACING_ENABLED 00302 mem_trace_mutex->lock(); 00303 mbed_mem_trace_realloc(new_ptr, ptr, size, MBED_CALLER_ADDR()); 00304 mem_trace_mutex->unlock(); 00305 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00306 return new_ptr; 00307 } 00308 00309 extern "C" void *SUB_CALLOC(size_t nmemb, size_t size) { 00310 void *ptr = NULL; 00311 #ifdef MBED_HEAP_STATS_ENABLED 00312 // Note - no lock needed since malloc is thread safe 00313 ptr = malloc(nmemb * size); 00314 if (ptr != NULL) { 00315 memset(ptr, 0, nmemb * size); 00316 } 00317 #else // #ifdef MBED_HEAP_STATS_ENABLED 00318 ptr = SUPER_CALLOC(nmemb, size); 00319 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00320 #ifdef MBED_MEM_TRACING_ENABLED 00321 mem_trace_mutex->lock(); 00322 mbed_mem_trace_calloc(ptr, nmemb, size, MBED_CALLER_ADDR()); 00323 mem_trace_mutex->unlock(); 00324 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00325 return ptr; 00326 } 00327 00328 extern "C" void SUB_FREE(void *ptr) { 00329 #ifdef MBED_HEAP_STATS_ENABLED 00330 malloc_stats_mutex->lock(); 00331 alloc_info_t *alloc_info = NULL; 00332 if (ptr != NULL) { 00333 alloc_info = ((alloc_info_t*)ptr) - 1; 00334 heap_stats.current_size -= alloc_info->size; 00335 heap_stats.alloc_cnt -= 1; 00336 } 00337 SUPER_FREE((void*)alloc_info); 00338 malloc_stats_mutex->unlock(); 00339 #else // #ifdef MBED_HEAP_STATS_ENABLED 00340 SUPER_FREE(ptr); 00341 #endif // #ifdef MBED_HEAP_STATS_ENABLED 00342 #ifdef MBED_MEM_TRACING_ENABLED 00343 mem_trace_mutex->lock(); 00344 mbed_mem_trace_free(ptr, MBED_CALLER_ADDR()); 00345 mem_trace_mutex->unlock(); 00346 #endif // #ifdef MBED_MEM_TRACING_ENABLED 00347 } 00348 00349 #endif // #if defined(MBED_MEM_TRACING_ENABLED) || defined(MBED_HEAP_STATS_ENABLED) 00350 00351 /******************************************************************************/ 00352 /* Allocation wrappers for other toolchains are not supported yet */ 00353 /******************************************************************************/ 00354 00355 #else 00356 00357 #ifdef MBED_MEM_TRACING_ENABLED 00358 #error Memory tracing is not supported with the current toolchain. 00359 #endif 00360 00361 #ifdef MBED_HEAP_STATS_ENABLED 00362 #error Heap statistics are not supported with the current toolchain. 00363 #endif 00364 00365 #endif // #if defined(TOOLCHAIN_GCC)
Generated on Tue Jul 12 2022 20:08:03 by
1.7.2
