added ability to merge heaps

This commit is contained in:
2026-06-09 23:48:56 +02:00
parent a5fe68867f
commit 9dd2ebaa5a
3 changed files with 91 additions and 30 deletions

View File

@@ -1,4 +1,4 @@
/* Version 1.5 */
/* Version 1.6 */
#ifndef __MINIMAL_HEAP_H__
#define __MINIMAL_HEAP_H__
@@ -44,7 +44,7 @@ typedef bool (MIHP_PlatformFreeMemoryFn)(const struct _MIHP_Heap* heap, void* pt
#define MIHP_HEAP_CORRUPTION_TYPE_SEGMENT_CHECKSUM_MISMATCH 1
#define MIHP_HEAP_CORRUPTION_TYPE_DOUBLE_FREE 2
typedef void (MIHP_OnHeapCorruptionDetectedFn)(const struct _MIHP_Heap* heap, struct _MIHP_HeapCorruptionInfo);
typedef void (MIHP_OnHeapCorruptionDetectedFn)(const struct _MIHP_Heap* heap, struct _MIHP_HeapCorruptionInfo corruptionInfo);
typedef void(MIHIP_LockHeapFn)(const struct _MIHP_Heap* heap, void* heapLock);
typedef void(MIHIP_UnlockHeapFn)(const struct _MIHP_Heap* heap, void* heapLock);
@@ -84,8 +84,9 @@ typedef struct _MIHP_HeapMemoryAreaHeader
struct _MIHP_HeapMemoryAreaHeader* NextArea;
struct _MIHP_HeapMemoryAreaHeader* PreviousArea;
struct _MIHP_Heap* OwningHeap;
struct _MIHP_HeapSegmentHeader* FirstSegment;
struct _MIHP_HeapSegmentHeader* FirstSegment;
const struct _MIHP_Heap* InstigatingHeap; // Heap that created this area. May not always be the owning heap (in case of a merge) or safe to deference!
uint32_t Checksum; // Checksum must be the last member !
} MIHP_HeapMemoryAreaHeader;
@@ -131,6 +132,8 @@ void* MIHP_Allocate(MIHP_Heap* heap, size_t size);
void* MIHP_Reallocate(MIHP_Heap* heap, void* ptr, size_t newSize);
bool MIHP_Free(MIHP_Heap* heap, void* ptr);
bool MIHP_MergeHeaps(MIHP_Heap* sourceHeap, MIHP_Heap* heapToAbsorb);
bool MIHP_IsPointerInHeap(MIHP_Heap* heap, void* ptr);
size_t MIHP_GetPtrAllocationSize(MIHP_Heap* heap, void* ptr);
void MIHP_ValidateHeap(MIHP_Heap* heap);
@@ -143,11 +146,11 @@ void MIHP_UnlockHeap(MIHP_Heap* heap);
MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_Heap* heap, size_t requestedSize);
bool MIHP_DestroyHeapMemoryArea(MIHP_Heap* heap, MIHP_HeapMemoryAreaHeader* area);
MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_HeapMemoryAreaHeader* area, void* segmentStart, size_t size);
bool MIHP_UninitializeHeapSegment(MIHP_HeapSegmentHeader* segment);
MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_Heap* heap, MIHP_HeapMemoryAreaHeader* area, void* segmentStart, size_t size);
bool MIHP_UninitializeHeapSegment(MIHP_Heap* heap, MIHP_HeapSegmentHeader* segment);
bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentSize, MIHP_HeapSegmentHeader** outNewSegment);
bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegmentHeader* segmentToAbsorb);
bool MIHP_SplitHeapSegment(MIHP_Heap* heap, MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentSize, MIHP_HeapSegmentHeader** outNewSegment);
bool MIHP_MergeHeapSegments(MIHP_Heap* heap, MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegmentHeader* segmentToAbsorb);
void* MIHP_GetSegmentPayloadPtr(MIHP_Heap* heap, MIHP_HeapSegmentHeader* segment);
MIHP_HeapSegmentHeader* MIHP_GetSegmentHeaderPtr(MIHP_Heap* heap, void* payloadPtr);

View File

@@ -131,7 +131,7 @@ void* MIHP_Allocate(MIHP_Heap* heap, size_t size)
MIHP_HeapSegmentHeader* targetSegment = NULL;
if (currentSegment->SegmentSize >= 2 * segmentHeaderSize + size + MIHP_GetMinimalPayloadSize(heap))
MIHP_SplitHeapSegment(currentSegment, segmentHeaderSize + size, &targetSegment);
MIHP_SplitHeapSegment(heap, currentSegment, segmentHeaderSize + size, &targetSegment);
else if (currentSegment->SegmentSize >= segmentHeaderSize + size)
targetSegment = currentSegment;
else
@@ -217,7 +217,7 @@ void* MIHP_Reallocate(MIHP_Heap* heap, void* ptr, size_t newSize)
return ptr;
}
if (segment->NextSegment && MIHP_MergeHeapSegments(segment, segment->NextSegment))
if (segment->NextSegment && MIHP_MergeHeapSegments(heap, segment, segment->NextSegment))
{
MIHP_UnlockHeap(heap);
return MIHP_Reallocate(heap, ptr, newSize);
@@ -246,9 +246,9 @@ void* MIHP_Reallocate(MIHP_Heap* heap, void* ptr, size_t newSize)
size_t newSplitSegmentSize = segment->SegmentSize - segmentHeaderSize - alignedNewSize;
MIHP_HeapSegmentHeader* newSpittedSegment = NULL;
MIHP_SplitHeapSegment(segment, newSplitSegmentSize, &newSpittedSegment);
MIHP_SplitHeapSegment(heap, segment, newSplitSegmentSize, &newSpittedSegment);
if (newSpittedSegment && newSpittedSegment->NextSegment)
MIHP_MergeHeapSegments(newSpittedSegment, newSpittedSegment->NextSegment);
MIHP_MergeHeapSegments(heap, newSpittedSegment, newSpittedSegment->NextSegment);
}
MIHP_UnlockHeap(heap);
@@ -333,20 +333,78 @@ bool MIHP_Free(MIHP_Heap* heap, void* ptr)
{
MIHP_ValidateHeapSegmentHeader(heap, segment->NextSegment);
if (segment->NextSegment->OccupiedSize == 0)
MIHP_MergeHeapSegments(segment, segment->NextSegment);
MIHP_MergeHeapSegments(heap, segment, segment->NextSegment);
}
if (segment->PreviousSegment)
{
MIHP_ValidateHeapSegmentHeader(heap, segment->PreviousSegment);
if (segment->PreviousSegment->OccupiedSize == 0)
MIHP_MergeHeapSegments(segment->PreviousSegment, segment);
MIHP_MergeHeapSegments(heap, segment->PreviousSegment, segment);
}
MIHP_UnlockHeap(heap);
return true;
}
bool MIHP_MergeHeaps(MIHP_Heap* sourceHeap, MIHP_Heap* heapToAbsorb)
{
if (sourceHeap == NULL)
return false;
if (heapToAbsorb == NULL)
return false;
if (!MIHP_IsHeapInitialized(sourceHeap))
return false;
if (!MIHP_IsHeapInitialized(heapToAbsorb))
return false;
if (sourceHeap->Config.PlatformFreeMemoryFn != heapToAbsorb->Config.PlatformFreeMemoryFn)
return false;
if (sourceHeap->Config.AllocationAlignment != heapToAbsorb->Config.AllocationAlignment)
return false;
if (sourceHeap->Config.MinimalMemoryAreaSize > heapToAbsorb->Config.MinimalMemoryAreaSize)
return false;
if (sourceHeap->Config.MaximalMemoryAreaSize < heapToAbsorb->Config.MaximalMemoryAreaSize)
return false;
MIHP_LockHeap(sourceHeap);
MIHP_LockHeap(heapToAbsorb);
MIHP_HeapMemoryAreaHeader* sourceEndArea = sourceHeap->FirstArea;
while (true)
{
MIHP_ValidateHeapMemoryAreaHeader(sourceHeap, sourceEndArea);
if (sourceEndArea->NextArea == NULL)
break;
sourceEndArea = sourceEndArea->NextArea;
}
sourceEndArea->NextArea = heapToAbsorb->FirstArea;
heapToAbsorb->FirstArea->PreviousArea = sourceEndArea;
heapToAbsorb->FirstArea = NULL;
sourceHeap->Stats.NumMemoryAreas += heapToAbsorb->Stats.NumMemoryAreas;
sourceHeap->Stats.NumTotalSegments += heapToAbsorb->Stats.NumTotalSegments;
sourceHeap->Stats.NumTotalOccupiedSegments += heapToAbsorb->Stats.NumTotalOccupiedSegments;
sourceHeap->Stats.TotalSize += heapToAbsorb->Stats.TotalSize;
MIHP_UnlockHeap(heapToAbsorb);
MIHP_MEMSET(heapToAbsorb, sizeof(MIHP_Heap), 0);
sourceEndArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(sourceEndArea);
sourceEndArea->NextArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(sourceEndArea->NextArea);
MIHP_UnlockHeap(sourceHeap);
return true;
}
bool MIHP_IsPointerInHeap(MIHP_Heap* heap, void* ptr)
{
if (heap == NULL)
@@ -438,12 +496,12 @@ MIHP_HeapMemoryAreaHeader* MIHP_CreateHeapMemoryArea(MIHP_Heap* heap, size_t req
MIHP_ASSERT(actualSize >= effectiveSize);
MIHP_MEMSET(area, sizeof(MIHP_HeapMemoryAreaHeader), 0);
area->InstigatingHeap = heap;
area->AreaSize = actualSize;
area->OwningHeap = heap;
area->Checksum = ~0;
size_t headerSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapMemoryAreaHeader));
area->FirstSegment = MIHP_InitializeHeapSegment(area, (char*)area + headerSize, area->AreaSize - headerSize);
area->FirstSegment = MIHP_InitializeHeapSegment(heap, area, (char*)area + headerSize, area->AreaSize - headerSize);
area->FirstSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(area->FirstSegment);
heap->Stats.NumMemoryAreas++;
@@ -461,7 +519,7 @@ bool MIHP_DestroyHeapMemoryArea(MIHP_Heap* heap, MIHP_HeapMemoryAreaHeader* memo
size_t areaNumOccupiedSegments = memoryArea->NumOccupiedSegments;
size_t areaSize = memoryArea->AreaSize;
if (!heap->Config.PlatformFreeMemoryFn(heap, memoryArea, memoryArea->AreaSize))
if (!heap->Config.PlatformFreeMemoryFn(memoryArea->InstigatingHeap, memoryArea, memoryArea->AreaSize))
return false;
heap->Stats.NumTotalSegments -= areaNumSegments;
@@ -472,7 +530,7 @@ bool MIHP_DestroyHeapMemoryArea(MIHP_Heap* heap, MIHP_HeapMemoryAreaHeader* memo
return true;
}
MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_HeapMemoryAreaHeader* area, void* segmentStart, size_t segmentSize)
MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_Heap* heap, MIHP_HeapMemoryAreaHeader* area, void* segmentStart, size_t segmentSize)
{
MIHP_ASSERT(area);
MIHP_ASSERT(segmentStart);
@@ -488,12 +546,12 @@ MIHP_HeapSegmentHeader* MIHP_InitializeHeapSegment(MIHP_HeapMemoryAreaHeader* ar
area->NumSegments++;
area->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(area);
area->OwningHeap->Stats.NumTotalSegments++;
heap->Stats.NumTotalSegments++;
return segment;
}
bool MIHP_UninitializeHeapSegment(MIHP_HeapSegmentHeader* segment)
bool MIHP_UninitializeHeapSegment(MIHP_Heap* heap, MIHP_HeapSegmentHeader* segment)
{
MIHP_ASSERT(segment);
@@ -502,19 +560,19 @@ bool MIHP_UninitializeHeapSegment(MIHP_HeapSegmentHeader* segment)
segment->OwningMemoryArea->NumSegments--;
segment->OwningMemoryArea->Checksum = MIHP_GenerateHeapMemoryAreaChecksum(segment->OwningMemoryArea);
segment->OwningMemoryArea->OwningHeap->Stats.NumTotalSegments--;
heap->Stats.NumTotalSegments--;
MIHP_MEMSET(segment, sizeof(MIHP_HeapSegmentHeader), 0);
return true;
}
bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentMinSize, MIHP_HeapSegmentHeader** outNewSegment)
bool MIHP_SplitHeapSegment(MIHP_Heap* heap, MIHP_HeapSegmentHeader* sourceSegment, size_t newSegmentMinSize, MIHP_HeapSegmentHeader** outNewSegment)
{
MIHP_ASSERT(sourceSegment);
size_t headerSize = MIHP_GetHeapAlignedSize(sourceSegment->OwningMemoryArea->OwningHeap, sizeof(MIHP_HeapSegmentHeader));
size_t effectiveNewSegmentSize = MIHP_GetHeapAlignedSize(sourceSegment->OwningMemoryArea->OwningHeap, newSegmentMinSize);
size_t headerSize = MIHP_GetHeapAlignedSize(heap, sizeof(MIHP_HeapSegmentHeader));
size_t effectiveNewSegmentSize = MIHP_GetHeapAlignedSize(heap, newSegmentMinSize);
if (sourceSegment->SegmentSize < effectiveNewSegmentSize)
return false;
@@ -526,13 +584,13 @@ bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegm
sourceSegment->SegmentSize = sourceResultingSegmentSize;
MIHP_HeapSegmentHeader* newSegment = MIHP_InitializeHeapSegment(sourceSegment->OwningMemoryArea, (char*)sourceSegment + sourceResultingSegmentSize, effectiveNewSegmentSize);
MIHP_HeapSegmentHeader* newSegment = MIHP_InitializeHeapSegment(heap, sourceSegment->OwningMemoryArea, (char*)sourceSegment + sourceResultingSegmentSize, effectiveNewSegmentSize);
newSegment->NextSegment = sourceSegment->NextSegment;
newSegment->PreviousSegment = sourceSegment;
if (sourceSegment->NextSegment)
{
MIHP_ValidateHeapSegmentHeader(sourceSegment->OwningMemoryArea->OwningHeap, sourceSegment->NextSegment);
MIHP_ValidateHeapSegmentHeader(heap, sourceSegment->NextSegment);
sourceSegment->NextSegment->PreviousSegment = newSegment;
sourceSegment->NextSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment->NextSegment);
}
@@ -546,7 +604,7 @@ bool MIHP_SplitHeapSegment(MIHP_HeapSegmentHeader* sourceSegment, size_t newSegm
return true;
}
bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegmentHeader* segmentToAbsorb)
bool MIHP_MergeHeapSegments(MIHP_Heap* heap, MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegmentHeader* segmentToAbsorb)
{
MIHP_ASSERT(sourceSegment);
MIHP_ASSERT(segmentToAbsorb);
@@ -559,13 +617,13 @@ bool MIHP_MergeHeapSegments(MIHP_HeapSegmentHeader* sourceSegment, MIHP_HeapSegm
if (sourceSegment->NextSegment)
{
MIHP_ValidateHeapSegmentHeader(sourceSegment->OwningMemoryArea->OwningHeap, sourceSegment->NextSegment);
MIHP_ValidateHeapSegmentHeader(heap, sourceSegment->NextSegment);
sourceSegment->NextSegment->PreviousSegment = sourceSegment;
sourceSegment->NextSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment->NextSegment);
}
sourceSegment->SegmentSize += segmentToAbsorb->SegmentSize;
MIHP_UninitializeHeapSegment(segmentToAbsorb);
MIHP_UninitializeHeapSegment(heap, segmentToAbsorb);
sourceSegment->Checksum = MIHP_GenerateHeapSegmentChecksum(sourceSegment);

View File

@@ -59,7 +59,7 @@ int main()
__debugbreak();
MIHP_MEMSET(myptrs[5], 5000, 0x75);
//MIHP_MEMSET(myptrs[5], 5000, 0x75);
for (int i = 0; i < NUM_ALLOCATIONS; i++)
{