#include "heap4_model.h" enum { BLOCK_BYTES = 48 }; typedef struct { ModelBlock first; uint8_t first_payload[BLOCK_BYTES - sizeof(ModelBlock)]; ModelBlock middle; uint8_t middle_payload[BLOCK_BYTES - sizeof(ModelBlock)]; ModelBlock last; uint8_t last_payload[BLOCK_BYTES - sizeof(ModelBlock)]; } CoalesceArena; typedef union { uint64_t force_alignment; CoalesceArena blocks; } AlignedCoalesceArena; AlignedCoalesceArena g_coalesce_arena; ModelBlock *g_free_head; volatile size_t g_before_nodes; volatile size_t g_before_total; volatile size_t g_before_largest; volatile size_t g_after_nodes; volatile size_t g_after_total; volatile size_t g_after_largest; volatile int g_task02_pass; static void insert_and_coalesce(ModelBlock *block) { ModelBlock *previous = NULL; ModelBlock *current = g_free_head; while (current != NULL && (uintptr_t)current < (uintptr_t)block) { previous = current; current = current->next; } block->next = current; if (current != NULL && (uint8_t *)block + block->size == (uint8_t *)current) { block->size += current->size; block->next = current->next; } if (previous != NULL && (uint8_t *)previous + previous->size == (uint8_t *)block) { previous->size += block->size; previous->next = block->next; } else if (previous != NULL) { previous->next = block; } else { g_free_head = block; } } static void measure(size_t *nodes, size_t *total, size_t *largest) { ModelBlock *block; *nodes = 0U; *total = 0U; *largest = 0U; for (block = g_free_head; block != NULL; block = block->next) { (*nodes)++; *total += block->size; if (block->size > *largest) { *largest = block->size; } } } __attribute__((noinline)) void task02_fragmented_checkpoint(void) { #if defined(__GNUC__) __asm__ volatile("" ::: "memory"); #endif } __attribute__((noinline)) void task02_debug_checkpoint(void) { #if defined(__GNUC__) __asm__ volatile("" ::: "memory"); #endif } int main(void) { CoalesceArena *arena = &g_coalesce_arena.blocks; size_t nodes; size_t total; size_t largest; arena->first.size = BLOCK_BYTES; arena->middle.size = BLOCK_BYTES; arena->last.size = BLOCK_BYTES; g_free_head = NULL; insert_and_coalesce(&arena->first); insert_and_coalesce(&arena->last); measure(&nodes, &total, &largest); g_before_nodes = nodes; g_before_total = total; g_before_largest = largest; task02_fragmented_checkpoint(); insert_and_coalesce(&arena->middle); measure(&nodes, &total, &largest); g_after_nodes = nodes; g_after_total = total; g_after_largest = largest; g_task02_pass = g_before_nodes == 2U && g_before_total == 96U && g_before_largest == 48U && g_after_nodes == 1U && g_after_total == 144U && g_after_largest == 144U && g_free_head == &arena->first && g_free_head->next == NULL; task02_debug_checkpoint(); #if defined(HOST_PRINTF) printf("before_nodes=%zu before_total=%zu before_largest=%zu " "after_nodes=%zu after_total=%zu after_largest=%zu pass=%d\n", g_before_nodes, g_before_total, g_before_largest, g_after_nodes, g_after_total, g_after_largest, g_task02_pass); #endif return g_task02_pass ? 0 : 1; }