mirror of
https://gitcode.com/JianFeeeee/homeagent-sdk.git
synced 2026-10-15 12:15:11 +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
|
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 (
|
const (
|
||||||
shmStageFieldCount = 18
|
shmStageFieldCount = 18
|
||||||
@ -88,8 +105,11 @@ var (
|
|||||||
|
|
||||||
handlerMu sync.RWMutex
|
handlerMu sync.RWMutex
|
||||||
toolHandlers = map[string]sdk.ToolHandler{}
|
toolHandlers = map[string]sdk.ToolHandler{}
|
||||||
|
toolCleaners = map[string]func(string) string{}
|
||||||
|
inputCleaners = map[string]func(string) string{}
|
||||||
stageHandlers = map[string]sdk.StageHandler{}
|
stageHandlers = map[string]sdk.StageHandler{}
|
||||||
outputHandlers = map[string]sdk.ToolHandler{}
|
outputHandlers = map[string]sdk.ToolHandler{}
|
||||||
|
outputCleaners = map[string]func(string) string{}
|
||||||
|
|
||||||
shm []byte
|
shm []byte
|
||||||
|
|
||||||
@ -416,9 +436,14 @@ func buildPluginSDK(name string) *sdk.PluginSDK {
|
|||||||
func(toolName string, def sdk.ToolDef, handler sdk.ToolHandler) error {
|
func(toolName string, def sdk.ToolDef, handler sdk.ToolHandler) error {
|
||||||
handlerMu.Lock()
|
handlerMu.Lock()
|
||||||
toolHandlers[toolName] = handler
|
toolHandlers[toolName] = handler
|
||||||
|
if def.Cleaner != nil {
|
||||||
|
toolCleaners[toolName] = def.Cleaner
|
||||||
|
} else {
|
||||||
|
delete(toolCleaners, toolName)
|
||||||
|
}
|
||||||
handlerMu.Unlock()
|
handlerMu.Unlock()
|
||||||
return callCoreVoid("tool.register", map[string]interface{}{
|
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) {
|
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 {
|
func(chName string, caps int, desc string, def sdk.ChannelDef, handler sdk.ToolHandler) error {
|
||||||
handlerMu.Lock()
|
handlerMu.Lock()
|
||||||
outputHandlers[chName] = handler
|
outputHandlers[chName] = handler
|
||||||
|
if def.Cleaner != nil {
|
||||||
|
outputCleaners[chName] = def.Cleaner
|
||||||
|
} else {
|
||||||
|
delete(outputCleaners, chName)
|
||||||
|
}
|
||||||
handlerMu.Unlock()
|
handlerMu.Unlock()
|
||||||
return callCoreVoid("output.register", map[string]interface{}{
|
return callCoreVoid("output.register", map[string]interface{}{
|
||||||
"name": chName, "caps": caps, "desc": desc,
|
"name": chName, "caps": caps, "desc": desc,
|
||||||
"def": map[string]interface{}{"NoMemory": def.NoMemory},
|
"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.SetTextMemoryAPI(procTextMemory{})
|
||||||
base.SetPluginMgrAPI(procPluginMgr{})
|
base.SetPluginMgrAPI(procPluginMgr{})
|
||||||
base.SetInputChannelRegistrar(func(chName string, def sdk.ChannelDef) error {
|
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{}{
|
return callCoreVoid("input.register", map[string]interface{}{
|
||||||
"name": chName,
|
"name": chName,
|
||||||
"def": map[string]interface{}{"NoMemory": def.NoMemory},
|
"def": map[string]interface{}{"NoMemory": def.NoMemory},
|
||||||
|
"has_cleaner": def.Cleaner != nil,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
return base
|
return base
|
||||||
@ -961,6 +1000,33 @@ func handleKernelRequest(req *rpcRequest) {
|
|||||||
}
|
}
|
||||||
respond(req.ID, map[string]interface{}{"result": res})
|
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":
|
case "stage.invoke":
|
||||||
handleStageInvoke(req)
|
handleStageInvoke(req)
|
||||||
|
|
||||||
@ -1065,41 +1131,41 @@ func handleHandshake(req *rpcRequest) {
|
|||||||
pluginName = p.PluginName
|
pluginName = p.PluginName
|
||||||
}
|
}
|
||||||
|
|
||||||
// 挂载 StageContext 共享段。
|
// 挂载统一共享内存区域。
|
||||||
// 传递机制按平台不同(Unix 用继承的 fd,Windows 用命名段),
|
// fd 3 (Unix) / 命名对象 (Windows) 传给插件子进程,包含 SuperBlock +
|
||||||
// 由 z_proc_shm_*.go 承担——本文件保持平台无关。
|
// StageContext + EvtRing 两段。SuperBlock 记录各段的偏移与大小。
|
||||||
if p.ShmSize > 0 {
|
if p.ShmSize > 0 {
|
||||||
m, err := attachStageShm(p.ShmSize)
|
m, err := attachUnifiedShm(p.ShmSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
respondErr(req.ID, fmt.Errorf("挂载共享段失败: %w", err))
|
respondErr(req.ID, fmt.Errorf("挂载统一共享区域失败: %w", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if got := binary.LittleEndian.Uint32(m[shmOffMagic:]); got != shmMagic {
|
if got := binary.LittleEndian.Uint32(m[sbOffMagic:]); got != unifiedMagic {
|
||||||
respondErr(req.ID, fmt.Errorf("共享段魔数不匹配(0x%x)", got))
|
respondErr(req.ID, fmt.Errorf("统一区域魔数不匹配(0x%x,期望 0x%x)", got, unifiedMagic))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
shm = m
|
ctxOff := binary.LittleEndian.Uint32(m[sbOffCtxOff:])
|
||||||
}
|
ctxSize := binary.LittleEndian.Uint32(m[sbOffCtxSize:])
|
||||||
|
evtOff := binary.LittleEndian.Uint32(m[sbOffEvtOff:])
|
||||||
// 挂载事件环段 + 打开通知句柄(§3.6)
|
evtSize := binary.LittleEndian.Uint32(m[sbOffEvtSize:])
|
||||||
if p.EvtRingSize > 0 {
|
// shm 指向 StageContext 段,后续代码用 shm[off...] 访问该段内部字段
|
||||||
er, err := attachEvtRingShm(p.EvtRingSize)
|
shm = m[ctxOff : ctxOff+ctxSize]
|
||||||
if err != nil {
|
// 挂载事件环段 + 打开通知句柄(§13.1:EvtRing 在统一区域内)
|
||||||
respondErr(req.ID, fmt.Errorf("挂载事件环段失败: %w", err))
|
if p.EvtRingSize > 0 && evtSize > 0 {
|
||||||
return
|
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{}{
|
respond(req.ID, map[string]interface{}{
|
||||||
|
|||||||
@ -10,31 +10,23 @@ import (
|
|||||||
|
|
||||||
// Unix 侧共享段挂载:内核经 ExtraFiles 传入继承的 fd。
|
// Unix 侧共享段挂载:内核经 ExtraFiles 传入继承的 fd。
|
||||||
//
|
//
|
||||||
// fd 布局(与内核 internal/plugin/proc/plugin.go 的 ExtraFiles 顺序一致):
|
// 统一共享内存区域布局(§13.1):
|
||||||
//
|
//
|
||||||
// fd 3 = StageContext 段(memfd / 已 unlink 的临时文件)
|
// fd 3 = 统一区域(SuperBlock + StageContext + EvtRing)
|
||||||
// fd 4 = 事件环段
|
// fd 4 = 事件通知(Linux eventfd / macOS pipe 读端)
|
||||||
// fd 5 = 事件通知(Linux eventfd / macOS pipe 读端)
|
|
||||||
//
|
//
|
||||||
// 继承的 fd 无需文件名,也不残留——这是选 memfd 而非 /dev/shm 的原因。
|
// 继承的 fd 无需文件名,也不残留——这是选 memfd 而非 /dev/shm 的原因。
|
||||||
const (
|
const (
|
||||||
fdStageShm = 3
|
fdUnifiedShm = 3
|
||||||
fdEvtRingShm = 4
|
fdEvtNotifier = 4
|
||||||
fdEvtNotifier = 5
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// attachStageShm 挂载 StageContext 共享段。
|
// attachUnifiedShm 挂载统一共享内存区域。
|
||||||
//
|
//
|
||||||
// 各进程 mmap 到不同虚拟地址,段内一律用相对偏移而非指针,故仍能正确解引用
|
// 各进程 mmap 到不同虚拟地址,段内一律用相对偏移而非指针,故仍能正确解引用
|
||||||
// (实验 2 已验证父子 mmap 基址不同时偏移解引用正确)。
|
// (实验 2 已验证父子 mmap 基址不同时偏移解引用正确)。
|
||||||
func attachStageShm(size int) ([]byte, error) {
|
func attachUnifiedShm(size int) ([]byte, error) {
|
||||||
return syscall.Mmap(fdStageShm, 0, size,
|
return syscall.Mmap(fdUnifiedShm, 0, size,
|
||||||
syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
|
|
||||||
}
|
|
||||||
|
|
||||||
// attachEvtRingShm 挂载事件环段。
|
|
||||||
func attachEvtRingShm(size int) ([]byte, error) {
|
|
||||||
return syscall.Mmap(fdEvtRingShm, 0, size,
|
|
||||||
syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
|
syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user