mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

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