16#include "pw_allocator/allocator.h"
17#include "pw_allocator/block.h"
18#include "pw_allocator/capability.h"
19#include "pw_allocator/fragmentation.h"
20#include "pw_bytes/span.h"
21#include "pw_result/result.h"
22#include "pw_status/status.h"
24namespace pw::allocator {
39 kImplementsGetRequestedLayout | kImplementsGetUsableLayout |
40 kImplementsGetAllocatedLayout | kImplementsGetCapacity |
41 kImplementsRecognizes;
78template <
typename OffsetType, u
int16_t kPoisonInterval, u
int16_t kAlign>
161 template <
typename PtrType,
162 typename BlockPtrType = std::conditional_t<
163 std::is_const_v<std::remove_pointer_t<PtrType>>,
186 void* DoAllocate(
Layout layout)
override;
189 void DoDeallocate(
void* ptr)
override;
192 void DoDeallocate(
void* ptr,
Layout)
override { DoDeallocate(ptr); }
195 bool DoResize(
void* ptr,
size_t new_size)
override;
198 Result<Layout> DoGetInfo(InfoType info_type,
const void* ptr)
const override;
210 virtual BlockType* ChooseBlock(Layout layout) = 0;
213 bool PrevIsFree(
const BlockType* block)
const {
214 return block->Prev() !=
nullptr && !block->Prev()->Used();
218 bool NextIsFree(
const BlockType* block)
const {
219 return !block->Last() && !block->Next()->Used();
224 void UpdateLast(BlockType* block);
227 size_t capacity_ = 0;
228 BlockType* first_ =
nullptr;
229 BlockType* last_ =
nullptr;
230 uint16_t unpoisoned_ = 0;
235template <
typename OffsetType, u
int16_t kPoisonInterval, u
int16_t kAlign>
236typename BlockAllocator<OffsetType, kPoisonInterval, kAlign>::Range
238 return Range(first_);
241template <
typename OffsetType, u
int16_t kPoisonInterval, u
int16_t kAlign>
242typename BlockAllocator<OffsetType, kPoisonInterval, kAlign>::ReverseRange
244 while (last_ !=
nullptr && !last_->Last()) {
245 last_ = last_->Next();
250template <
typename OffsetType, u
int16_t kPoisonInterval, u
int16_t kAlign>
253 Result<BlockType*> result = BlockType::Init(region);
254 Init(*result,
nullptr);
257template <
typename OffsetType, u
int16_t kPoisonInterval, u
int16_t kAlign>
260 PW_ASSERT(begin !=
nullptr);
261 if (end ==
nullptr) {
263 while (!end->
Last()) {
267 PW_ASSERT(begin < end);
272 for (
const auto& block : blocks()) {
277template <
typename OffsetType, u
int16_t kPoisonInterval, u
int16_t kAlign>
279 for (
auto* block : blocks()) {
281 CrashOnAllocated(block);
286template <
typename OffsetType, u
int16_t kPoisonInterval, u
int16_t kAlign>
289 BlockType* block = ChooseBlock(layout);
290 if (block ==
nullptr) {
294 return block->UsableSpace();
297template <
typename OffsetType, u
int16_t kPoisonInterval, u
int16_t kAlign>
298void BlockAllocator<OffsetType, kPoisonInterval, kAlign>::DoDeallocate(
300 auto result = FromUsableSpace(ptr);
302 CrashOnInvalidFree(ptr);
304 BlockType* block = *result;
305 if (!block->Used()) {
306 CrashOnDoubleFree(block);
310 if (PrevIsFree(block)) {
311 ReserveBlock(block->Prev());
313 if (NextIsFree(block)) {
314 ReserveBlock(block->Next());
318 BlockType::Free(block);
321 if constexpr (kPoisonInterval != 0) {
323 if (unpoisoned_ >= kPoisonInterval) {
332template <
typename OffsetType, u
int16_t kPoisonInterval, u
int16_t kAlign>
333bool BlockAllocator<OffsetType, kPoisonInterval, kAlign>::DoResize(
334 void* ptr,
size_t new_size) {
335 auto result = FromUsableSpace(ptr);
339 BlockType* block = *result;
342 if (NextIsFree(block)) {
343 ReserveBlock(block->Next());
346 if (!BlockType::Resize(block, new_size).ok()) {
351 if (NextIsFree(block)) {
352 RecycleBlock(block->Next());
358template <
typename OffsetType, u
int16_t kPoisonInterval, u
int16_t kAlign>
359Result<Layout> BlockAllocator<OffsetType, kPoisonInterval, kAlign>::DoGetInfo(
360 InfoType info_type,
const void* ptr)
const {
362 if (info_type == InfoType::kCapacity) {
363 return Layout(capacity_, kAlign);
366 auto result = FromUsableSpace(ptr);
368 return Status::NotFound();
370 const BlockType* block = result.value();
371 if (!block->Used()) {
372 return Status::FailedPrecondition();
375 case InfoType::kRequestedLayoutOf:
376 return Layout(block->RequestedSize(), block->Alignment());
377 case InfoType::kUsableLayoutOf:
378 return Layout(block->InnerSize(), block->Alignment());
379 case InfoType::kAllocatedLayoutOf:
380 return Layout(block->OuterSize(), block->Alignment());
381 case InfoType::kRecognizes:
383 case InfoType::kCapacity:
385 return Status::Unimplemented();
389template <
typename OffsetType, u
int16_t kPoisonInterval, u
int16_t kAlign>
394 for (
auto block : blocks()) {
395 if (!block->Used()) {
396 fragmentation.AddFragment(block->InnerSize() / BlockType::kAlignment);
399 return fragmentation;
402template <
typename OffsetType, u
int16_t kPoisonInterval, u
int16_t kAlign>
403template <
typename PtrType,
typename BlockPtrType>
407 if (ptr < first_->UsableSpace() || last_->UsableSpace() < ptr) {
408 return Status::OutOfRange();
410 BlockPtrType block = BlockType::FromUsableSpace(ptr);
411 block->CrashIfInvalid();
415template <
typename OffsetType, u
int16_t kPoisonInterval, u
int16_t kAlign>
420 }
else if (block->Next()->Last()) {
421 last_ = block->Next();
Definition: allocator.h:32
constexpr Allocator()=default
TODO(b/326509341): Remove when downstream consumers migrate.
Definition: block_allocator.h:79
Fragmentation MeasureFragmentation() const
Returns fragmentation information for the block allocator's memory region.
Definition: block_allocator.h:391
void Init(BlockType *begin)
Definition: block_allocator.h:116
virtual void Init(BlockType *begin, BlockType *end)
Definition: block_allocator.h:258
BlockAllocator(ByteSpan region)
Definition: block_allocator.h:93
constexpr BlockAllocator()
Constexpr constructor. Callers must explicitly call Init.
Definition: block_allocator.h:85
Result< BlockPtrType > FromUsableSpace(PtrType ptr) const
Definition: block_allocator.h:405
ReverseRange rblocks()
Definition: block_allocator.h:243
void Init(ByteSpan region)
Definition: block_allocator.h:251
Range blocks() const
Returns a Range of blocks tracking the memory of this allocator.
Definition: block_allocator.h:237
virtual void ReserveBlock(BlockType *)
Definition: block_allocator.h:174
virtual void RecycleBlock(BlockType *)
Definition: block_allocator.h:182
void Reset()
Definition: block_allocator.h:278
size_t OuterSize() const
Definition: block.h:162
void MarkLast()
Marks this block as the last one in the chain.
Definition: block.h:347
bool Last() const
Definition: block.h:338
Block * Next() const
Definition: block.h:796
Definition: capability.h:64
Definition: block_allocator.h:36
static void CrashOnDoubleFree(void *freed)
Crashes with an informational message that a given block was freed twice.
static void CrashOnInvalidFree(void *freed)
static void CrashOnAllocated(void *allocated)
Definition: fragmentation.h:44