feat(shm): ToolCall ring buffer(§13.3) — 栈帧模型 ring,push/pop 帧状态机

- ToolCallRing: 定长帧 ring buffer (64 frames × 112B),状态机 FREE→CALLING→READING→READY→FREE
- Reserve: 环形扫描找 FREE 帧,全忙返回 ErrToolCallRingFull 背压
- SharedRef: pack/unpack 辅助函数
- unified.go: arena 分配器(arenaAlloc/arenaWrite/arenaRead)
- 5 个单测覆盖 init/reserve/背压/find/reuse
This commit is contained in:
JianFeeeee
2026-09-10 12:33:58 +08:00
parent 09c8bce59c
commit 6682710e43
2 changed files with 415 additions and 0 deletions

View File

@ -0,0 +1,166 @@
package proc
import (
"testing"
"unsafe"
)
func TestToolCallRing_InitAndReserve(t *testing.T) {
arenaSize := 256 * 1024
size := superBlockSize + int(shmDefaultSize) + int(evtTotalSize) + arenaSize + int(trlOffFrameBase+toolRingCap*toolFrameSize)
data := make([]byte, size)
putU32(data[0:], unifiedMagic)
putU32(data[4:], unifiedVersion)
putU32(data[16:], uint32(size))
ringData := data[size-int(trlOffFrameBase+toolRingCap*toolFrameSize) : size]
if err := InitToolRing(ringData); err != nil {
t.Fatalf("InitToolRing: %v", err)
}
ring, err := AttachToolRing(ringData)
if err != nil {
t.Fatalf("AttachToolRing: %v", err)
}
if ring.cap != toolRingCap {
t.Fatalf("cap: got %d, want %d", ring.cap, toolRingCap)
}
// Reserve 帧应成功
idx, err := ring.Reserve()
if err != nil {
t.Fatalf("Reserve: %v", err)
}
if idx != 0 {
t.Fatalf("首帧 index: got %d, want 0", idx)
}
// SetCalling -> GetCallingFrame -> SetReady -> GetReadyFrame -> ReleaseFrame
inputRef := SharedRef{Offset: 1024, Length: 100, Generation: 0, Flags: 1}
ring.SetCalling(idx, 42, "demo_upper", inputRef)
name, gotInput := ring.GetCallingFrame(idx)
if name != "demo_upper" {
t.Fatalf("GetCallingFrame name: got %q, want %q", name, "demo_upper")
}
if gotInput.Offset != 1024 || gotInput.Length != 100 {
t.Fatalf("GetCallingFrame input: got %+v", gotInput)
}
ring.SetReading(idx)
outputRef := SharedRef{Offset: 2048, Length: 50, Generation: 0, Flags: 0}
ring.SetReady(idx, outputRef)
reqID, gotOutput := ring.GetReadyFrame(idx)
if reqID != 42 {
t.Fatalf("GetReadyFrame reqID: got %d, want 42", reqID)
}
if gotOutput.Offset != 2048 || gotOutput.Length != 50 {
t.Fatalf("GetReadyFrame output: got %+v", gotOutput)
}
ring.ReleaseFrame(idx)
// 释放后应能重用
idx2, err := ring.Reserve()
if err != nil {
t.Fatalf("Reserve after release: %v", err)
}
if idx2 != 1 {
t.Fatalf("第二帧 index: got %d, want 1", idx2)
}
}
func TestToolCallRing_FullBackpressure(t *testing.T) {
size := int(toolRingCap)*int(toolFrameSize) + 64*1024
data := make([]byte, size)
if err := InitToolRing(data); err != nil {
t.Fatalf("InitToolRing: %v", err)
}
ring, err := AttachToolRing(data)
if err != nil {
t.Fatalf("AttachToolRing: %v", err)
}
// Reserve 所有帧
for i := uint32(0); i < toolRingCap; i++ {
idx, err := ring.Reserve()
if err != nil {
t.Fatalf("Reserve %d: %v", i, err)
}
ring.SetCalling(idx, uint64(i+1), "tool", SharedRef{})
ring.SetReading(idx)
// 不释放
}
// 再 Reserve 应失败(背压)
_, err = ring.Reserve()
if err != ErrToolCallRingFull {
t.Fatalf("满帧后 Reserve 应返回 ErrToolCallRingFull,实际: %v", err)
}
// 释放一帧后应恢复
ring.ReleaseFrame(0)
idx, err := ring.Reserve()
if err != nil {
t.Fatalf("释放后 Reserve: %v", err)
}
_ = idx
}
func TestToolCallRing_FindFrameByReqID(t *testing.T) {
size := int(toolRingCap)*int(toolFrameSize) + 64*1024
data := make([]byte, size)
if err := InitToolRing(data); err != nil {
t.Fatal(err)
}
ring, _ := AttachToolRing(data)
// 没有帧时应找不到
_, err := ring.FindFrameByReqID(999)
if err != ErrToolCallNotFound {
t.Fatalf("空 ring 应返回 ErrToolCallNotFound,实际: %v", err)
}
// Reserve + SetCalling 后应能找到
idx, _ := ring.Reserve()
ring.SetCalling(idx, 100, "tool_a", SharedRef{})
ring.SetReading(idx)
found, err := ring.FindFrameByReqID(100)
if err != nil {
t.Fatalf("FindFrameByReqID: %v", err)
}
if found != idx {
t.Fatalf("FindFrameByReqID: got %d, want %d", found, idx)
}
// Release 后应找不到
ring.ReleaseFrame(idx)
_, err = ring.FindFrameByReqID(100)
if err != ErrToolCallNotFound {
t.Fatalf("释放后应找不到,实际: %v", err)
}
}
func TestSharedRef_PackUnpack(t *testing.T) {
b := make([]byte, sharedRefSize)
ref := SharedRef{Offset: 1024, Length: 256, Generation: 7, Flags: 3}
packSharedRef(b, ref)
got := unpackSharedRef(b)
if got.Offset != ref.Offset || got.Length != ref.Length || got.Generation != ref.Generation || got.Flags != ref.Flags {
t.Fatalf("pack/unpack: got %+v, want %+v", got, ref)
}
}
func TestToolFrameLayoutAligned(t *testing.T) {
// 确保帧布局字段偏移与内存布局一致(安全断言)
var frame toolFrame
off := func(ptr *uint32) uint32 {
return uint32(uintptr(unsafe.Pointer(ptr)) - uintptr(unsafe.Pointer(&frame)))
}
if off(&frame.state) != toolFrameOffState {
t.Errorf("state offset: got %d, want %d", off(&frame.state), toolFrameOffState)
}
}