mirror of
https://gitcode.com/JianFeeeee/homeagent-sdk.git
synced 2026-09-21 01:18:02 +00:00
feat(shm): 统一共享内存区域(§13.1) — 子进程侧模板适配
- proc_shm_unix.go.tmpl: fd 3 = 统一区域,fd 4 = eventfd - proc_main.go.tmpl: 握手解析 SuperBlock,从 ctxOff/evtOff 定位两段 - 新增 unified region 常量(magic/version/offset) + StageContext 内部布局常量
This commit is contained in:
@ -27,7 +27,24 @@ import (
|
||||
|
||||
const procProtocolVersion = 1
|
||||
|
||||
// ---- 共享段布局(须与内核 internal/plugin/proc/shm.go 一致)----
|
||||
// ---- 统一共享内存区域布局(与内核 internal/plugin/proc/unified.go 一致)----
|
||||
|
||||
const (
|
||||
unifiedMagic = 0x554D5352 // "UMSR" — Unified Memory Shared Region
|
||||
unifiedVersion = 1
|
||||
superBlockSize = 64
|
||||
|
||||
sbOffMagic = 0
|
||||
sbOffVersion = 4
|
||||
sbOffGeneration = 8
|
||||
sbOffCapacity = 16
|
||||
sbOffCtxOff = 20
|
||||
sbOffCtxSize = 24
|
||||
sbOffEvtOff = 28
|
||||
sbOffEvtSize = 32
|
||||
)
|
||||
|
||||
// ---- StageContext 段内部布局(与内核 internal/plugin/proc/shm.go 一致)----
|
||||
|
||||
const (
|
||||
shmStageFieldCount = 18
|
||||
@ -88,8 +105,11 @@ var (
|
||||
|
||||
handlerMu sync.RWMutex
|
||||
toolHandlers = map[string]sdk.ToolHandler{}
|
||||
toolCleaners = map[string]func(string) string{}
|
||||
inputCleaners = map[string]func(string) string{}
|
||||
stageHandlers = map[string]sdk.StageHandler{}
|
||||
outputHandlers = map[string]sdk.ToolHandler{}
|
||||
outputCleaners = map[string]func(string) string{}
|
||||
|
||||
shm []byte
|
||||
|
||||
@ -416,9 +436,14 @@ func buildPluginSDK(name string) *sdk.PluginSDK {
|
||||
func(toolName string, def sdk.ToolDef, handler sdk.ToolHandler) error {
|
||||
handlerMu.Lock()
|
||||
toolHandlers[toolName] = handler
|
||||
if def.Cleaner != nil {
|
||||
toolCleaners[toolName] = def.Cleaner
|
||||
} else {
|
||||
delete(toolCleaners, toolName)
|
||||
}
|
||||
handlerMu.Unlock()
|
||||
return callCoreVoid("tool.register", map[string]interface{}{
|
||||
"name": toolName, "def": def,
|
||||
"name": toolName, "def": def, "has_cleaner": def.Cleaner != nil,
|
||||
})
|
||||
},
|
||||
func(stage sdk.Stage, handler sdk.StageHandler) {
|
||||
@ -437,10 +462,16 @@ func buildPluginSDK(name string) *sdk.PluginSDK {
|
||||
func(chName string, caps int, desc string, def sdk.ChannelDef, handler sdk.ToolHandler) error {
|
||||
handlerMu.Lock()
|
||||
outputHandlers[chName] = handler
|
||||
if def.Cleaner != nil {
|
||||
outputCleaners[chName] = def.Cleaner
|
||||
} else {
|
||||
delete(outputCleaners, chName)
|
||||
}
|
||||
handlerMu.Unlock()
|
||||
return callCoreVoid("output.register", map[string]interface{}{
|
||||
"name": chName, "caps": caps, "desc": desc,
|
||||
"def": map[string]interface{}{"NoMemory": def.NoMemory},
|
||||
"has_cleaner": def.Cleaner != nil,
|
||||
})
|
||||
},
|
||||
)
|
||||
@ -454,9 +485,17 @@ func buildPluginSDK(name string) *sdk.PluginSDK {
|
||||
base.SetTextMemoryAPI(procTextMemory{})
|
||||
base.SetPluginMgrAPI(procPluginMgr{})
|
||||
base.SetInputChannelRegistrar(func(chName string, def sdk.ChannelDef) error {
|
||||
handlerMu.Lock()
|
||||
if def.Cleaner != nil {
|
||||
inputCleaners[chName] = def.Cleaner
|
||||
} else {
|
||||
delete(inputCleaners, chName)
|
||||
}
|
||||
handlerMu.Unlock()
|
||||
return callCoreVoid("input.register", map[string]interface{}{
|
||||
"name": chName,
|
||||
"def": map[string]interface{}{"NoMemory": def.NoMemory},
|
||||
"has_cleaner": def.Cleaner != nil,
|
||||
})
|
||||
})
|
||||
return base
|
||||
@ -961,6 +1000,33 @@ func handleKernelRequest(req *rpcRequest) {
|
||||
}
|
||||
respond(req.ID, map[string]interface{}{"result": res})
|
||||
|
||||
case "cleaner.invoke":
|
||||
var p struct {
|
||||
Scope string `json:"scope"`
|
||||
Name string `json:"name"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
if err := json.Unmarshal(req.Params, &p); err != nil {
|
||||
respondErr(req.ID, fmt.Errorf("解析 Cleaner 参数: %w", err))
|
||||
return
|
||||
}
|
||||
handlerMu.RLock()
|
||||
var cleaner func(string) string
|
||||
switch p.Scope {
|
||||
case "tool":
|
||||
cleaner = toolCleaners[p.Name]
|
||||
case "input":
|
||||
cleaner = inputCleaners[p.Name]
|
||||
case "output":
|
||||
cleaner = outputCleaners[p.Name]
|
||||
}
|
||||
handlerMu.RUnlock()
|
||||
if cleaner == nil {
|
||||
respondErr(req.ID, fmt.Errorf("%s %s 未注册 Cleaner", p.Scope, p.Name))
|
||||
return
|
||||
}
|
||||
respond(req.ID, map[string]interface{}{"text": cleaner(p.Text)})
|
||||
|
||||
case "stage.invoke":
|
||||
handleStageInvoke(req)
|
||||
|
||||
@ -1065,41 +1131,41 @@ func handleHandshake(req *rpcRequest) {
|
||||
pluginName = p.PluginName
|
||||
}
|
||||
|
||||
// 挂载 StageContext 共享段。
|
||||
// 传递机制按平台不同(Unix 用继承的 fd,Windows 用命名段),
|
||||
// 由 z_proc_shm_*.go 承担——本文件保持平台无关。
|
||||
// 挂载统一共享内存区域。
|
||||
// fd 3 (Unix) / 命名对象 (Windows) 传给插件子进程,包含 SuperBlock +
|
||||
// StageContext + EvtRing 两段。SuperBlock 记录各段的偏移与大小。
|
||||
if p.ShmSize > 0 {
|
||||
m, err := attachStageShm(p.ShmSize)
|
||||
m, err := attachUnifiedShm(p.ShmSize)
|
||||
if err != nil {
|
||||
respondErr(req.ID, fmt.Errorf("挂载共享段失败: %w", err))
|
||||
respondErr(req.ID, fmt.Errorf("挂载统一共享区域失败: %w", err))
|
||||
return
|
||||
}
|
||||
if got := binary.LittleEndian.Uint32(m[shmOffMagic:]); got != shmMagic {
|
||||
respondErr(req.ID, fmt.Errorf("共享段魔数不匹配(0x%x)", got))
|
||||
if got := binary.LittleEndian.Uint32(m[sbOffMagic:]); got != unifiedMagic {
|
||||
respondErr(req.ID, fmt.Errorf("统一区域魔数不匹配(0x%x,期望 0x%x)", got, unifiedMagic))
|
||||
return
|
||||
}
|
||||
shm = m
|
||||
}
|
||||
|
||||
// 挂载事件环段 + 打开通知句柄(§3.6)
|
||||
if p.EvtRingSize > 0 {
|
||||
er, err := attachEvtRingShm(p.EvtRingSize)
|
||||
if err != nil {
|
||||
respondErr(req.ID, fmt.Errorf("挂载事件环段失败: %w", err))
|
||||
return
|
||||
ctxOff := binary.LittleEndian.Uint32(m[sbOffCtxOff:])
|
||||
ctxSize := binary.LittleEndian.Uint32(m[sbOffCtxSize:])
|
||||
evtOff := binary.LittleEndian.Uint32(m[sbOffEvtOff:])
|
||||
evtSize := binary.LittleEndian.Uint32(m[sbOffEvtSize:])
|
||||
// shm 指向 StageContext 段,后续代码用 shm[off...] 访问该段内部字段
|
||||
shm = m[ctxOff : ctxOff+ctxSize]
|
||||
// 挂载事件环段 + 打开通知句柄(§13.1:EvtRing 在统一区域内)
|
||||
if p.EvtRingSize > 0 && evtSize > 0 {
|
||||
er := m[evtOff : evtOff+evtSize]
|
||||
if got := binary.LittleEndian.Uint32(er[evtOffMagic : evtOffMagic+4]); got != evtRingMagic {
|
||||
respondErr(req.ID, fmt.Errorf("事件环魔数不匹配(0x%x)", got))
|
||||
return
|
||||
}
|
||||
notifier, err := openEvtNotifier()
|
||||
if err != nil {
|
||||
respondErr(req.ID, fmt.Errorf("打开事件通知句柄失败: %w", err))
|
||||
return
|
||||
}
|
||||
evtRingData = er
|
||||
evtNotifier = notifier
|
||||
go evtConsumerLoop()
|
||||
}
|
||||
if got := binary.LittleEndian.Uint32(er[evtOffMagic : evtOffMagic+4]); got != evtRingMagic {
|
||||
respondErr(req.ID, fmt.Errorf("事件环魔数不匹配(0x%x)", got))
|
||||
return
|
||||
}
|
||||
notifier, err := openEvtNotifier()
|
||||
if err != nil {
|
||||
respondErr(req.ID, fmt.Errorf("打开事件通知句柄失败: %w", err))
|
||||
return
|
||||
}
|
||||
evtRingData = er
|
||||
evtNotifier = notifier
|
||||
go evtConsumerLoop()
|
||||
}
|
||||
|
||||
respond(req.ID, map[string]interface{}{
|
||||
|
||||
@ -10,31 +10,23 @@ import (
|
||||
|
||||
// Unix 侧共享段挂载:内核经 ExtraFiles 传入继承的 fd。
|
||||
//
|
||||
// fd 布局(与内核 internal/plugin/proc/plugin.go 的 ExtraFiles 顺序一致):
|
||||
// 统一共享内存区域布局(§13.1):
|
||||
//
|
||||
// fd 3 = StageContext 段(memfd / 已 unlink 的临时文件)
|
||||
// fd 4 = 事件环段
|
||||
// fd 5 = 事件通知(Linux eventfd / macOS pipe 读端)
|
||||
// fd 3 = 统一区域(SuperBlock + StageContext + EvtRing)
|
||||
// fd 4 = 事件通知(Linux eventfd / macOS pipe 读端)
|
||||
//
|
||||
// 继承的 fd 无需文件名,也不残留——这是选 memfd 而非 /dev/shm 的原因。
|
||||
const (
|
||||
fdStageShm = 3
|
||||
fdEvtRingShm = 4
|
||||
fdEvtNotifier = 5
|
||||
fdUnifiedShm = 3
|
||||
fdEvtNotifier = 4
|
||||
)
|
||||
|
||||
// attachStageShm 挂载 StageContext 共享段。
|
||||
// attachUnifiedShm 挂载统一共享内存区域。
|
||||
//
|
||||
// 各进程 mmap 到不同虚拟地址,段内一律用相对偏移而非指针,故仍能正确解引用
|
||||
// (实验 2 已验证父子 mmap 基址不同时偏移解引用正确)。
|
||||
func attachStageShm(size int) ([]byte, error) {
|
||||
return syscall.Mmap(fdStageShm, 0, size,
|
||||
syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
|
||||
}
|
||||
|
||||
// attachEvtRingShm 挂载事件环段。
|
||||
func attachEvtRingShm(size int) ([]byte, error) {
|
||||
return syscall.Mmap(fdEvtRingShm, 0, size,
|
||||
func attachUnifiedShm(size int) ([]byte, error) {
|
||||
return syscall.Mmap(fdUnifiedShm, 0, size,
|
||||
syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user