Files
hakmem/core/hakmem_super_registry.c

155 lines
5.1 KiB
C
Raw Normal View History

#include "hakmem_super_registry.h"
#include "hakmem_tiny_superslab.h"
#include <string.h>
#include <stdio.h>
// Global registry storage
SuperRegEntry g_super_reg[SUPER_REG_SIZE];
pthread_mutex_t g_super_reg_lock = PTHREAD_MUTEX_INITIALIZER;
int g_super_reg_initialized = 0;
// Initialize registry (call once at startup)
void hak_super_registry_init(void) {
if (g_super_reg_initialized) return;
// Zero-initialize all entries
memset(g_super_reg, 0, sizeof(g_super_reg));
// Memory fence to ensure initialization is visible to all threads
atomic_thread_fence(memory_order_release);
g_super_reg_initialized = 1;
}
// Register SuperSlab (mutex-protected)
// CRITICAL: Call AFTER SuperSlab is fully initialized
// Publish order: ss init → release fence → base write
// Phase 8.3: ACE - lg_size aware registration
int hak_super_register(uintptr_t base, SuperSlab* ss) {
if (!g_super_reg_initialized) {
hak_super_registry_init();
}
pthread_mutex_lock(&g_super_reg_lock);
int lg = ss->lg_size; // Phase 8.3: Get lg_size from SuperSlab
int h = hak_super_hash(base, lg);
// Linear probing to find empty slot
for (int i = 0; i < SUPER_MAX_PROBE; i++) {
SuperRegEntry* e = &g_super_reg[(h + i) & SUPER_REG_MASK];
if (e->base == 0) {
// Found empty slot
// Step 1: Write SuperSlab pointer and lg_size (atomic for MT-safety)
atomic_store_explicit(&e->ss, ss, memory_order_release);
e->lg_size = lg; // Phase 8.3: Store lg_size for fast lookup
// Step 2: Release fence (ensures ss/lg_size write is visible before base)
atomic_thread_fence(memory_order_release);
// Step 3: Publish base address (makes entry visible to readers)
atomic_store_explicit((_Atomic uintptr_t*)&e->base, base,
memory_order_release);
pthread_mutex_unlock(&g_super_reg_lock);
return 1;
}
if (e->base == base && e->lg_size == lg) {
// Already registered (duplicate registration)
pthread_mutex_unlock(&g_super_reg_lock);
return 1;
}
}
// Registry full (probing limit reached)
pthread_mutex_unlock(&g_super_reg_lock);
fprintf(stderr, "HAKMEM: SuperSlab registry full! Increase SUPER_REG_SIZE\n");
return 0;
}
// Unregister SuperSlab (mutex-protected)
// CRITICAL: Call BEFORE munmap to prevent reader segfault
// Unpublish order: base = 0 (release) → munmap outside this function
// Phase 8.3: ACE - Try both lg_sizes (we don't know which one was used)
void hak_super_unregister(uintptr_t base) {
if (!g_super_reg_initialized) return;
pthread_mutex_lock(&g_super_reg_lock);
// Try both 1MB (20) and 2MB (21) alignments
for (int lg = 20; lg <= 21; lg++) {
int h = hak_super_hash(base, lg);
// Linear probing to find matching entry
for (int i = 0; i < SUPER_MAX_PROBE; i++) {
SuperRegEntry* e = &g_super_reg[(h + i) & SUPER_REG_MASK];
if (e->base == base && e->lg_size == lg) {
// Found entry to remove
// Step 1: Clear SuperSlab pointer (atomic, prevents TOCTOU race)
atomic_store_explicit(&e->ss, NULL, memory_order_release);
// Step 2: Unpublish base (makes entry invisible to readers)
atomic_store_explicit((_Atomic uintptr_t*)&e->base, 0,
memory_order_release);
// Step 3: Clear lg_size (optional cleanup)
e->lg_size = 0;
pthread_mutex_unlock(&g_super_reg_lock);
return;
}
if (e->base == 0) {
// Not found in this lg_size, try next
break;
}
}
}
pthread_mutex_unlock(&g_super_reg_lock);
// Not found is not an error (could be duplicate unregister)
}
// Debug: Get registry statistics
void hak_super_registry_stats(SuperRegStats* stats) {
if (!stats) return;
stats->total_slots = SUPER_REG_SIZE;
stats->used_slots = 0;
stats->max_probe_depth = 0;
pthread_mutex_lock(&g_super_reg_lock);
// Count used slots
for (int i = 0; i < SUPER_REG_SIZE; i++) {
if (g_super_reg[i].base != 0) {
stats->used_slots++;
}
}
// Calculate max probe depth
for (int i = 0; i < SUPER_REG_SIZE; i++) {
if (g_super_reg[i].base != 0) {
uintptr_t base = g_super_reg[i].base;
int lg = g_super_reg[i].lg_size; // Phase 8.3: Use stored lg_size
int h = hak_super_hash(base, lg);
// Find actual probe depth for this entry
for (int j = 0; j < SUPER_MAX_PROBE; j++) {
int idx = (h + j) & SUPER_REG_MASK;
if (g_super_reg[idx].base == base && g_super_reg[idx].lg_size == lg) {
if (j > stats->max_probe_depth) {
stats->max_probe_depth = j;
}
break;
}
}
}
}
pthread_mutex_unlock(&g_super_reg_lock);
}