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