SlabHandle Box (Ownership + Remote Drain + Metadata) =================================================== 目的 - Slab 単位の操作を「所有権を持つハンドル」でカプセル化し、境界の 1 箇所化と不変条件の自動チェックを実現する。 - 下層(RemoteQueue / Ownership)の堅牢性を高め、上層(Publish/Adopt)が壊れない土台を作る。 ファイル - core/slab_handle.h(約 100 行) 型 - `SlabHandle { ss, meta, slab_idx, owner_tid, valid }` - `valid==1` のときのみ drain/modify が可能。 API - `slab_try_acquire(ss, idx, tid) -> SlabHandle` - `owner_tid==0` の場合のみ CAS で取得し、`valid=1` のハンドルを返す。 - `slab_drain_remote(&h)` - `valid==1` 必須。RemoteQueue → freelist へ統合。`remote_counts` を 0 に。 - `slab_release(&h)` - `owner_tid=0` に戻し、`valid=0` にする(明示的に解放したい場合)。 - アクセサ: `slab_meta(&h)`, `slab_freelist(&h)`, `slab_used(&h)`, `slab_capacity(&h)`, `slab_is_valid(&h)` - 便宜操作: `slab_freelist_push(&h, ptr)`, `slab_freelist_pop(&h)`(いずれも `valid==1` 必須) 不変条件(Invariants) - RemoteQueue(Box 2)は push/exchange と `remote_counts` の整合のみ扱い、owner/freelist には触れない。 - Ownership(Box 3)は `owner_tid==0` からの取得と release のみ扱い、RemoteQueue には触れない。 - Refill 採用境界 1 箇所でのみ `drain → bind → owner_acquire` を行う。 適用箇所(6 箇所) - `tiny_refill.h`: Sticky / Hot / Bench / Mailbox 採用分岐 - `tiny_mmap_gate.h`: Registry scan 採用 - `hakmem_tiny_free.inc`: SuperSlab adopt path アンチパターンの禁止(Do/Don’t) - Don’t: publish 側で drain / owner を弄る(通知とヒントのみに限定)。 - Don’t: RemoteQueue が freelist/owner に触る。 - Do: 採用境界でのみ `slab_try_acquire` → `slab_drain_remote` → `bind` の順で処理。 デバッグ TIPS - `HAKMEM_SAFE_FREE=1`: free 境界での範囲/クラス不一致の Fail‑Fast。 - `HAKMEM_TINY_TRACE_RING=1 + SIGUSR2`: `remote_push/remote_drain/mailbox_publish/mailbox_fetch/bind` を確認。 - `HAKMEM_TINY_RF_FORCE_NOTIFY=1`: 初回通知の見逃しが疑われるケースの可視化。 既知の現象(追跡中) - `fault_addr=0x6261`、`free_enter` が同一 `ptr` で異なる `class` に跨って記録されるケースがある。 - 読み: free 境界のクラス判定(lookup)または直前の bind/owner の不整合。 - 対処: 上記 Fail‑Fast を既定 ON(デバッグ期間)、Ring の直前イベントで境界のどこでズレたかを特定。 関連修正(所有権なし drain の是正) - `hakmem_tiny_superslab.h:376` 付近: `ss_remote_drain_light()` が所有権チェックなしで drain していた問題を修正。 - 修正方針: `ss_owner_try_acquire()` 成功時にのみ `ss_remote_drain_to_freelist()` を実行(Box 3→2 の順)。