2025-11-29 05:13:04 +09:00
|
|
|
// superslab_backend.c - Backend allocation paths for SuperSlab allocator
|
2025-12-01 16:37:59 +09:00
|
|
|
// Purpose: Shared pool backend implementation (legacy path archived)
|
2025-11-29 05:13:04 +09:00
|
|
|
// License: MIT
|
|
|
|
|
// Date: 2025-11-28
|
|
|
|
|
|
|
|
|
|
#include "hakmem_tiny_superslab_internal.h"
|
2025-12-05 23:41:01 +09:00
|
|
|
#include "box/c7_meta_used_counter_box.h"
|
|
|
|
|
#include <stdatomic.h>
|
|
|
|
|
|
|
|
|
|
static _Atomic uint32_t g_c7_backend_calls = 0;
|
2025-11-29 05:13:04 +09:00
|
|
|
|
2025-12-01 16:37:59 +09:00
|
|
|
// Note: Legacy backend moved to archive/superslab_backend_legacy.c (not built).
|
2025-11-29 05:13:04 +09:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Shared pool backend for hak_tiny_alloc_superslab_box().
|
|
|
|
|
*
|
|
|
|
|
* Phase 12-2:
|
|
|
|
|
* - Uses SharedSuperSlabPool (g_shared_pool) to obtain a SuperSlab/slab
|
|
|
|
|
* for the requested class_idx.
|
|
|
|
|
* - This backend EXPRESSLY owns only:
|
|
|
|
|
* - choosing (ss, slab_idx) via shared_pool_acquire_slab()
|
|
|
|
|
* - initializing that slab's TinySlabMeta via superslab_init_slab()
|
|
|
|
|
* and nothing else; all callers must go through hak_tiny_alloc_superslab_box().
|
|
|
|
|
*
|
|
|
|
|
* - For now this is a minimal, conservative implementation:
|
|
|
|
|
* - One linear bump-run is carved from the acquired slab using tiny_block_stride_for_class().
|
|
|
|
|
* - No complex per-slab freelist or refill policy yet (Phase 12-3+).
|
2025-12-01 16:37:59 +09:00
|
|
|
* - If shared_pool_acquire_slab() fails, allocation returns NULL (no legacy fallback).
|
2025-11-29 05:13:04 +09:00
|
|
|
*/
|
|
|
|
|
void* hak_tiny_alloc_superslab_backend_shared(int class_idx)
|
|
|
|
|
{
|
|
|
|
|
if (class_idx < 0 || class_idx >= TINY_NUM_CLASSES_SS) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SuperSlab* ss = NULL;
|
|
|
|
|
int slab_idx = -1;
|
|
|
|
|
|
|
|
|
|
if (shared_pool_acquire_slab(class_idx, &ss, &slab_idx) != 0 || !ss) {
|
|
|
|
|
// Shared pool could not provide a slab; caller may choose to fall back.
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TinySlabMeta* meta = &ss->slabs[slab_idx];
|
|
|
|
|
|
|
|
|
|
// Defensive: shared_pool must either hand us an UNASSIGNED slab or one
|
|
|
|
|
// already bound to this class. Anything else is a hard bug.
|
|
|
|
|
if (meta->class_idx != 255 && meta->class_idx != (uint8_t)class_idx) {
|
|
|
|
|
#if !HAKMEM_BUILD_RELEASE
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"[HAKMEM][SS_SHARED] BUG: acquire_slab mismatch: cls=%d meta->class_idx=%u slab_idx=%d ss=%p\n",
|
|
|
|
|
class_idx, (unsigned)meta->class_idx, slab_idx, (void*)ss);
|
|
|
|
|
#endif
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize slab geometry once for this class.
|
|
|
|
|
if (meta->capacity == 0) {
|
|
|
|
|
size_t block_size = g_tiny_class_sizes[class_idx];
|
|
|
|
|
// LARSON FIX: Pass actual thread ID for cross-thread free detection
|
|
|
|
|
uint32_t my_tid = (uint32_t)(uintptr_t)pthread_self();
|
|
|
|
|
superslab_init_slab(ss, slab_idx, block_size, my_tid);
|
|
|
|
|
meta = &ss->slabs[slab_idx];
|
|
|
|
|
|
|
|
|
|
// CRITICAL FIX: Always set class_idx after init to avoid C0/C7 confusion.
|
|
|
|
|
// New SuperSlabs start with meta->class_idx=0 (mmap zero-init).
|
|
|
|
|
// Must explicitly set to requested class, not just when class_idx==255.
|
|
|
|
|
meta->class_idx = (uint8_t)class_idx;
|
|
|
|
|
// P1.1: Update class_map in shared acquire path
|
|
|
|
|
ss->class_map[slab_idx] = (uint8_t)class_idx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Final contract check before computing addresses.
|
|
|
|
|
if (meta->class_idx != (uint8_t)class_idx ||
|
|
|
|
|
meta->capacity == 0 ||
|
|
|
|
|
meta->used > meta->capacity) {
|
|
|
|
|
#if !HAKMEM_BUILD_RELEASE
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"[HAKMEM][SS_SHARED] BUG: invalid slab meta before alloc: "
|
|
|
|
|
"cls=%d slab_idx=%d meta_cls=%u used=%u cap=%u ss=%p\n",
|
|
|
|
|
class_idx, slab_idx,
|
|
|
|
|
(unsigned)meta->class_idx,
|
|
|
|
|
(unsigned)meta->used,
|
|
|
|
|
(unsigned)meta->capacity,
|
|
|
|
|
(void*)ss);
|
|
|
|
|
#endif
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-05 23:41:01 +09:00
|
|
|
if (class_idx == 7) {
|
|
|
|
|
uint32_t n = atomic_fetch_add_explicit(&g_c7_backend_calls, 1, memory_order_relaxed);
|
|
|
|
|
if (n < 8) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"[REL_C7_BACKEND_CALL] cls=%d meta_cls=%u used=%u cap=%u ss=%p slab=%d\n",
|
|
|
|
|
class_idx,
|
|
|
|
|
(unsigned)meta->class_idx,
|
|
|
|
|
(unsigned)meta->used,
|
|
|
|
|
(unsigned)meta->capacity,
|
|
|
|
|
(void*)ss,
|
|
|
|
|
slab_idx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-29 05:13:04 +09:00
|
|
|
// Simple bump allocation within this slab.
|
|
|
|
|
if (meta->used >= meta->capacity) {
|
|
|
|
|
// Slab exhausted: in minimal Phase12-2 backend we do not loop;
|
|
|
|
|
// caller or future logic must acquire another slab.
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t stride = tiny_block_stride_for_class(class_idx);
|
|
|
|
|
size_t offset = (size_t)meta->used * stride;
|
|
|
|
|
|
|
|
|
|
// Phase 12-2 minimal geometry:
|
|
|
|
|
// - slab 0 data offset via SUPERSLAB_SLAB0_DATA_OFFSET
|
|
|
|
|
// - subsequent slabs at fixed SUPERSLAB_SLAB_USABLE_SIZE strides.
|
|
|
|
|
size_t slab_base_off = SUPERSLAB_SLAB0_DATA_OFFSET
|
|
|
|
|
+ (size_t)slab_idx * SUPERSLAB_SLAB_USABLE_SIZE;
|
|
|
|
|
uint8_t* base = (uint8_t*)ss + slab_base_off + offset;
|
|
|
|
|
|
|
|
|
|
meta->used++;
|
2025-12-05 23:41:01 +09:00
|
|
|
c7_meta_used_note(class_idx, C7_META_USED_SRC_BACKEND);
|
2025-11-29 05:13:04 +09:00
|
|
|
atomic_fetch_add_explicit(&ss->total_active_blocks, 1, memory_order_relaxed);
|
|
|
|
|
|
2025-11-29 05:38:30 +09:00
|
|
|
HAK_RET_ALLOC_BLOCK_TRACED(class_idx, base, ALLOC_PATH_BACKEND);
|
2025-11-29 05:13:04 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Box API entry:
|
|
|
|
|
* - Single front-door for tiny-side Superslab allocations.
|
|
|
|
|
*
|
2025-12-01 13:47:23 +09:00
|
|
|
* Phase 9-2 Final: Shared Pool ONLY (Legacy Backend Removed)
|
2025-11-30 09:27:08 +09:00
|
|
|
* Policy:
|
2025-12-01 13:47:23 +09:00
|
|
|
* - HAKMEM_TINY_SS_SHARED is now ignored (or used only for logging).
|
|
|
|
|
* - Always uses Shared Pool backend.
|
|
|
|
|
* - Legacy backend (g_superslab_heads) is no longer used for allocation.
|
2025-11-29 05:13:04 +09:00
|
|
|
*/
|
|
|
|
|
void* hak_tiny_alloc_superslab_box(int class_idx)
|
|
|
|
|
{
|
2025-12-01 13:47:23 +09:00
|
|
|
// Always use Shared Pool (Mode 2 equivalent)
|
|
|
|
|
void* p = hak_tiny_alloc_superslab_backend_shared(class_idx);
|
|
|
|
|
|
|
|
|
|
if (p == NULL) {
|
|
|
|
|
static _Atomic uint32_t g_ss_oom_log = 0;
|
|
|
|
|
uint32_t n = atomic_fetch_add_explicit(&g_ss_oom_log, 1, memory_order_relaxed);
|
2025-11-29 05:13:04 +09:00
|
|
|
if (n < 4) {
|
2025-12-01 13:47:23 +09:00
|
|
|
fprintf(stderr, "[SS_BACKEND] shared_fail→NULL (OOM) cls=%d\n", class_idx);
|
2025-11-29 05:13:04 +09:00
|
|
|
}
|
|
|
|
|
}
|
2025-12-01 13:47:23 +09:00
|
|
|
return p;
|
2025-11-29 05:13:04 +09:00
|
|
|
}
|