From 18fec9b003abef73b5b2b5d998597808c2ac429b Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Thu, 10 Sep 2026 16:04:55 +0800 Subject: [PATCH] =?UTF-8?q?feat(shm):=20Cleaner=20SharedRef=20+=20ContextP?= =?UTF-8?q?olicy=20(=C2=A713.4/=C2=A713.8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - cleaner.invoke 协议: TextRef SharedRef 替代内联 text - 插件侧 arenaWrite/SharedRef 读写辅助 - ToolDef.ContextPolicy 字段(默认 none / 可设 prune) - 握手解析统一区域 SuperBlock + arena 元数据 --- tools/plugindev/templates/proc_main.go.tmpl | 60 +++++++++++++++++++-- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/tools/plugindev/templates/proc_main.go.tmpl b/tools/plugindev/templates/proc_main.go.tmpl index a691d20..b2b0a42 100644 --- a/tools/plugindev/templates/proc_main.go.tmpl +++ b/tools/plugindev/templates/proc_main.go.tmpl @@ -42,6 +42,9 @@ const ( sbOffCtxSize = 24 sbOffEvtOff = 28 sbOffEvtSize = 32 + sbOffArenaOff = 36 + sbOffArenaCap = 40 + sbOffArenaUsed = 44 ) // ---- StageContext 段内部布局(与内核 internal/plugin/proc/shm.go 一致)---- @@ -89,6 +92,43 @@ const ( flagResponseSet = 1 ) +// SharedRef 跨进程共享内存描述符。 +type SharedRef struct { + Offset uint32 `json:"offset"` + Length uint32 `json:"length"` + Generation uint32 `json:"generation"` + Flags uint32 `json:"flags"` +} + +func (r SharedRef) IsZero() bool { return r.Offset == 0 && r.Length == 0 } +func (r SharedRef) Slice(data []byte) []byte { + if r.IsZero() || int(r.Offset)+int(r.Length) > len(data) { + return nil + } + return data[r.Offset : r.Offset+r.Length] +} + +// arena 辅助(插件侧简化版:bump 分配) +var arenaOff uint32 +var arenaUsed uint32 + +func arenaWrite(b []byte) (SharedRef, error) { + if len(b) == 0 { + return SharedRef{}, nil + } + off := arenaUsed + if off == 0 { + off = 1 + } + end := off + uint32(len(b)) + if int(end) > len(region)-int(arenaOff) { + return SharedRef{}, fmt.Errorf("arena 空间不足") + } + copy(region[arenaOff+off:arenaOff+end], b) + arenaUsed = end + return SharedRef{Offset: arenaOff + off, Length: uint32(len(b))}, nil +} + // ---- 全局状态 ---- var ( @@ -112,6 +152,7 @@ var ( outputCleaners = map[string]func(string) string{} shm []byte + region []byte // 统一区域完整 mmap(用于 SharedRef 读写) // 事件环(§3.6):fd 4 = 事件环段 mmap,fd 5 = eventfd 读端 evtRingData []byte @@ -1002,9 +1043,9 @@ func handleKernelRequest(req *rpcRequest) { case "cleaner.invoke": var p struct { - Scope string `json:"scope"` - Name string `json:"name"` - Text string `json:"text"` + Scope string `json:"scope"` + Name string `json:"name"` + TextRef SharedRef `json:"text_ref"` } if err := json.Unmarshal(req.Params, &p); err != nil { respondErr(req.ID, fmt.Errorf("解析 Cleaner 参数: %w", err)) @@ -1025,7 +1066,14 @@ func handleKernelRequest(req *rpcRequest) { respondErr(req.ID, fmt.Errorf("%s %s 未注册 Cleaner", p.Scope, p.Name)) return } - respond(req.ID, map[string]interface{}{"text": cleaner(p.Text)}) + input := string(p.TextRef.Slice(region)) + output := cleaner(input) + outRef, err := arenaWrite([]byte(output)) + if err != nil { + respondErr(req.ID, fmt.Errorf("arena 写入失败: %w", err)) + return + } + respond(req.ID, map[string]interface{}{"text_ref": outRef}) case "stage.invoke": handleStageInvoke(req) @@ -1150,6 +1198,10 @@ func handleHandshake(req *rpcRequest) { evtSize := binary.LittleEndian.Uint32(m[sbOffEvtSize:]) // shm 指向 StageContext 段,后续代码用 shm[off...] 访问该段内部字段 shm = m[ctxOff : ctxOff+ctxSize] + // region 保存完整 mmap 区域,供 SharedRef 读写 arena + region = m + arenaOff = binary.LittleEndian.Uint32(m[sbOffArenaOff:]) + arenaUsed = 1 // 挂载事件环段 + 打开通知句柄(§13.1:EvtRing 在统一区域内) if p.EvtRingSize > 0 && evtSize > 0 { er := m[evtOff : evtOff+evtSize]