LCOV - code coverage report
Current view: top level - AP_MultiHeap - AP_MultiHeap.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 61 97 62.9 %
Date: 2026-09-09 11:02:08 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :   multiple heap interface, allowing for an allocator that uses
       3             :   multiple underlying heaps to cope with multiple memory regions on
       4             :   STM32 boards
       5             :  */
       6             : 
       7             : #include "AP_MultiHeap.h"
       8             : 
       9             : #include <AP_Math/AP_Math.h>
      10             : #include <AP_Scripting/AP_Scripting_config.h>
      11             : #include <stdio.h>
      12             : 
      13             : /*
      14             :   allow up to 10 heaps
      15             :  */
      16             : #ifndef MAX_HEAPS
      17             : #define MAX_HEAPS 10
      18             : #endif
      19             : 
      20             : extern const AP_HAL::HAL &hal;
      21             : 
      22             : /*
      23             :   create heaps with a total memory size, splitting over at most
      24             :   max_heaps
      25             :  */
      26          99 : bool MultiHeap::create(uint32_t total_size, uint8_t max_heaps, bool _allow_expansion, uint32_t _reserve_size)
      27             : {
      28          99 :     max_heaps = MIN(MAX_HEAPS, max_heaps);
      29          99 :     if (heaps != nullptr) {
      30             :         // don't allow double allocation
      31           0 :         return false;
      32             :     }
      33          99 :     heaps = NEW_NOTHROW Heap[max_heaps];
      34          99 :     if (heaps == nullptr) {
      35           0 :         return false;
      36             :     }
      37          99 :     num_heaps = max_heaps;
      38          99 :     for (uint8_t i=0; i<max_heaps; i++) {
      39          99 :         uint32_t alloc_size = total_size;
      40          99 :         while (alloc_size > 0) {
      41          99 :             heaps[i].hp = heap_create(alloc_size);
      42          99 :             if (heaps[i].hp != nullptr) {
      43          99 :                 total_size -= alloc_size;
      44          99 :                 sum_size += alloc_size;
      45          99 :                 break;
      46             :             }
      47           0 :             alloc_size *= 0.9;
      48             :         }
      49          99 :         if (total_size == 0) {
      50          99 :             break;
      51             :         }
      52             :     }
      53          99 :     if (total_size != 0) {
      54           0 :         destroy();
      55           0 :         return false;
      56             :     }
      57             : 
      58          99 :     allow_expansion = _allow_expansion;
      59          99 :     reserve_size = _reserve_size;
      60             : 
      61          99 :     return true;
      62             : }
      63             : 
      64             : // destroy heap
      65          58 : void MultiHeap::destroy(void)
      66             : {
      67          58 :     if (!available()) {
      68           0 :         return;
      69             :     }
      70         638 :     for (uint8_t i=0; i<num_heaps; i++) {
      71         580 :         if (heaps[i].hp != nullptr) {
      72          58 :             heap_destroy(heaps[i].hp);
      73          58 :             heaps[i].hp = nullptr;
      74             :         }
      75             :     }
      76          58 :     delete[] heaps;
      77          58 :     heaps = nullptr;
      78          58 :     num_heaps = 0;
      79          58 :     sum_size = 0;
      80          58 :     expanded_to = 0;
      81             : }
      82             : 
      83             : // return true if heap is available for operations
      84     3880159 : bool MultiHeap::available(void) const
      85             : {
      86     3880159 :     return heaps != nullptr && heaps[0].hp != nullptr;
      87             : }
      88             : 
      89             : /*
      90             :   allocate memory from a heap
      91             :  */
      92     1924493 : void *MultiHeap::allocate(uint32_t size)
      93             : {
      94     1924493 :     if (!available() || size == 0) {
      95          12 :         return nullptr;
      96             :     }
      97     1924484 :     for (uint8_t i=0; i<num_heaps; i++) {
      98     1924484 :         if (heaps[i].hp == nullptr) {
      99           3 :             break;
     100             :         }
     101     1924481 :         void *newptr = heap_allocate(heaps[i].hp, size);
     102     1924481 :         if (newptr != nullptr) {
     103     1924478 :             last_failed = false;
     104     1924478 :             return newptr;
     105             :         }
     106             :     }
     107           3 :     if (!allow_expansion || !last_failed) {
     108             :         /*
     109             :           we only allow expansion when the last allocation
     110             :           failed. This gives the lua engine a chance to use garbage
     111             :           collection to recover memory
     112             :          */
     113           3 :         last_failed = true;
     114           3 :         return nullptr;
     115             :     }
     116             : 
     117             : #if !AP_SCRIPTING_HEAP_EXPANSION_ALWAYS_ENABLED
     118           0 :     if (!hal.util->get_soft_armed()) {
     119             :         // only expand the available heaps when armed. When disarmed
     120             :         // user should fix their SCR_HEAP_SIZE parameter
     121           0 :         last_failed = true;
     122           0 :         return nullptr;
     123             :     }
     124             : #endif
     125             : 
     126             :     /*
     127             :       MultiHeap (for scripting) is out of memory. We will see if we
     128             :       can add a new heap from available memory if we have at least
     129             :       reserve_size bytes free
     130             :      */
     131           0 :     const uint32_t available = hal.util->available_memory();
     132           0 :     const uint32_t heap_overhead = 128; // conservative value, varies with HAL
     133           0 :     const uint32_t min_size = size + heap_overhead;
     134           0 :     if (available < reserve_size+min_size) {
     135           0 :         last_failed = true;
     136           0 :         return nullptr;
     137             :     }
     138             : 
     139             :     // round up to a minimum of 30k to allocate, and allow for heap overhead
     140           0 :     const uint32_t round_to = 30*1024U;
     141           0 :     const uint32_t alloc_size = MIN(available - reserve_size, MAX(size+heap_overhead, round_to));
     142           0 :     if (alloc_size < min_size) {
     143           0 :         last_failed = true;
     144           0 :         return nullptr;
     145             :     }
     146           0 :     for (uint8_t i=0; i<num_heaps; i++) {
     147           0 :         if (heaps[i].hp == nullptr) {
     148           0 :             heaps[i].hp = heap_create(alloc_size);
     149           0 :             if (heaps[i].hp == nullptr) {
     150           0 :                 last_failed = true;
     151           0 :                 return nullptr;
     152             :             }
     153           0 :             sum_size += alloc_size;
     154           0 :             expanded_to = sum_size;
     155           0 :             void *p = heap_allocate(heaps[i].hp, size);
     156           0 :             last_failed = p == nullptr;
     157           0 :             return p;
     158             :         }
     159             :     }
     160           0 :     last_failed = true;
     161           0 :     return nullptr;
     162             : }
     163             : 
     164             : /*
     165             :   free memory from a heap
     166             :  */
     167     1955412 : void MultiHeap::deallocate(void *ptr)
     168             : {
     169     1955412 :     if (!available() || ptr == nullptr) {
     170       54774 :         return;
     171             :     }
     172     1900638 :     heap_free(ptr);
     173             : }
     174             : 
     175             : /*
     176             :   change size of an allocation, operates like realloc(), but requires
     177             :   the old_size when ptr is not NULL
     178             :  */
     179     3649875 : void *MultiHeap::change_size(void *ptr, uint32_t old_size, uint32_t new_size)
     180             : {
     181     3649875 :     if (new_size == 0) {
     182     1727613 :         deallocate(ptr);
     183     1727613 :         return nullptr;
     184             :     }
     185             :     /*
     186             :       we don't want to require the underlying allocation system to
     187             :       support realloc() and we also want to be able to handle the case
     188             :       of having to move the allocation to a new heap, so we do a
     189             :       simple alloc/copy/deallocate for reallocation
     190             :      */
     191     1922262 :     void *newp = allocate(new_size);
     192     1922262 :     if (ptr == nullptr) {
     193     1696586 :         return newp;
     194             :     }
     195      225676 :     if (newp == nullptr) {
     196           0 :         if (old_size >= new_size) {
     197             :             // Lua assumes that the allocator never fails when osize >= nsize
     198             :             // the best we can do is return the old pointer
     199           0 :             return ptr;
     200             :         }
     201           0 :         return nullptr;
     202             :     }
     203      225676 :     memcpy(newp, ptr, MIN(old_size, new_size));
     204      225676 :     deallocate(ptr);
     205      225676 :     return newp;
     206             : }

Generated by: LCOV version 1.14