// smallobject_segment_mid_v3.c // Phase v11a-2: Multi-class MID v3.5 segment implementation (L2 physical layer) #include #include #include #include #include "box/smallobject_segment_mid_v3_box.h" #include "box/region_id_v6_box.h" // ============================================================================ // SmallPageMeta - Page metadata for MID v3 // ============================================================================ typedef struct SmallPageMeta { void *ptr; // Page base pointer uint32_t capacity; // Slots per page uint8_t class_idx; // Size class (C5-C7) uint32_t alloc_count; // Total allocations on this page uint32_t free_count; // Total frees on this page void *segment; // Back-pointer to SmallSegment_MID_v3 struct SmallPageMeta *next; // For free stack linking } SmallPageMeta; // ============================================================================ // Geometry Constants // ============================================================================ #define SMALL_MID_SEGMENT_SIZE (2 * 1024 * 1024) // 2 MiB #define SMALL_MID_PAGE_SIZE (64 * 1024) // 64 KiB #define SMALL_MID_PAGES_PER_SEG (SMALL_MID_SEGMENT_SIZE / SMALL_MID_PAGE_SIZE) // 32 // ============================================================================ // Helper: class_idx to slots mapping // ============================================================================ static uint32_t class_idx_to_slots(uint32_t class_idx) { // MID v3.5 targets C5-C7 (257-1024B) // C5: 257-384B → 64KiB / 384B ≈ 170 slots // C6: 385-640B → 64KiB / 640B ≈ 102 slots // C7: 641-1024B → 64KiB / 1024B ≈ 64 slots switch (class_idx) { case 5: return 170; // C5 case 6: return 102; // C6 case 7: return 64; // C7 default: return 0; } } // ============================================================================ // Segment Lifecycle // ============================================================================ SmallSegment_MID_v3* small_segment_mid_v3_create(void) { // 1. Allocate SmallSegment_MID_v3 structure SmallSegment_MID_v3 *seg = malloc(sizeof(*seg)); if (!seg) return NULL; // 2. mmap 2MiB contiguous memory seg->start = mmap(NULL, SMALL_MID_SEGMENT_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (seg->start == MAP_FAILED) { free(seg); return NULL; } seg->total_size = SMALL_MID_SEGMENT_SIZE; seg->page_size = SMALL_MID_PAGE_SIZE; seg->num_pages = SMALL_MID_PAGES_PER_SEG; // 3. Initialize per-class free page stacks for (int i = 0; i < 8; i++) { seg->free_pages[i] = NULL; seg->free_count[i] = 0; seg->current_page[i] = NULL; seg->page_offset[i] = 0; } // 4. Allocate and initialize page metadata array seg->pages = malloc(sizeof(SmallPageMeta*) * SMALL_MID_PAGES_PER_SEG); if (!seg->pages) { munmap(seg->start, SMALL_MID_SEGMENT_SIZE); free(seg); return NULL; } // Allocate individual page metadata structures for (uint32_t i = 0; i < SMALL_MID_PAGES_PER_SEG; i++) { SmallPageMeta *meta = malloc(sizeof(SmallPageMeta)); if (!meta) { // Cleanup on failure for (uint32_t j = 0; j < i; j++) { free(seg->pages[j]); } free(seg->pages); munmap(seg->start, SMALL_MID_SEGMENT_SIZE); free(seg); return NULL; } meta->ptr = (char*)seg->start + (i * SMALL_MID_PAGE_SIZE); meta->capacity = 0; meta->class_idx = 0xFF; // Unassigned meta->alloc_count = 0; meta->free_count = 0; meta->segment = seg; meta->next = NULL; seg->pages[i] = meta; } // 5. Register with RegionIdBox seg->region_id = region_id_register_v6(seg->start, seg->total_size, REGION_KIND_MID_V3, seg); seg->total_allocations = 0; seg->total_frees = 0; seg->last_refill_count = 0; return seg; } void small_segment_mid_v3_destroy(SmallSegment_MID_v3 *seg) { if (!seg) return; // Unregister from RegionIdBox region_id_unregister_v6(seg->region_id); // Free page metadata if (seg->pages) { for (uint32_t i = 0; i < SMALL_MID_PAGES_PER_SEG; i++) { if (seg->pages[i]) { free(seg->pages[i]); } } free(seg->pages); } // Unmap segment memory if (seg->start && seg->start != MAP_FAILED) { munmap(seg->start, seg->total_size); } free(seg); } // ============================================================================ // Page Management // ============================================================================ // Take a page from the free stack (LIFO) void* small_segment_mid_v3_take_page(SmallSegment_MID_v3 *seg, uint32_t class_idx) { if (!seg || class_idx >= 8) return NULL; if (seg->free_count[class_idx] > 0) { // Pop from free stack void **stack = seg->free_pages[class_idx]; if (!stack || seg->free_count[class_idx] == 0) return NULL; // Get the top page void *page = stack[seg->free_count[class_idx] - 1]; seg->free_count[class_idx]--; return page; } // No free pages available return NULL; } // Release a page back to the free stack (LIFO) void small_segment_mid_v3_release_page(SmallSegment_MID_v3 *seg, void *page, uint32_t class_idx) { if (!seg || !page || class_idx >= 8) return; // Allocate stack if needed (lazy initialization) if (!seg->free_pages[class_idx]) { seg->free_pages[class_idx] = malloc(sizeof(void*) * SMALL_MID_PAGES_PER_SEG); if (!seg->free_pages[class_idx]) return; } // Push to free stack seg->free_pages[class_idx][seg->free_count[class_idx]] = page; seg->free_count[class_idx]++; } // Get region ID uint32_t small_segment_mid_v3_region_id(SmallSegment_MID_v3 *seg) { return seg ? seg->region_id : 0; } // Set region ID (called by RegionIdBox) void small_segment_mid_v3_set_region_id(SmallSegment_MID_v3 *seg, uint32_t region_id) { if (seg) { seg->region_id = region_id; } } // Check if page is within segment bounds bool small_segment_mid_v3_contains_page(SmallSegment_MID_v3 *seg, void *page) { if (!seg || !page) return false; uintptr_t page_addr = (uintptr_t)page; uintptr_t seg_start = (uintptr_t)seg->start; uintptr_t seg_end = seg_start + seg->total_size; return (page_addr >= seg_start && page_addr < seg_end); } // Get page metadata for pointer struct SmallPageMeta* small_segment_mid_v3_get_page_meta( SmallSegment_MID_v3 *seg, void *page ) { if (!seg || !page || !seg->pages) return NULL; // Calculate page index uintptr_t page_addr = (uintptr_t)page; uintptr_t seg_start = (uintptr_t)seg->start; if (page_addr < seg_start) return NULL; uintptr_t offset = page_addr - seg_start; uint32_t page_idx = offset / SMALL_MID_PAGE_SIZE; if (page_idx >= SMALL_MID_PAGES_PER_SEG) return NULL; return (struct SmallPageMeta*)seg->pages[page_idx]; } // ============================================================================ // Statistics // ============================================================================ SmallSegmentStatsMID_v3 small_segment_mid_v3_get_stats(SmallSegment_MID_v3 *seg) { SmallSegmentStatsMID_v3 stats = {0}; if (!seg) return stats; stats.total_allocations = seg->total_allocations; stats.total_frees = seg->total_frees; // Count active pages per class for (uint32_t i = 0; i < SMALL_MID_PAGES_PER_SEG; i++) { SmallPageMeta *meta = seg->pages[i]; if (meta && meta->class_idx < 8 && meta->class_idx != 0xFF) { stats.active_pages[meta->class_idx]++; } } return stats; } void small_segment_mid_v3_reset_stats(SmallSegment_MID_v3 *seg) { if (!seg) return; seg->total_allocations = 0; seg->total_frees = 0; seg->last_refill_count = 0; } // ============================================================================ // Validation & Debugging // ============================================================================ bool small_segment_mid_v3_validate(SmallSegment_MID_v3 *seg) { if (!seg) return false; if (!seg->start || seg->start == MAP_FAILED) return false; if (seg->total_size != SMALL_MID_SEGMENT_SIZE) return false; if (seg->num_pages != SMALL_MID_PAGES_PER_SEG) return false; if (!seg->pages) return false; return true; } void small_segment_mid_v3_debug_print(SmallSegment_MID_v3 *seg) { if (!seg) { fprintf(stderr, "[MID_v3] Segment: NULL\n"); return; } fprintf(stderr, "[MID_v3] Segment %p:\n", (void*)seg); fprintf(stderr, " start=%p size=%zu pages=%u region_id=%u\n", seg->start, seg->total_size, seg->num_pages, seg->region_id); fprintf(stderr, " allocs=%lu frees=%lu\n", seg->total_allocations, seg->total_frees); for (int i = 0; i < 8; i++) { if (seg->free_count[i] > 0) { fprintf(stderr, " C%d: free_pages=%u\n", i, seg->free_count[i]); } } }