2025-11-05 12:31:14 +09:00
|
|
|
|
#include <inttypes.h>
|
2025-11-08 21:35:43 +09:00
|
|
|
|
#include <pthread.h>
|
2025-11-05 12:31:14 +09:00
|
|
|
|
#include "tiny_remote.h"
|
|
|
|
|
|
#include "slab_handle.h"
|
|
|
|
|
|
#include "tiny_refill.h"
|
|
|
|
|
|
#include "tiny_tls_guard.h"
|
Phase 1: Box Theory refactoring + include reduction
Phase 1-1: Split hakmem_tiny_free.inc (1,711 → 452 lines, -73%)
- Created tiny_free_magazine.inc.h (413 lines) - Magazine layer
- Created tiny_superslab_alloc.inc.h (394 lines) - SuperSlab alloc
- Created tiny_superslab_free.inc.h (305 lines) - SuperSlab free
Phase 1-2++: Refactor hakmem_pool.c (1,481 → 907 lines, -38.8%)
- Created pool_tls_types.inc.h (32 lines) - TLS structures
- Created pool_mf2_types.inc.h (266 lines) - MF2 data structures
- Created pool_mf2_helpers.inc.h (158 lines) - Helper functions
- Created pool_mf2_adoption.inc.h (129 lines) - Adoption logic
Phase 1-3: Reduce hakmem_tiny.c includes (60 → 46, -23.3%)
- Created tiny_system.h - System headers umbrella (stdio, stdlib, etc.)
- Created tiny_api.h - API headers umbrella (stats, query, rss, registry)
Performance: 4.19M ops/s maintained (±0% regression)
Verified: Larson benchmark 2×8×128×1024 = 4,192,128 ops/s
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 21:54:12 +09:00
|
|
|
|
#include "box/free_publish_box.h"
|
2025-11-10 16:48:20 +09:00
|
|
|
|
#include "box/tls_sll_box.h" // Box TLS-SLL: C7-safe push/pop/splice
|
2025-11-05 12:31:14 +09:00
|
|
|
|
#include "mid_tcache.h"
|
|
|
|
|
|
extern __thread void* g_tls_sll_head[TINY_NUM_CLASSES];
|
|
|
|
|
|
extern __thread uint32_t g_tls_sll_count[TINY_NUM_CLASSES];
|
|
|
|
|
|
#if !HAKMEM_BUILD_RELEASE
|
|
|
|
|
|
#include "hakmem_tiny_magazine.h"
|
|
|
|
|
|
#endif
|
|
|
|
|
|
extern int g_tiny_force_remote;
|
|
|
|
|
|
|
|
|
|
|
|
// ENV: HAKMEM_TINY_DRAIN_TO_SLL (0=off) — adopt/bind境界でfreelist→TLS SLLへN個スプライス
|
|
|
|
|
|
static inline int tiny_drain_to_sll_budget(void) {
|
|
|
|
|
|
static int v = -1;
|
|
|
|
|
|
if (__builtin_expect(v == -1, 0)) {
|
|
|
|
|
|
const char* s = getenv("HAKMEM_TINY_DRAIN_TO_SLL");
|
|
|
|
|
|
int parsed = (s && *s) ? atoi(s) : 0;
|
|
|
|
|
|
if (parsed < 0) parsed = 0; if (parsed > 256) parsed = 256;
|
|
|
|
|
|
v = parsed;
|
|
|
|
|
|
}
|
|
|
|
|
|
return v;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static inline void tiny_drain_freelist_to_sll_once(SuperSlab* ss, int slab_idx, int class_idx) {
|
|
|
|
|
|
int budget = tiny_drain_to_sll_budget();
|
|
|
|
|
|
if (__builtin_expect(budget <= 0, 1)) return;
|
2025-11-10 16:48:20 +09:00
|
|
|
|
// CRITICAL: C7 (1KB) is headerless - MUST NOT drain to TLS SLL
|
|
|
|
|
|
// Reason: SLL stores next pointer in first 8 bytes (user data for C7)
|
|
|
|
|
|
if (__builtin_expect(class_idx == 7, 0)) return;
|
2025-11-05 12:31:14 +09:00
|
|
|
|
if (!(ss && ss->magic == SUPERSLAB_MAGIC)) return;
|
|
|
|
|
|
if (slab_idx < 0) return;
|
|
|
|
|
|
TinySlabMeta* m = &ss->slabs[slab_idx];
|
|
|
|
|
|
int moved = 0;
|
|
|
|
|
|
while (m->freelist && moved < budget) {
|
|
|
|
|
|
void* p = m->freelist;
|
2025-11-08 01:18:37 +09:00
|
|
|
|
|
|
|
|
|
|
// CORRUPTION DEBUG: Validate freelist pointer before moving to TLS SLL
|
|
|
|
|
|
if (__builtin_expect(tiny_refill_failfast_level() >= 2, 0)) {
|
|
|
|
|
|
extern const size_t g_tiny_class_sizes[];
|
|
|
|
|
|
size_t blk = g_tiny_class_sizes[class_idx];
|
|
|
|
|
|
void* old_head = g_tls_sll_head[class_idx];
|
|
|
|
|
|
|
|
|
|
|
|
// Validate p alignment
|
|
|
|
|
|
if (((uintptr_t)p % blk) != 0) {
|
|
|
|
|
|
fprintf(stderr, "[DRAIN_CORRUPT] Freelist ptr=%p misaligned (cls=%d blk=%zu offset=%zu)\n",
|
|
|
|
|
|
p, class_idx, blk, (uintptr_t)p % blk);
|
|
|
|
|
|
fprintf(stderr, "[DRAIN_CORRUPT] Attempting to drain corrupted freelist to TLS SLL!\n");
|
|
|
|
|
|
fprintf(stderr, "[DRAIN_CORRUPT] ss=%p slab=%d moved=%d/%d\n", ss, slab_idx, moved, budget);
|
|
|
|
|
|
abort();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Validate old_head alignment if not NULL
|
|
|
|
|
|
if (old_head && ((uintptr_t)old_head % blk) != 0) {
|
|
|
|
|
|
fprintf(stderr, "[DRAIN_CORRUPT] TLS SLL head=%p already corrupted! (cls=%d blk=%zu offset=%zu)\n",
|
|
|
|
|
|
old_head, class_idx, blk, (uintptr_t)old_head % blk);
|
|
|
|
|
|
fprintf(stderr, "[DRAIN_CORRUPT] Corruption detected BEFORE drain write (ptr=%p)\n", p);
|
|
|
|
|
|
fprintf(stderr, "[DRAIN_CORRUPT] ss=%p slab=%d moved=%d/%d\n", ss, slab_idx, moved, budget);
|
|
|
|
|
|
abort();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, "[DRAIN_TO_SLL] cls=%d ptr=%p old_head=%p moved=%d/%d\n",
|
|
|
|
|
|
class_idx, p, old_head, moved, budget);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 12:31:14 +09:00
|
|
|
|
m->freelist = *(void**)p;
|
2025-11-10 16:48:20 +09:00
|
|
|
|
|
|
|
|
|
|
// Use Box TLS-SLL API (C7-safe push)
|
|
|
|
|
|
// Note: C7 already rejected at line 34, so this always succeeds
|
|
|
|
|
|
uint32_t sll_capacity = 256; // Conservative limit
|
|
|
|
|
|
if (tls_sll_push(class_idx, p, sll_capacity)) {
|
|
|
|
|
|
moved++;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// SLL full, stop draining
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2025-11-05 12:31:14 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static inline int tiny_remote_queue_contains_guard(SuperSlab* ss, int slab_idx, void* target) {
|
|
|
|
|
|
if (!ss || slab_idx < 0) return 0;
|
|
|
|
|
|
uintptr_t cur = atomic_load_explicit(&ss->remote_heads[slab_idx], memory_order_acquire);
|
|
|
|
|
|
int limit = 8192;
|
|
|
|
|
|
while (cur && limit-- > 0) {
|
|
|
|
|
|
if ((void*)cur == target) {
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
uintptr_t next;
|
|
|
|
|
|
if (__builtin_expect(g_remote_side_enable, 0)) {
|
|
|
|
|
|
next = tiny_remote_side_get(ss, slab_idx, (void*)cur);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
next = atomic_load_explicit((_Atomic uintptr_t*)cur, memory_order_relaxed);
|
|
|
|
|
|
}
|
|
|
|
|
|
cur = next;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (limit <= 0) {
|
|
|
|
|
|
return 1; // fail-safe: treat unbounded traversal as duplicate
|
|
|
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Phase 6.12.1: Free with pre-calculated slab (Option C - avoids duplicate lookup)
|
|
|
|
|
|
void hak_tiny_free_with_slab(void* ptr, TinySlab* slab) {
|
|
|
|
|
|
// Phase 7.6: slab == NULL means SuperSlab mode (Magazine integration)
|
|
|
|
|
|
if (!slab) {
|
|
|
|
|
|
// SuperSlab path: Get class_idx from SuperSlab
|
|
|
|
|
|
SuperSlab* ss = hak_super_lookup(ptr);
|
|
|
|
|
|
if (!ss || ss->magic != SUPERSLAB_MAGIC) return;
|
|
|
|
|
|
int class_idx = ss->size_class;
|
|
|
|
|
|
size_t ss_size = (size_t)1ULL << ss->lg_size;
|
|
|
|
|
|
uintptr_t ss_base = (uintptr_t)ss;
|
|
|
|
|
|
if (__builtin_expect(class_idx < 0 || class_idx >= TINY_NUM_CLASSES, 0)) {
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_SUPERSLAB_ADOPT_FAIL, (uint16_t)0xFFu, ss, (uintptr_t)ss->size_class);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
// Optional: cross-lookup TinySlab owner and detect class mismatch early
|
2025-11-10 01:59:11 +09:00
|
|
|
|
// Class7(1KB)はヘッダ無しのため、releaseでも軽量ガードを常時適用
|
|
|
|
|
|
// それ以外は従来どおり g_tiny_safe_free で切替
|
|
|
|
|
|
if (__builtin_expect(g_tiny_safe_free || class_idx == 7, 0)) {
|
2025-11-05 12:31:14 +09:00
|
|
|
|
TinySlab* ts = hak_tiny_owner_slab(ptr);
|
|
|
|
|
|
if (ts) {
|
|
|
|
|
|
int ts_cls = ts->class_idx;
|
|
|
|
|
|
if (ts_cls >= 0 && ts_cls < TINY_NUM_CLASSES && ts_cls != class_idx) {
|
|
|
|
|
|
uint32_t code = 0xAA00u | ((uint32_t)ts_cls & 0xFFu);
|
|
|
|
|
|
uintptr_t aux = tiny_remote_pack_diag(code, ss_base, ss_size, (uintptr_t)ptr);
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_REMOTE_INVALID, (uint16_t)class_idx, ptr, aux);
|
|
|
|
|
|
if (g_tiny_safe_free_strict) { raise(SIGUSR2); return; }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_FREE_ENTER, (uint16_t)class_idx, ptr, 0);
|
|
|
|
|
|
// Detect cross-thread: cross-thread free MUST go via superslab path
|
|
|
|
|
|
int slab_idx = slab_index_for(ss, ptr);
|
|
|
|
|
|
int ss_cap = ss_slabs_capacity(ss);
|
|
|
|
|
|
if (__builtin_expect(slab_idx < 0 || slab_idx >= ss_cap, 0)) {
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_SUPERSLAB_ADOPT_FAIL, (uint16_t)0xFEu, ss, (uintptr_t)slab_idx);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
TinySlabMeta* meta = &ss->slabs[slab_idx];
|
2025-11-10 01:59:11 +09:00
|
|
|
|
if (__builtin_expect(g_tiny_safe_free || class_idx == 7, 0)) {
|
2025-11-05 12:31:14 +09:00
|
|
|
|
size_t blk = g_tiny_class_sizes[class_idx];
|
|
|
|
|
|
uint8_t* base = tiny_slab_base_for(ss, slab_idx);
|
|
|
|
|
|
uintptr_t delta = (uintptr_t)ptr - (uintptr_t)base;
|
|
|
|
|
|
int cap_ok = (meta->capacity > 0) ? 1 : 0;
|
|
|
|
|
|
int align_ok = (delta % blk) == 0;
|
|
|
|
|
|
int range_ok = cap_ok && (delta / blk) < meta->capacity;
|
|
|
|
|
|
if (!align_ok || !range_ok) {
|
|
|
|
|
|
uint32_t code = 0xA104u;
|
|
|
|
|
|
if (align_ok) code |= 0x2u;
|
|
|
|
|
|
if (range_ok) code |= 0x1u;
|
|
|
|
|
|
uintptr_t aux = tiny_remote_pack_diag(code, ss_base, ss_size, (uintptr_t)ptr);
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_REMOTE_INVALID, (uint16_t)class_idx, ptr, aux);
|
2025-11-10 01:59:11 +09:00
|
|
|
|
if (g_tiny_safe_free_strict || class_idx == 7) { raise(SIGUSR2); return; }
|
2025-11-05 12:31:14 +09:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
uint32_t self_tid = tiny_self_u32();
|
|
|
|
|
|
if (__builtin_expect(meta->owner_tid != self_tid, 0)) {
|
|
|
|
|
|
// route directly to superslab (remote queue / freelist)
|
|
|
|
|
|
uintptr_t ptr_val = (uintptr_t)ptr;
|
|
|
|
|
|
uintptr_t ss_base = (uintptr_t)ss;
|
|
|
|
|
|
size_t ss_size = (size_t)1ULL << ss->lg_size;
|
|
|
|
|
|
if (__builtin_expect(ptr_val < ss_base || ptr_val >= ss_base + ss_size, 0)) {
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_SUPERSLAB_ADOPT_FAIL, (uint16_t)0xFDu, ss, ptr_val);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_FREE_REMOTE, (uint16_t)class_idx, ss, (uintptr_t)ptr);
|
|
|
|
|
|
hak_tiny_free_superslab(ptr, ss);
|
|
|
|
|
|
HAK_STAT_FREE(class_idx);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
Phase 1: Box Theory refactoring + include reduction
Phase 1-1: Split hakmem_tiny_free.inc (1,711 → 452 lines, -73%)
- Created tiny_free_magazine.inc.h (413 lines) - Magazine layer
- Created tiny_superslab_alloc.inc.h (394 lines) - SuperSlab alloc
- Created tiny_superslab_free.inc.h (305 lines) - SuperSlab free
Phase 1-2++: Refactor hakmem_pool.c (1,481 → 907 lines, -38.8%)
- Created pool_tls_types.inc.h (32 lines) - TLS structures
- Created pool_mf2_types.inc.h (266 lines) - MF2 data structures
- Created pool_mf2_helpers.inc.h (158 lines) - Helper functions
- Created pool_mf2_adoption.inc.h (129 lines) - Adoption logic
Phase 1-3: Reduce hakmem_tiny.c includes (60 → 46, -23.3%)
- Created tiny_system.h - System headers umbrella (stdio, stdlib, etc.)
- Created tiny_api.h - API headers umbrella (stats, query, rss, registry)
Performance: 4.19M ops/s maintained (±0% regression)
Verified: Larson benchmark 2×8×128×1024 = 4,192,128 ops/s
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 21:54:12 +09:00
|
|
|
|
// A/B: Force SS freelist path for same-thread frees (publish on first-free)
|
|
|
|
|
|
do {
|
|
|
|
|
|
static int g_free_to_ss2 = -1;
|
|
|
|
|
|
if (__builtin_expect(g_free_to_ss2 == -1, 0)) {
|
|
|
|
|
|
const char* e = getenv("HAKMEM_TINY_FREE_TO_SS");
|
|
|
|
|
|
g_free_to_ss2 = (e && *e && *e != '0') ? 1 : 0; // default OFF
|
|
|
|
|
|
}
|
|
|
|
|
|
if (g_free_to_ss2) {
|
|
|
|
|
|
hak_tiny_free_superslab(ptr, ss);
|
|
|
|
|
|
HAK_STAT_FREE(class_idx);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
} while (0);
|
|
|
|
|
|
|
2025-11-05 12:31:14 +09:00
|
|
|
|
if (__builtin_expect(g_debug_fast0, 0)) {
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_FRONT_BYPASS, (uint16_t)class_idx, ptr, (uintptr_t)slab_idx);
|
2025-11-10 16:48:20 +09:00
|
|
|
|
// Always operate on block base for C0-C6 (header lives at base)
|
|
|
|
|
|
void* base = (class_idx == 7) ? ptr : (void*)((uint8_t*)ptr - 1);
|
2025-11-05 12:31:14 +09:00
|
|
|
|
void* prev = meta->freelist;
|
2025-11-10 16:48:20 +09:00
|
|
|
|
*(void**)base = prev;
|
|
|
|
|
|
meta->freelist = base;
|
2025-11-05 12:31:14 +09:00
|
|
|
|
meta->used--;
|
|
|
|
|
|
ss_active_dec_one(ss);
|
|
|
|
|
|
if (prev == NULL) {
|
|
|
|
|
|
ss_partial_publish((int)ss->size_class, ss);
|
|
|
|
|
|
}
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_FREE_LOCAL, (uint16_t)class_idx, ptr, (uintptr_t)slab_idx);
|
|
|
|
|
|
HAK_STAT_FREE(class_idx);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (g_fast_enable && g_fast_cap[class_idx] != 0) {
|
2025-11-10 16:48:20 +09:00
|
|
|
|
// Push block base into fast cache
|
|
|
|
|
|
void* base = (class_idx == 7) ? ptr : (void*)((uint8_t*)ptr - 1);
|
|
|
|
|
|
if (tiny_fast_push(class_idx, base)) {
|
2025-11-05 12:31:14 +09:00
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_FREE_FAST, (uint16_t)class_idx, ptr, slab_idx);
|
|
|
|
|
|
HAK_STAT_FREE(class_idx);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (g_tls_list_enable) {
|
|
|
|
|
|
TinyTLSList* tls = &g_tls_lists[class_idx];
|
|
|
|
|
|
uint32_t seq = atomic_load_explicit(&g_tls_param_seq[class_idx], memory_order_relaxed);
|
|
|
|
|
|
if (__builtin_expect(seq != g_tls_param_seen[class_idx], 0)) {
|
|
|
|
|
|
tiny_tls_refresh_params(class_idx, tls);
|
|
|
|
|
|
}
|
|
|
|
|
|
// TinyHotMag front push(8/16/32B, A/B)
|
|
|
|
|
|
if (__builtin_expect(g_hotmag_enable && class_idx <= 2, 1)) {
|
2025-11-10 16:48:20 +09:00
|
|
|
|
void* base = (class_idx == 7) ? ptr : (void*)((uint8_t*)ptr - 1);
|
|
|
|
|
|
if (hotmag_push(class_idx, base)) {
|
2025-11-05 12:31:14 +09:00
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_FREE_RETURN_MAG, (uint16_t)class_idx, ptr, 1);
|
|
|
|
|
|
HAK_STAT_FREE(class_idx);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (tls->count < tls->cap) {
|
2025-11-10 16:48:20 +09:00
|
|
|
|
void* base = (class_idx == 7) ? ptr : (void*)((uint8_t*)ptr - 1);
|
|
|
|
|
|
tiny_tls_list_guard_push(class_idx, tls, base);
|
|
|
|
|
|
tls_list_push(tls, base);
|
2025-11-05 12:31:14 +09:00
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_FREE_LOCAL, (uint16_t)class_idx, ptr, 0);
|
|
|
|
|
|
HAK_STAT_FREE(class_idx);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
seq = atomic_load_explicit(&g_tls_param_seq[class_idx], memory_order_relaxed);
|
|
|
|
|
|
if (__builtin_expect(seq != g_tls_param_seen[class_idx], 0)) {
|
|
|
|
|
|
tiny_tls_refresh_params(class_idx, tls);
|
|
|
|
|
|
}
|
2025-11-10 16:48:20 +09:00
|
|
|
|
{
|
|
|
|
|
|
void* base = (class_idx == 7) ? ptr : (void*)((uint8_t*)ptr - 1);
|
|
|
|
|
|
tiny_tls_list_guard_push(class_idx, tls, base);
|
|
|
|
|
|
tls_list_push(tls, base);
|
|
|
|
|
|
}
|
2025-11-05 12:31:14 +09:00
|
|
|
|
if (tls_list_should_spill(tls)) {
|
|
|
|
|
|
tls_list_spill_excess(class_idx, tls);
|
|
|
|
|
|
}
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_FREE_LOCAL, (uint16_t)class_idx, ptr, 2);
|
|
|
|
|
|
HAK_STAT_FREE(class_idx);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
Phase 1: Box Theory refactoring + include reduction
Phase 1-1: Split hakmem_tiny_free.inc (1,711 → 452 lines, -73%)
- Created tiny_free_magazine.inc.h (413 lines) - Magazine layer
- Created tiny_superslab_alloc.inc.h (394 lines) - SuperSlab alloc
- Created tiny_superslab_free.inc.h (305 lines) - SuperSlab free
Phase 1-2++: Refactor hakmem_pool.c (1,481 → 907 lines, -38.8%)
- Created pool_tls_types.inc.h (32 lines) - TLS structures
- Created pool_mf2_types.inc.h (266 lines) - MF2 data structures
- Created pool_mf2_helpers.inc.h (158 lines) - Helper functions
- Created pool_mf2_adoption.inc.h (129 lines) - Adoption logic
Phase 1-3: Reduce hakmem_tiny.c includes (60 → 46, -23.3%)
- Created tiny_system.h - System headers umbrella (stdio, stdlib, etc.)
- Created tiny_api.h - API headers umbrella (stats, query, rss, registry)
Performance: 4.19M ops/s maintained (±0% regression)
Verified: Larson benchmark 2×8×128×1024 = 4,192,128 ops/s
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 21:54:12 +09:00
|
|
|
|
#include "tiny_free_magazine.inc.h"
|
2025-11-05 12:31:14 +09:00
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// Phase 6.23: SuperSlab Allocation Helpers
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
// Phase 6.24: Allocate from SuperSlab slab (lazy freelist + linear allocation)
|
Phase 1: Box Theory refactoring + include reduction
Phase 1-1: Split hakmem_tiny_free.inc (1,711 → 452 lines, -73%)
- Created tiny_free_magazine.inc.h (413 lines) - Magazine layer
- Created tiny_superslab_alloc.inc.h (394 lines) - SuperSlab alloc
- Created tiny_superslab_free.inc.h (305 lines) - SuperSlab free
Phase 1-2++: Refactor hakmem_pool.c (1,481 → 907 lines, -38.8%)
- Created pool_tls_types.inc.h (32 lines) - TLS structures
- Created pool_mf2_types.inc.h (266 lines) - MF2 data structures
- Created pool_mf2_helpers.inc.h (158 lines) - Helper functions
- Created pool_mf2_adoption.inc.h (129 lines) - Adoption logic
Phase 1-3: Reduce hakmem_tiny.c includes (60 → 46, -23.3%)
- Created tiny_system.h - System headers umbrella (stdio, stdlib, etc.)
- Created tiny_api.h - API headers umbrella (stats, query, rss, registry)
Performance: 4.19M ops/s maintained (±0% regression)
Verified: Larson benchmark 2×8×128×1024 = 4,192,128 ops/s
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 21:54:12 +09:00
|
|
|
|
#include "tiny_superslab_alloc.inc.h"
|
|
|
|
|
|
#include "tiny_superslab_free.inc.h"
|
2025-11-05 12:31:14 +09:00
|
|
|
|
|
|
|
|
|
|
void hak_tiny_free(void* ptr) {
|
2025-11-07 01:27:04 +09:00
|
|
|
|
// Track total tiny free calls (diagnostics)
|
|
|
|
|
|
extern _Atomic uint64_t g_hak_tiny_free_calls;
|
|
|
|
|
|
atomic_fetch_add_explicit(&g_hak_tiny_free_calls, 1, memory_order_relaxed);
|
2025-11-05 12:31:14 +09:00
|
|
|
|
if (!ptr || !g_tiny_initialized) return;
|
|
|
|
|
|
|
|
|
|
|
|
hak_tiny_stats_poll();
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_FREE_ENTER, 0, ptr, 0);
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAKMEM_TINY_BENCH_SLL_ONLY
|
|
|
|
|
|
// Bench-only SLL-only free: push to TLS SLL for ≤64B when possible
|
|
|
|
|
|
{
|
|
|
|
|
|
int class_idx = -1;
|
|
|
|
|
|
if (g_use_superslab) {
|
|
|
|
|
|
// FIXED: Use hak_super_lookup() instead of hak_super_lookup() to avoid false positives
|
|
|
|
|
|
SuperSlab* ss = hak_super_lookup(ptr);
|
|
|
|
|
|
if (ss && ss->magic == SUPERSLAB_MAGIC) class_idx = ss->size_class;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (class_idx < 0) {
|
|
|
|
|
|
TinySlab* slab = hak_tiny_owner_slab(ptr);
|
|
|
|
|
|
if (slab) class_idx = slab->class_idx;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (class_idx >= 0 && class_idx <= 3) {
|
|
|
|
|
|
uint32_t sll_cap = sll_cap_for_class(class_idx, (uint32_t)TINY_TLS_MAG_CAP);
|
|
|
|
|
|
if ((int)g_tls_sll_count[class_idx] < (int)sll_cap) {
|
2025-11-08 01:18:37 +09:00
|
|
|
|
// CORRUPTION DEBUG: Validate ptr and head before TLS SLL write
|
|
|
|
|
|
if (__builtin_expect(tiny_refill_failfast_level() >= 2, 0)) {
|
|
|
|
|
|
extern const size_t g_tiny_class_sizes[];
|
|
|
|
|
|
size_t blk = g_tiny_class_sizes[class_idx];
|
|
|
|
|
|
void* old_head = g_tls_sll_head[class_idx];
|
|
|
|
|
|
|
|
|
|
|
|
// Validate ptr alignment
|
|
|
|
|
|
if (((uintptr_t)ptr % blk) != 0) {
|
|
|
|
|
|
fprintf(stderr, "[FAST_FREE_CORRUPT] ptr=%p misaligned (cls=%d blk=%zu offset=%zu)\n",
|
|
|
|
|
|
ptr, class_idx, blk, (uintptr_t)ptr % blk);
|
|
|
|
|
|
fprintf(stderr, "[FAST_FREE_CORRUPT] Attempting to push corrupted pointer to TLS SLL!\n");
|
|
|
|
|
|
abort();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Validate old_head alignment if not NULL
|
|
|
|
|
|
if (old_head && ((uintptr_t)old_head % blk) != 0) {
|
|
|
|
|
|
fprintf(stderr, "[FAST_FREE_CORRUPT] TLS SLL head=%p already corrupted! (cls=%d blk=%zu offset=%zu)\n",
|
|
|
|
|
|
old_head, class_idx, blk, (uintptr_t)old_head % blk);
|
|
|
|
|
|
fprintf(stderr, "[FAST_FREE_CORRUPT] Corruption detected BEFORE fast free write (ptr=%p)\n", ptr);
|
|
|
|
|
|
abort();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, "[FAST_FREE] cls=%d ptr=%p old_head=%p count=%u\n",
|
|
|
|
|
|
class_idx, ptr, old_head, g_tls_sll_count[class_idx]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-10 16:48:20 +09:00
|
|
|
|
// Use Box TLS-SLL API (C7-safe push)
|
|
|
|
|
|
if (tls_sll_push(class_idx, ptr, sll_cap)) {
|
|
|
|
|
|
return; // Success
|
|
|
|
|
|
}
|
|
|
|
|
|
// Fall through if push fails (SLL full or C7)
|
2025-11-05 12:31:14 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
if (g_tiny_ultra) {
|
|
|
|
|
|
int class_idx = -1;
|
|
|
|
|
|
if (g_use_superslab) {
|
|
|
|
|
|
// FIXED: Use hak_super_lookup() instead of hak_super_lookup() to avoid false positives
|
|
|
|
|
|
SuperSlab* ss = hak_super_lookup(ptr);
|
|
|
|
|
|
if (ss && ss->magic == SUPERSLAB_MAGIC) class_idx = ss->size_class;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (class_idx < 0) {
|
|
|
|
|
|
TinySlab* slab = hak_tiny_owner_slab(ptr);
|
|
|
|
|
|
if (slab) class_idx = slab->class_idx;
|
|
|
|
|
|
}
|
2025-11-10 16:48:20 +09:00
|
|
|
|
// CRITICAL: C7 (1KB) is headerless - MUST NOT use TLS SLL
|
|
|
|
|
|
// Reason: SLL stores next pointer in first 8 bytes (user data for C7)
|
|
|
|
|
|
// Fix: Exclude C7 from ultra free path
|
|
|
|
|
|
if (class_idx >= 0 && class_idx != 7) {
|
2025-11-05 12:31:14 +09:00
|
|
|
|
// Ultra free: push directly to TLS SLL without magazine init
|
|
|
|
|
|
int sll_cap = ultra_sll_cap_for_class(class_idx);
|
|
|
|
|
|
if ((int)g_tls_sll_count[class_idx] < sll_cap) {
|
2025-11-08 01:18:37 +09:00
|
|
|
|
// CORRUPTION DEBUG: Validate ptr and head before TLS SLL write
|
|
|
|
|
|
if (__builtin_expect(tiny_refill_failfast_level() >= 2, 0)) {
|
|
|
|
|
|
extern const size_t g_tiny_class_sizes[];
|
|
|
|
|
|
size_t blk = g_tiny_class_sizes[class_idx];
|
|
|
|
|
|
void* old_head = g_tls_sll_head[class_idx];
|
|
|
|
|
|
|
|
|
|
|
|
// Validate ptr alignment
|
|
|
|
|
|
if (((uintptr_t)ptr % blk) != 0) {
|
|
|
|
|
|
fprintf(stderr, "[ULTRA_FREE_CORRUPT] ptr=%p misaligned (cls=%d blk=%zu offset=%zu)\n",
|
|
|
|
|
|
ptr, class_idx, blk, (uintptr_t)ptr % blk);
|
|
|
|
|
|
fprintf(stderr, "[ULTRA_FREE_CORRUPT] Attempting to push corrupted pointer to TLS SLL!\n");
|
|
|
|
|
|
abort();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Validate old_head alignment if not NULL
|
|
|
|
|
|
if (old_head && ((uintptr_t)old_head % blk) != 0) {
|
|
|
|
|
|
fprintf(stderr, "[ULTRA_FREE_CORRUPT] TLS SLL head=%p already corrupted! (cls=%d blk=%zu offset=%zu)\n",
|
|
|
|
|
|
old_head, class_idx, blk, (uintptr_t)old_head % blk);
|
|
|
|
|
|
fprintf(stderr, "[ULTRA_FREE_CORRUPT] Corruption detected BEFORE ultra free write (ptr=%p)\n", ptr);
|
|
|
|
|
|
abort();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, "[ULTRA_FREE] cls=%d ptr=%p old_head=%p count=%u\n",
|
|
|
|
|
|
class_idx, ptr, old_head, g_tls_sll_count[class_idx]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-10 16:48:20 +09:00
|
|
|
|
// Use Box TLS-SLL API (C7-safe push)
|
|
|
|
|
|
// Note: C7 already rejected at line 334
|
|
|
|
|
|
{
|
|
|
|
|
|
void* base = (class_idx == 7) ? ptr : (void*)((uint8_t*)ptr - 1);
|
|
|
|
|
|
if (tls_sll_push(class_idx, base, (uint32_t)sll_cap)) {
|
|
|
|
|
|
// CORRUPTION DEBUG: Verify write succeeded
|
|
|
|
|
|
if (__builtin_expect(tiny_refill_failfast_level() >= 2, 0)) {
|
|
|
|
|
|
void* readback = *(void**)base;
|
|
|
|
|
|
(void)readback;
|
|
|
|
|
|
void* new_head = g_tls_sll_head[class_idx];
|
|
|
|
|
|
if (new_head != base) {
|
|
|
|
|
|
fprintf(stderr, "[ULTRA_FREE_CORRUPT] Write verification failed! base=%p new_head=%p\n",
|
|
|
|
|
|
base, new_head);
|
|
|
|
|
|
abort();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return; // Success
|
2025-11-08 01:18:37 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-10 16:48:20 +09:00
|
|
|
|
// Fall through if push fails (SLL full)
|
2025-11-05 12:31:14 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// Fallback to existing path if class resolution fails
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SuperSlab* fast_ss = NULL;
|
|
|
|
|
|
TinySlab* fast_slab = NULL;
|
|
|
|
|
|
int fast_class_idx = -1;
|
|
|
|
|
|
if (g_use_superslab) {
|
|
|
|
|
|
fast_ss = hak_super_lookup(ptr);
|
|
|
|
|
|
if (fast_ss && fast_ss->magic == SUPERSLAB_MAGIC) {
|
|
|
|
|
|
fast_class_idx = fast_ss->size_class;
|
Phase 1: Box Theory refactoring + include reduction
Phase 1-1: Split hakmem_tiny_free.inc (1,711 → 452 lines, -73%)
- Created tiny_free_magazine.inc.h (413 lines) - Magazine layer
- Created tiny_superslab_alloc.inc.h (394 lines) - SuperSlab alloc
- Created tiny_superslab_free.inc.h (305 lines) - SuperSlab free
Phase 1-2++: Refactor hakmem_pool.c (1,481 → 907 lines, -38.8%)
- Created pool_tls_types.inc.h (32 lines) - TLS structures
- Created pool_mf2_types.inc.h (266 lines) - MF2 data structures
- Created pool_mf2_helpers.inc.h (158 lines) - Helper functions
- Created pool_mf2_adoption.inc.h (129 lines) - Adoption logic
Phase 1-3: Reduce hakmem_tiny.c includes (60 → 46, -23.3%)
- Created tiny_system.h - System headers umbrella (stdio, stdlib, etc.)
- Created tiny_api.h - API headers umbrella (stats, query, rss, registry)
Performance: 4.19M ops/s maintained (±0% regression)
Verified: Larson benchmark 2×8×128×1024 = 4,192,128 ops/s
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 21:54:12 +09:00
|
|
|
|
// BUGFIX: Validate size_class before using as array index (prevents OOB = 85% of FREE_TO_SS SEGV)
|
|
|
|
|
|
if (__builtin_expect(fast_class_idx < 0 || fast_class_idx >= TINY_NUM_CLASSES, 0)) {
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_REMOTE_INVALID, 0xF0, ptr, (uintptr_t)fast_class_idx);
|
|
|
|
|
|
if (g_tiny_safe_free_strict) { raise(SIGUSR2); return; }
|
|
|
|
|
|
fast_ss = NULL;
|
|
|
|
|
|
fast_class_idx = -1;
|
|
|
|
|
|
}
|
2025-11-05 12:31:14 +09:00
|
|
|
|
} else {
|
|
|
|
|
|
fast_ss = NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (fast_class_idx < 0) {
|
|
|
|
|
|
fast_slab = hak_tiny_owner_slab(ptr);
|
|
|
|
|
|
if (fast_slab) fast_class_idx = fast_slab->class_idx;
|
|
|
|
|
|
}
|
|
|
|
|
|
// Safety: detect class mismatch (SS vs TinySlab) early
|
|
|
|
|
|
if (__builtin_expect(g_tiny_safe_free && fast_class_idx >= 0, 0)) {
|
|
|
|
|
|
int ss_cls = -1, ts_cls = -1;
|
|
|
|
|
|
SuperSlab* chk_ss = fast_ss ? fast_ss : (g_use_superslab ? hak_super_lookup(ptr) : NULL);
|
|
|
|
|
|
if (chk_ss && chk_ss->magic == SUPERSLAB_MAGIC) ss_cls = chk_ss->size_class;
|
|
|
|
|
|
TinySlab* chk_slab = fast_slab ? fast_slab : hak_tiny_owner_slab(ptr);
|
|
|
|
|
|
if (chk_slab) ts_cls = chk_slab->class_idx;
|
|
|
|
|
|
if (ss_cls >= 0 && ts_cls >= 0 && ss_cls != ts_cls) {
|
|
|
|
|
|
uintptr_t packed = ((uintptr_t)(uint16_t)ss_cls << 16) | (uint16_t)ts_cls;
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_REMOTE_INVALID, (uint16_t)fast_class_idx, ptr, packed);
|
|
|
|
|
|
if (g_tiny_safe_free_strict) { raise(SIGUSR2); return; }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (fast_class_idx >= 0) {
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_FREE_ENTER, (uint16_t)fast_class_idx, ptr, 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (fast_class_idx >= 0 && g_fast_enable && g_fast_cap[fast_class_idx] != 0) {
|
2025-11-10 16:48:20 +09:00
|
|
|
|
void* base2 = (fast_class_idx == 7) ? ptr : (void*)((uint8_t*)ptr - 1);
|
|
|
|
|
|
if (tiny_fast_push(fast_class_idx, base2)) {
|
2025-11-05 12:31:14 +09:00
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_FREE_FAST, (uint16_t)fast_class_idx, ptr, 0);
|
|
|
|
|
|
HAK_STAT_FREE(fast_class_idx);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SuperSlab detection: prefer fast mask-based check when available
|
|
|
|
|
|
SuperSlab* ss = fast_ss;
|
|
|
|
|
|
if (!ss && g_use_superslab) {
|
|
|
|
|
|
ss = hak_super_lookup(ptr);
|
|
|
|
|
|
if (!(ss && ss->magic == SUPERSLAB_MAGIC)) {
|
|
|
|
|
|
ss = NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ss && ss->magic == SUPERSLAB_MAGIC) {
|
Phase 1: Box Theory refactoring + include reduction
Phase 1-1: Split hakmem_tiny_free.inc (1,711 → 452 lines, -73%)
- Created tiny_free_magazine.inc.h (413 lines) - Magazine layer
- Created tiny_superslab_alloc.inc.h (394 lines) - SuperSlab alloc
- Created tiny_superslab_free.inc.h (305 lines) - SuperSlab free
Phase 1-2++: Refactor hakmem_pool.c (1,481 → 907 lines, -38.8%)
- Created pool_tls_types.inc.h (32 lines) - TLS structures
- Created pool_mf2_types.inc.h (266 lines) - MF2 data structures
- Created pool_mf2_helpers.inc.h (158 lines) - Helper functions
- Created pool_mf2_adoption.inc.h (129 lines) - Adoption logic
Phase 1-3: Reduce hakmem_tiny.c includes (60 → 46, -23.3%)
- Created tiny_system.h - System headers umbrella (stdio, stdlib, etc.)
- Created tiny_api.h - API headers umbrella (stats, query, rss, registry)
Performance: 4.19M ops/s maintained (±0% regression)
Verified: Larson benchmark 2×8×128×1024 = 4,192,128 ops/s
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 21:54:12 +09:00
|
|
|
|
// BUGFIX: Validate size_class before using as array index (prevents OOB)
|
|
|
|
|
|
if (__builtin_expect(ss->size_class < 0 || ss->size_class >= TINY_NUM_CLASSES, 0)) {
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_REMOTE_INVALID, 0xF2, ptr, (uintptr_t)ss->size_class);
|
|
|
|
|
|
if (g_tiny_safe_free_strict) { raise(SIGUSR2); return; }
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-11-05 12:31:14 +09:00
|
|
|
|
// Direct SuperSlab free (avoid second lookup TOCTOU)
|
|
|
|
|
|
hak_tiny_free_superslab(ptr, ss);
|
|
|
|
|
|
HAK_STAT_FREE(ss->size_class);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Fallback to TinySlab only when SuperSlab is not in use
|
|
|
|
|
|
TinySlab* slab = fast_slab;
|
|
|
|
|
|
if (!slab) slab = hak_tiny_owner_slab(ptr);
|
|
|
|
|
|
if (!slab) return; // Not managed by Tiny Pool
|
|
|
|
|
|
if (__builtin_expect(g_use_superslab, 0)) {
|
|
|
|
|
|
// In SS mode, a pointer that resolves only to TinySlab is suspicious → treat as invalid free
|
|
|
|
|
|
tiny_debug_ring_record(TINY_RING_EVENT_REMOTE_INVALID, 0xEE, ptr, 0xF1u);
|
|
|
|
|
|
if (g_tiny_safe_free_strict) { raise(SIGUSR2); return; }
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
hak_tiny_free_with_slab(ptr, slab);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// EXTRACTED TO hakmem_tiny_query.c (Phase 2B-1)
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// EXTRACTED: int hak_tiny_is_managed(void* ptr) {
|
|
|
|
|
|
// EXTRACTED: if (!ptr || !g_tiny_initialized) return 0;
|
|
|
|
|
|
// EXTRACTED: // Phase 6.12.1: O(1) slab lookup via registry/list
|
|
|
|
|
|
// EXTRACTED: return hak_tiny_owner_slab(ptr) != NULL || hak_super_lookup(ptr) != NULL;
|
|
|
|
|
|
// EXTRACTED: }
|
|
|
|
|
|
|
|
|
|
|
|
// Phase 7.6: Check if pointer is managed by Tiny Pool (TinySlab OR SuperSlab)
|
|
|
|
|
|
// EXTRACTED: int hak_tiny_is_managed_superslab(void* ptr) {
|
|
|
|
|
|
// EXTRACTED: if (!ptr || !g_tiny_initialized) return 0;
|
|
|
|
|
|
// EXTRACTED:
|
|
|
|
|
|
// EXTRACTED: // Safety: Only check if g_use_superslab is enabled
|
|
|
|
|
|
// EXTRACTED: if (g_use_superslab) {
|
|
|
|
|
|
// EXTRACTED: SuperSlab* ss = hak_super_lookup(ptr);
|
|
|
|
|
|
// EXTRACTED: // Phase 8.2 optimization: Use alignment check instead of mincore()
|
|
|
|
|
|
// EXTRACTED: // SuperSlabs are always SUPERSLAB_SIZE-aligned (2MB)
|
|
|
|
|
|
// EXTRACTED: if (ss && ((uintptr_t)ss & (SUPERSLAB_SIZE - 1)) == 0) {
|
|
|
|
|
|
// EXTRACTED: if (ss->magic == SUPERSLAB_MAGIC) {
|
|
|
|
|
|
// EXTRACTED: return 1; // Valid SuperSlab pointer
|
|
|
|
|
|
// EXTRACTED: }
|
|
|
|
|
|
// EXTRACTED: }
|
|
|
|
|
|
// EXTRACTED: }
|
|
|
|
|
|
// EXTRACTED:
|
|
|
|
|
|
// EXTRACTED: // Fallback to TinySlab check
|
|
|
|
|
|
// EXTRACTED: return hak_tiny_owner_slab(ptr) != NULL;
|
|
|
|
|
|
// EXTRACTED: }
|
|
|
|
|
|
|
|
|
|
|
|
// Return the usable size for a Tiny-managed pointer (0 if unknown/not tiny).
|
|
|
|
|
|
// Prefer SuperSlab metadata when available; otherwise use TinySlab owner class.
|
|
|
|
|
|
// EXTRACTED: size_t hak_tiny_usable_size(void* ptr) {
|
|
|
|
|
|
// EXTRACTED: if (!ptr || !g_tiny_initialized) return 0;
|
|
|
|
|
|
// EXTRACTED:
|
|
|
|
|
|
// EXTRACTED: // Check SuperSlab first via registry (safe under direct link and LD)
|
|
|
|
|
|
// EXTRACTED: if (g_use_superslab) {
|
|
|
|
|
|
// EXTRACTED: SuperSlab* ss = hak_super_lookup(ptr);
|
|
|
|
|
|
// EXTRACTED: if (ss && ss->magic == SUPERSLAB_MAGIC) {
|
|
|
|
|
|
// EXTRACTED: int k = (int)ss->size_class;
|
|
|
|
|
|
// EXTRACTED: if (k >= 0 && k < TINY_NUM_CLASSES) {
|
|
|
|
|
|
// EXTRACTED: return g_tiny_class_sizes[k];
|
|
|
|
|
|
// EXTRACTED: }
|
|
|
|
|
|
// EXTRACTED: }
|
|
|
|
|
|
// EXTRACTED: }
|
|
|
|
|
|
// EXTRACTED:
|
|
|
|
|
|
// EXTRACTED: // Fallback: TinySlab owner lookup
|
|
|
|
|
|
// EXTRACTED: TinySlab* slab = hak_tiny_owner_slab(ptr);
|
|
|
|
|
|
// EXTRACTED: if (slab) {
|
|
|
|
|
|
// EXTRACTED: int k = slab->class_idx;
|
|
|
|
|
|
// EXTRACTED: if (k >= 0 && k < TINY_NUM_CLASSES) {
|
|
|
|
|
|
// EXTRACTED: return g_tiny_class_sizes[k];
|
|
|
|
|
|
// EXTRACTED: }
|
|
|
|
|
|
// EXTRACTED: }
|
|
|
|
|
|
// EXTRACTED: return 0;
|
|
|
|
|
|
// EXTRACTED: }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// Statistics and Debug Functions - Extracted to hakmem_tiny_stats.c
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// (Phase 2B API headers moved to top of file)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Optional shutdown hook to stop background components (e.g., Intelligence Engine)
|
|
|
|
|
|
void hak_tiny_shutdown(void) {
|
|
|
|
|
|
// Release TLS SuperSlab references (dec refcount) before stopping BG/INT
|
|
|
|
|
|
for (int k = 0; k < TINY_NUM_CLASSES; k++) {
|
|
|
|
|
|
TinyTLSSlab* tls = &g_tls_slabs[k];
|
|
|
|
|
|
if (tls->ss) {
|
|
|
|
|
|
superslab_ref_dec(tls->ss);
|
|
|
|
|
|
tls->ss = NULL;
|
|
|
|
|
|
tls->meta = NULL;
|
|
|
|
|
|
tls->slab_base = NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (g_bg_bin_started) {
|
|
|
|
|
|
g_bg_bin_stop = 1;
|
|
|
|
|
|
if (!pthread_equal(tiny_self_pt(), g_bg_bin_thread)) {
|
|
|
|
|
|
pthread_join(g_bg_bin_thread, NULL);
|
|
|
|
|
|
}
|
|
|
|
|
|
g_bg_bin_started = 0;
|
|
|
|
|
|
g_bg_bin_enable = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
tiny_obs_shutdown();
|
|
|
|
|
|
if (g_int_engine && g_int_started) {
|
|
|
|
|
|
g_int_stop = 1;
|
|
|
|
|
|
// Best-effort join; avoid deadlock if called from within the thread
|
|
|
|
|
|
if (!pthread_equal(tiny_self_pt(), g_int_thread)) {
|
|
|
|
|
|
pthread_join(g_int_thread, NULL);
|
|
|
|
|
|
}
|
|
|
|
|
|
g_int_started = 0;
|
|
|
|
|
|
g_int_engine = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Always-available: Trim empty slabs (release fully-free slabs)
|