Changes to support running on smaller memory LPC device LPC1764

Fork of mbed-dev by mbed official

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 "mbed_mem_trace.h"
00018 #include "mbed_stats.h"
00019 #include "toolchain.h"
00020 #include "SingletonPtr.h"
00021 #include "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