Nicolas Borla / Mbed OS BBR_1Ebene
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_alloc_wrappers.cpp Source File

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     return malloc_wrapper(r, size, MBED_CALLER_ADDR());
00093 }
00094 
00095 extern "C" void * malloc_wrapper(struct _reent * r, size_t size, void * caller) {
00096     void *ptr = NULL;
00097 #ifdef MBED_MEM_TRACING_ENABLED
00098     mbed_mem_trace_lock();
00099 #endif
00100 #ifdef MBED_HEAP_STATS_ENABLED
00101     malloc_stats_mutex->lock();
00102     alloc_info_t *alloc_info = (alloc_info_t*)__real__malloc_r(r, size + sizeof(alloc_info_t));
00103     if (alloc_info != NULL) {
00104         alloc_info->size = size;
00105         ptr = (void*)(alloc_info + 1);
00106         heap_stats.current_size += size;
00107         heap_stats.total_size += size;
00108         heap_stats.alloc_cnt += 1;
00109         if (heap_stats.current_size > heap_stats.max_size) {
00110             heap_stats.max_size = heap_stats.current_size;
00111         }
00112     } else {
00113         heap_stats.alloc_fail_cnt += 1;
00114     }
00115     malloc_stats_mutex->unlock();
00116 #else // #ifdef MBED_HEAP_STATS_ENABLED
00117     ptr = __real__malloc_r(r, size);
00118 #endif // #ifdef MBED_HEAP_STATS_ENABLED
00119 #ifdef MBED_MEM_TRACING_ENABLED
00120     mbed_mem_trace_malloc(ptr, size, caller);
00121     mbed_mem_trace_unlock();
00122 #endif // #ifdef MBED_MEM_TRACING_ENABLED
00123     return ptr;
00124 }
00125 
00126 extern "C" void * __wrap__realloc_r(struct _reent * r, void * ptr, size_t size) {
00127     void *new_ptr = NULL;
00128 #ifdef MBED_MEM_TRACING_ENABLED
00129     mbed_mem_trace_lock();
00130 #endif
00131 #ifdef MBED_HEAP_STATS_ENABLED
00132     // Implement realloc_r with malloc and free.
00133     // The function realloc_r can't be used here directly since
00134     // it can call into __wrap__malloc_r (returns ptr + 4) or
00135     // resize memory directly (returns ptr + 0).
00136 
00137     // Note - no lock needed since malloc and free are thread safe
00138 
00139     // Get old size
00140     uint32_t old_size = 0;
00141     if (ptr != NULL) {
00142         alloc_info_t *alloc_info = ((alloc_info_t*)ptr) - 1;
00143         old_size = alloc_info->size;
00144     }
00145 
00146     // Allocate space
00147     if (size != 0) {
00148         new_ptr = malloc(size);
00149     }
00150 
00151     // If the new buffer has been allocated copy the data to it
00152     // and free the old buffer
00153     if (new_ptr != NULL) {
00154         uint32_t copy_size = (old_size < size) ? old_size : size;
00155         memcpy(new_ptr, (void*)ptr, copy_size);
00156         free(ptr);
00157     }
00158 #else // #ifdef MBED_HEAP_STATS_ENABLED
00159     new_ptr = __real__realloc_r(r, ptr, size);
00160 #endif // #ifdef MBED_HEAP_STATS_ENABLED
00161 #ifdef MBED_MEM_TRACING_ENABLED
00162     mbed_mem_trace_realloc(new_ptr, ptr, size, MBED_CALLER_ADDR());
00163     mbed_mem_trace_unlock();
00164 #endif // #ifdef MBED_MEM_TRACING_ENABLED
00165     return new_ptr;
00166 }
00167 
00168 extern "C" void __wrap__free_r(struct _reent * r, void * ptr) {
00169     free_wrapper(r, ptr, MBED_CALLER_ADDR());
00170 }
00171 
00172 extern "C" void free_wrapper(struct _reent * r, void * ptr, void * caller) {
00173 #ifdef MBED_MEM_TRACING_ENABLED
00174     mbed_mem_trace_lock();
00175 #endif
00176 #ifdef MBED_HEAP_STATS_ENABLED
00177     malloc_stats_mutex->lock();
00178     alloc_info_t *alloc_info = NULL;
00179     if (ptr != NULL) {
00180         alloc_info = ((alloc_info_t*)ptr) - 1;
00181         heap_stats.current_size -= alloc_info->size;
00182         heap_stats.alloc_cnt -= 1;
00183     }
00184     __real__free_r(r, (void*)alloc_info);
00185     malloc_stats_mutex->unlock();
00186 #else // #ifdef MBED_HEAP_STATS_ENABLED
00187     __real__free_r(r, ptr);
00188 #endif // #ifdef MBED_HEAP_STATS_ENABLED
00189 #ifdef MBED_MEM_TRACING_ENABLED
00190     mbed_mem_trace_free(ptr, caller);
00191     mbed_mem_trace_unlock();
00192 #endif // #ifdef MBED_MEM_TRACING_ENABLED
00193 }
00194 
00195 extern "C" void * __wrap__calloc_r(struct _reent * r, size_t nmemb, size_t size) {
00196     void *ptr = NULL;
00197 #ifdef MBED_MEM_TRACING_ENABLED
00198     mbed_mem_trace_lock();
00199 #endif
00200 #ifdef MBED_HEAP_STATS_ENABLED
00201     // Note - no lock needed since malloc is thread safe
00202 
00203     ptr = malloc(nmemb * size);
00204     if (ptr != NULL) {
00205         memset(ptr, 0, nmemb * size);
00206     }
00207 #else // #ifdef MBED_HEAP_STATS_ENABLED
00208     ptr = __real__calloc_r(r, nmemb, size);
00209 #endif // #ifdef MBED_HEAP_STATS_ENABLED
00210 #ifdef MBED_MEM_TRACING_ENABLED
00211     mbed_mem_trace_calloc(ptr, nmemb, size, MBED_CALLER_ADDR());
00212     mbed_mem_trace_unlock();
00213 #endif // #ifdef MBED_MEM_TRACING_ENABLED
00214     return ptr;
00215 }
00216 
00217 extern "C" void * __wrap__memalign_r(struct _reent * r, size_t alignment, size_t bytes) {
00218     return __real__memalign_r(r, alignment, bytes);
00219 }
00220 
00221 #endif // if !defined(FEATURE_UVISOR)
00222 
00223 
00224 /******************************************************************************/
00225 /* ARMCC / IAR memory allocation wrappers                                     */
00226 /******************************************************************************/
00227 
00228 #elif defined(TOOLCHAIN_ARM) || defined(__ICCARM__)
00229 
00230 #if defined(TOOLCHAIN_ARM)
00231 #define SUPER_MALLOC    $Super$$malloc
00232 #define SUB_MALLOC      $Sub$$malloc
00233 #define SUPER_REALLOC   $Super$$realloc
00234 #define SUB_REALLOC     $Sub$$realloc
00235 #define SUPER_CALLOC    $Super$$calloc
00236 #define SUB_CALLOC      $Sub$$calloc
00237 #define SUPER_FREE      $Super$$free
00238 #define SUB_FREE        $Sub$$free
00239 #elif defined(__ICCARM__)
00240 #define SUPER_MALLOC    $Super$$__iar_dlmalloc
00241 #define SUB_MALLOC      $Sub$$__iar_dlmalloc
00242 #define SUPER_REALLOC   $Super$$__iar_dlrealloc
00243 #define SUB_REALLOC     $Sub$$__iar_dlrealloc
00244 #define SUPER_CALLOC    $Super$$__iar_dlcalloc
00245 #define SUB_CALLOC      $Sub$$__iar_dlcalloc
00246 #define SUPER_FREE      $Super$$__iar_dlfree
00247 #define SUB_FREE        $Sub$$__iar_dlfree
00248 #endif
00249 
00250 /* Enable hooking of memory function only if tracing is also enabled */
00251 #if defined(MBED_MEM_TRACING_ENABLED) || defined(MBED_HEAP_STATS_ENABLED)
00252 
00253 extern "C" {
00254     void *SUPER_MALLOC(size_t size);
00255     void *SUPER_REALLOC(void *ptr, size_t size);
00256     void *SUPER_CALLOC(size_t nmemb, size_t size);
00257     void SUPER_FREE(void *ptr);
00258     void *malloc_wrapper(size_t size, void* caller);
00259     void free_wrapper(void *ptr, void* caller);
00260 }
00261 
00262 
00263 extern "C" void* SUB_MALLOC(size_t size) {
00264     return malloc_wrapper(size, MBED_CALLER_ADDR());
00265 }
00266 
00267 extern "C" void* malloc_wrapper(size_t size, void* caller) {
00268     void *ptr = NULL;
00269 #ifdef MBED_MEM_TRACING_ENABLED
00270     mbed_mem_trace_lock();
00271 #endif
00272 #ifdef MBED_HEAP_STATS_ENABLED
00273     malloc_stats_mutex->lock();
00274     alloc_info_t *alloc_info = (alloc_info_t*)SUPER_MALLOC(size + sizeof(alloc_info_t));
00275     if (alloc_info != NULL) {
00276         alloc_info->size = size;
00277         ptr = (void*)(alloc_info + 1);
00278         heap_stats.current_size += size;
00279         heap_stats.total_size += size;
00280         heap_stats.alloc_cnt += 1;
00281         if (heap_stats.current_size > heap_stats.max_size) {
00282             heap_stats.max_size = heap_stats.current_size;
00283         }
00284     } else {
00285         heap_stats.alloc_fail_cnt += 1;
00286     }
00287     malloc_stats_mutex->unlock();
00288 #else // #ifdef MBED_HEAP_STATS_ENABLED
00289     ptr = SUPER_MALLOC(size);
00290 #endif // #ifdef MBED_HEAP_STATS_ENABLED
00291 #ifdef MBED_MEM_TRACING_ENABLED
00292     mbed_mem_trace_malloc(ptr, size, caller);
00293     mbed_mem_trace_unlock();
00294 #endif // #ifdef MBED_MEM_TRACING_ENABLED
00295     return ptr;
00296 }
00297 
00298 
00299 extern "C" void* SUB_REALLOC(void *ptr, size_t size) {
00300     void *new_ptr = NULL;
00301 #ifdef MBED_MEM_TRACING_ENABLED
00302     mbed_mem_trace_lock();
00303 #endif
00304 #ifdef MBED_HEAP_STATS_ENABLED
00305     // Note - no lock needed since malloc and free are thread safe
00306 
00307     // Get old size
00308     uint32_t old_size = 0;
00309     if (ptr != NULL) {
00310         alloc_info_t *alloc_info = ((alloc_info_t*)ptr) - 1;
00311         old_size = alloc_info->size;
00312     }
00313 
00314     // Allocate space
00315     if (size != 0) {
00316         new_ptr = malloc(size);
00317     }
00318 
00319     // If the new buffer has been allocated copy the data to it
00320     // and free the old buffer
00321     if (new_ptr != NULL) {
00322         uint32_t copy_size = (old_size < size) ? old_size : size;
00323         memcpy(new_ptr, (void*)ptr, copy_size);
00324         free(ptr);
00325     }
00326 #else // #ifdef MBED_HEAP_STATS_ENABLED
00327     new_ptr = SUPER_REALLOC(ptr, size);
00328 #endif // #ifdef MBED_HEAP_STATS_ENABLED
00329 #ifdef MBED_MEM_TRACING_ENABLED
00330     mbed_mem_trace_realloc(new_ptr, ptr, size, MBED_CALLER_ADDR());
00331     mbed_mem_trace_unlock();
00332 #endif // #ifdef MBED_MEM_TRACING_ENABLED
00333     return new_ptr;
00334 }
00335 
00336 extern "C" void *SUB_CALLOC(size_t nmemb, size_t size) {
00337     void *ptr = NULL;
00338 #ifdef MBED_MEM_TRACING_ENABLED
00339     mbed_mem_trace_lock();
00340 #endif
00341 #ifdef MBED_HEAP_STATS_ENABLED
00342     // Note - no lock needed since malloc is thread safe
00343     ptr = malloc(nmemb * size);
00344     if (ptr != NULL) {
00345         memset(ptr, 0, nmemb * size);
00346     }
00347 #else // #ifdef MBED_HEAP_STATS_ENABLED
00348     ptr = SUPER_CALLOC(nmemb, size);
00349 #endif // #ifdef MBED_HEAP_STATS_ENABLED
00350 #ifdef MBED_MEM_TRACING_ENABLED
00351     mbed_mem_trace_calloc(ptr, nmemb, size, MBED_CALLER_ADDR());
00352     mbed_mem_trace_unlock();
00353 #endif // #ifdef MBED_MEM_TRACING_ENABLED
00354     return ptr;
00355 }
00356 
00357 extern "C" void SUB_FREE(void *ptr) {
00358     free_wrapper(ptr, MBED_CALLER_ADDR());
00359 }
00360 
00361 extern "C" void free_wrapper(void *ptr, void* caller) {
00362 #ifdef MBED_MEM_TRACING_ENABLED
00363     mbed_mem_trace_lock();
00364 #endif
00365 #ifdef MBED_HEAP_STATS_ENABLED
00366     malloc_stats_mutex->lock();
00367     alloc_info_t *alloc_info = NULL;
00368     if (ptr != NULL) {
00369         alloc_info = ((alloc_info_t*)ptr) - 1;
00370         heap_stats.current_size -= alloc_info->size;
00371         heap_stats.alloc_cnt -= 1;
00372     }
00373     SUPER_FREE((void*)alloc_info);
00374     malloc_stats_mutex->unlock();
00375 #else // #ifdef MBED_HEAP_STATS_ENABLED
00376     SUPER_FREE(ptr);
00377 #endif // #ifdef MBED_HEAP_STATS_ENABLED
00378 #ifdef MBED_MEM_TRACING_ENABLED
00379     mbed_mem_trace_free(ptr, caller);
00380     mbed_mem_trace_unlock();
00381 #endif // #ifdef MBED_MEM_TRACING_ENABLED
00382 }
00383 
00384 #endif // #if defined(MBED_MEM_TRACING_ENABLED) || defined(MBED_HEAP_STATS_ENABLED)
00385 
00386 /******************************************************************************/
00387 /* Allocation wrappers for other toolchains are not supported yet             */
00388 /******************************************************************************/
00389 
00390 #else
00391 
00392 #ifdef MBED_MEM_TRACING_ENABLED
00393 #error Memory tracing is not supported with the current toolchain.
00394 #endif
00395 
00396 #ifdef MBED_HEAP_STATS_ENABLED
00397 #error Heap statistics are not supported with the current toolchain.
00398 #endif
00399 
00400 #endif // #if defined(TOOLCHAIN_GCC)