295 lines
9.3 KiB
C
295 lines
9.3 KiB
C
|
|
// smallobject_segment_mid_v3.c
|
||
|
|
// Phase v11a-2: Multi-class MID v3.5 segment implementation (L2 physical layer)
|
||
|
|
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <sys/mman.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#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]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|