// free_remote_box.h - Box: Cross-thread free to remote queue (transition publishes) #pragma once #include #include #include #include "hakmem_tiny_superslab.h" #include "ptr_type_box.h" // Phase 10 #include "free_publish_box.h" #include "hakmem_tiny.h" #include "hakmem_tiny_integrity.h" // HAK_CHECK_CLASS_IDX // Performs remote push. On transition (0->nonzero), publishes via Ready/Mailbox. // Returns 1 if transition occurred, 0 otherwise. static inline int tiny_free_remote_box(SuperSlab* ss, int slab_idx, TinySlabMeta* meta, hak_base_ptr_t base, uint32_t my_tid) { extern _Atomic uint64_t g_free_remote_box_calls; atomic_fetch_add_explicit(&g_free_remote_box_calls, 1, memory_order_relaxed); if (!(ss && ss->magic == SUPERSLAB_MAGIC)) return 0; if (slab_idx < 0 || slab_idx >= ss_slabs_capacity(ss)) return 0; (void)my_tid; void* raw_base = HAK_BASE_TO_RAW(base); // BUGFIX: Decrement used BEFORE remote push to maintain visibility consistency // Remote push uses memory_order_release, so drainer must see updated used count uint8_t cls_raw = meta ? meta->class_idx : 0xFFu; HAK_CHECK_CLASS_IDX((int)cls_raw, "tiny_free_remote_box"); if (__builtin_expect(cls_raw >= TINY_NUM_CLASSES, 0)) { static _Atomic int g_remote_push_cls_oob = 0; if (atomic_fetch_add_explicit(&g_remote_push_cls_oob, 1, memory_order_relaxed) == 0) { fprintf(stderr, "[REMOTE_PUSH_CLASS_OOB] ss=%p slab_idx=%d meta=%p cls=%u ptr=%p\n", (void*)ss, slab_idx, (void*)meta, (unsigned)cls_raw, raw_base); } return 0; } meta->used--; int transitioned = ss_remote_push(ss, slab_idx, raw_base); // ss_active_dec_one() called inside // ss_active_dec_one(ss); // REMOVED: Already called inside ss_remote_push() if (transitioned) { // Phase 12: use per-slab class for publish metadata uint8_t cls = (meta && meta->class_idx < TINY_NUM_CLASSES) ? meta->class_idx : 0; tiny_free_publish_remote_transition((int)cls, ss, slab_idx); return 1; } return 0; }