mirror of
https://github.com/ArduPilot/ardupilot
synced 2025-02-25 17:23:56 -04:00
AP_Common: added MultiHeap class
for scripting allocation with multiple heaps
This commit is contained in:
parent
e96a55c1b6
commit
22a16f9672
143
libraries/AP_Common/MultiHeap.cpp
Normal file
143
libraries/AP_Common/MultiHeap.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
multiple heap interface, allowing for an allocator that uses
|
||||
multiple underlying heaps to cope with multiple memory regions on
|
||||
STM32 boards
|
||||
*/
|
||||
|
||||
#include <AP_HAL/AP_HAL.h>
|
||||
#include <AP_HAL/Util.h>
|
||||
#include <AP_Math/AP_Math.h>
|
||||
|
||||
#include "MultiHeap.h"
|
||||
|
||||
/*
|
||||
on ChibiOS allow up to 4 heaps. On other HALs only allow a single
|
||||
heap. This is needed as hal.util->heap_realloc() needs to have the
|
||||
property that heap_realloc(heap, ptr, 0) must not care if ptr comes
|
||||
from the given heap. This is true on ChibiOS, but is not true on
|
||||
other HALs
|
||||
*/
|
||||
#ifndef MAX_HEAPS
|
||||
#if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS
|
||||
#define MAX_HEAPS 4
|
||||
#else
|
||||
#define MAX_HEAPS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern const AP_HAL::HAL &hal;
|
||||
|
||||
/*
|
||||
create heaps with a total memory size, splitting over at most
|
||||
max_heaps
|
||||
*/
|
||||
bool MultiHeap::create(uint32_t total_size, uint8_t max_heaps)
|
||||
{
|
||||
max_heaps = MIN(MAX_HEAPS, max_heaps);
|
||||
if (heaps != nullptr) {
|
||||
// don't allow double allocation
|
||||
return false;
|
||||
}
|
||||
heaps = new void*[max_heaps];
|
||||
if (heaps == nullptr) {
|
||||
return false;
|
||||
}
|
||||
num_heaps = max_heaps;
|
||||
for (uint8_t i=0; i<max_heaps; i++) {
|
||||
uint32_t alloc_size = total_size;
|
||||
while (alloc_size > 0) {
|
||||
heaps[i] = hal.util->allocate_heap_memory(alloc_size);
|
||||
if (heaps[i] != nullptr) {
|
||||
total_size -= alloc_size;
|
||||
break;
|
||||
}
|
||||
alloc_size *= 0.9;
|
||||
}
|
||||
if (total_size == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (total_size != 0) {
|
||||
destroy();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// destroy heap
|
||||
void MultiHeap::destroy(void)
|
||||
{
|
||||
if (!available()) {
|
||||
return;
|
||||
}
|
||||
for (uint8_t i=0; i<num_heaps; i++) {
|
||||
if (heaps[i] != nullptr) {
|
||||
free(heaps[i]);
|
||||
heaps[i] = nullptr;
|
||||
}
|
||||
}
|
||||
delete[] heaps;
|
||||
heaps = nullptr;
|
||||
num_heaps = 0;
|
||||
}
|
||||
|
||||
// return true if heap is available for operations
|
||||
bool MultiHeap::available(void) const
|
||||
{
|
||||
return heaps != nullptr && heaps[0] != nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
allocate memory from a heap
|
||||
*/
|
||||
void *MultiHeap::allocate(uint32_t size)
|
||||
{
|
||||
if (!available()) {
|
||||
return nullptr;
|
||||
}
|
||||
for (uint8_t i=0; i<num_heaps; i++) {
|
||||
if (heaps[i] == nullptr) {
|
||||
break;
|
||||
}
|
||||
void *newptr = hal.util->heap_realloc(heaps[i], nullptr, 0, size);
|
||||
if (newptr != nullptr) {
|
||||
return newptr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
free memory from a heap
|
||||
*/
|
||||
void MultiHeap::deallocate(void *ptr)
|
||||
{
|
||||
if (!available()) {
|
||||
return;
|
||||
}
|
||||
// NOTE! this relies on either there being a single heap or heap_realloc()
|
||||
// not using the first argument when size is zero.
|
||||
hal.util->heap_realloc(heaps[0], ptr, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
change size of an allocation
|
||||
*/
|
||||
void *MultiHeap::change_size(void *ptr, uint32_t old_size, uint32_t new_size)
|
||||
{
|
||||
if (new_size == 0) {
|
||||
deallocate(ptr);
|
||||
return nullptr;
|
||||
}
|
||||
if (old_size == 0 || ptr == nullptr) {
|
||||
return allocate(new_size);
|
||||
}
|
||||
/*
|
||||
we cannot know which heap this came from, so we rely on the fact
|
||||
that on ChibiOS the underlying call doesn't use the heap
|
||||
argument and on other HALs we only have one heap. We pass
|
||||
through old_size and new_size so that we can validate the lua
|
||||
old_size value
|
||||
*/
|
||||
return hal.util->heap_realloc(heaps[0], ptr, old_size, new_size);
|
||||
}
|
29
libraries/AP_Common/MultiHeap.h
Normal file
29
libraries/AP_Common/MultiHeap.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
multiple heap interface, allowing for an allocator that uses
|
||||
multiple underlying heaps to cope with multiple memory regions on
|
||||
STM32 boards
|
||||
*/
|
||||
|
||||
class MultiHeap {
|
||||
public:
|
||||
/*
|
||||
allocate/deallocate heaps
|
||||
*/
|
||||
bool create(uint32_t total_size, uint8_t max_heaps);
|
||||
void destroy(void);
|
||||
|
||||
// return true if the heap is available for operations
|
||||
bool available(void) const;
|
||||
|
||||
// allocate memory within heaps
|
||||
void *allocate(uint32_t size);
|
||||
void deallocate(void *ptr);
|
||||
|
||||
// change allocated size of a pointer - this requires the old
|
||||
// size, unlike realloc()
|
||||
void *change_size(void *ptr, uint32_t old_size, uint32_t new_size);
|
||||
|
||||
private:
|
||||
uint8_t num_heaps;
|
||||
void **heaps;
|
||||
};
|
Loading…
Reference in New Issue
Block a user