参照对象 :Linux io_uring 的实现机制 (不是引入它)。
本 issue 只做一件事:把 io_uring 里与「跨进程/跨 runtime 派发 opcode」相关的机制逐条对到 kvlang 现有 handoff 上,给出抄什么、不抄什么 ,作为 #189 (kvlang-runtime 概念与调度设计)的参考输入。
背景:现有 handoff 机制
myrwircaps 命中失败 → handoff_external_rwir(runtime/src/kvcpu.c:881)把 pc 挂到共享队列
/lib/<opcode>/vids/<vtid>;队列由首个 rwir 建真实 strkeymap、后续同 opcode 的 vids 为 Ptr 指向它
(幂等,runtime/src/myrwircaps.c:13);扩展 RunSeq(pc) 顺序跑自己 caps 内的连续指令,遇第一条不在
caps 内的即停、写回最终 PC、删 vids 条目;中央 runtime 用 kvlangKvWatch(vids/<vtid>, 30s)
(kvcpu.c:901)等条目消失,自己不推进 PC。规范见 spec 05-runtime语义/07-notinmyrwircaps、
08-myrwir扩展-c。
即:队列 = 提交环、删条目 = 完成事件、opcode ∈ 谁 = 谁执行 。这三个恰好是 io_uring 的核心结构。
机制逐条对照
io_uring 机制
kvlang 现状
差什么 / 抄哪条
SQ/CQ 两个 mmap 共享环;完成式 (completion)而非就绪式(readiness)
vids strkeymap 队列 + Watch 条目消失
结构同构;差别在介质(持久 KV 树 vs 内存环)→ 不抄介质,抄语义
IORING_OP_URING_CMD(5.19+)passthrough :内核不解释该 opcode,按 fd 找驱动注册的 uring_cmd,把 SQE 的 cmd 字段(普通环 16B,IORING_SETUP_SQE128 下 80B)原样递给驱动;opcode 由子系统/驱动自定义 (连 LSM 都审不出来,故另加 hook)
notinmyrwircaps handoff:中央 runtime 不解释远端 opcode,按 /lib/<opcode> 路由到扩展
同构 ,这是本 issue 最强的一条:kvlang 已实现 io_uring 的 passthrough 语义;可借它论证「中央 runtime 永不需要懂扩展 opcode」这一职责线
提交侧只写 SQE,完成侧单值 res + 标志 (NVMe 透传要两个结果 → IORING_SETUP_CQE32)
扩展只写回最终 PC;失败/部分完成无处表达
抄:把「删条目 = 完成」升级为完成槽 (pc + status + 字节数/nr),删条目仅作通知。否则扩展失败只能靠 30s 超时兜
SQPOLL:内核线程自旋 SQ,提交零 syscall
kvlangKvWatch(..., 30s)
Watch 是粗糙的 SQPOLL(也是粗糙的完成轮询);若要降延迟,方向是「扩展完成时直接唤醒等待方」,而非缩短 watch 间隔
环定长 :SQ 满 → 提交侧必须等/重试(io_uring_enter 阻塞;SQPOLL 下自旋)
vids 无界 strkeymap
抄:队列上限 + 满即拒绝 handoff (宁可报错不静默排队)。无界队列 = 无背压 = 内存与延迟双失控
IOSQE_IO_LINK:链起来才保证提交序=完成序 ;不链则完成可乱序
RunSeq「顺序执行、非并行 batch」,单消费者时天然有序
抄:明确写死「同一 vids 队列是否允许多消费者并行认领」。若允许,必须引入显式依赖/令牌;否则顺序保证是隐式的、会被并发打破
IORING_REGISTER_BUFFERS / REGISTER_FILES:预注册固定缓冲/fd,免每步 pin/map
ResolveReadPath + kvspaceGet 借用读 + DecodeHead + GetPart 分片(已是零拷贝骨架)
半抄:现在是「每次借用」,缺「预注册/常驻」概念。与 #212 / #268 (句柄缓存)合并评估:扩展声明常用 key/缓冲,跨多步 handoff 复用
multishot:一次提交、多次完成
一个 vthread 反复 handoff(每步一次 Set + Watch)
抄:把「一次 handoff 跑一整段」的边界说清(现在是「遇陌生即还」,可能出现乒乓 handoff)。可考虑「同 opcode 连续段合并成一次提交」
IORING_SETUP_SINGLE_ISSUER:5.19 时唯一需要它的就是 URING_CMD
vids 首队列由多写者经 Ptr 统一写入
已踩过坑(重复注册经路径穿透把首队列改成自指 Ptr → resolve_path 死循环,修法=幂等跳过)。照 uring 的结论:多写者共享一个环必须显式约定所有权 ,否则就是竞态温床
落地方案(可执行清单)
背压 :vids 加容量上限(计数/条目数),满时 handoff 直接报 RuntimeError,不排队。
完成槽 :handoff 结果改为写 (pc, status, bytes),条目删除只作通知;失败路径有明确表达。
所有权与接管 :watch 超时后谁接管、旧执行体复活怎么办 → 引入 epoch/fencing token (写回带 epoch,过期写回被拒)。与 0.4 的 [RFC] 0-kvspace: XValue head 增加 rwx + uid/gid 权限系统:kvspace 层硬强制读写码 #54 (权限系统)同源,建议合并设计。
顺序规则显式化 :写进 spec —— 同一 vids 队列允许/禁止并行认领,以及禁止时的实现约束。
预注册零拷贝 :扩展跨步复用常驻缓冲/常用 key(与 [EPIC] 2-runtime: 性能加速下一步计划:kv.set/get 重构 + kvspace shm 零拷贝 + kvspace-c 优化 #212 、[PERF] 0-kvspace/2-runtime: 句柄缓存(kvspaceResolveRef/GetByRef/SetPartByRef + block_id + forwarding tombstone + 帧级失效) #268 合评)。
事件不丢 :Watch 目前「删即信号」,丢一次就等 30s → 参考 KV watch 的 revision + 从指定版本重放(kvspace 层缺口,另记)。
明确不做
不引入内核 io_uring 依赖,不把 vids 换成共享内存环:持久可恢复是 kvlang 的红线 (PC 是 KV 路径、崩溃可续跑),io_uring 只作机制参照。
不改「中央 runtime 不解释扩展 opcode」这一职责线(它本来就对)。
验收
参考
关联:#189 (调度设计)、#54 (权限/epoch 可合并)、#212 / #268 (预注册零拷贝合评)、#305 (handoff 相关指针语义已落)。
参照对象:Linux
io_uring的实现机制(不是引入它)。本 issue 只做一件事:把 io_uring 里与「跨进程/跨 runtime 派发 opcode」相关的机制逐条对到 kvlang 现有 handoff 上,给出抄什么、不抄什么,作为 #189(kvlang-runtime 概念与调度设计)的参考输入。
背景:现有 handoff 机制
myrwircaps命中失败 →handoff_external_rwir(runtime/src/kvcpu.c:881)把 pc 挂到共享队列/lib/<opcode>/vids/<vtid>;队列由首个 rwir 建真实 strkeymap、后续同 opcode 的vids为Ptr指向它(幂等,
runtime/src/myrwircaps.c:13);扩展RunSeq(pc)顺序跑自己 caps 内的连续指令,遇第一条不在caps 内的即停、写回最终 PC、删
vids条目;中央 runtime 用kvlangKvWatch(vids/<vtid>, 30s)(
kvcpu.c:901)等条目消失,自己不推进 PC。规范见 spec05-runtime语义/07-notinmyrwircaps、08-myrwir扩展-c。即:队列 = 提交环、删条目 = 完成事件、opcode ∈ 谁 = 谁执行。这三个恰好是 io_uring 的核心结构。
机制逐条对照
vidsstrkeymap 队列 + Watch 条目消失IORING_OP_URING_CMD(5.19+)passthrough:内核不解释该 opcode,按 fd 找驱动注册的uring_cmd,把 SQE 的cmd字段(普通环 16B,IORING_SETUP_SQE128下 80B)原样递给驱动;opcode 由子系统/驱动自定义(连 LSM 都审不出来,故另加 hook)notinmyrwircapshandoff:中央 runtime 不解释远端 opcode,按/lib/<opcode>路由到扩展IORING_SETUP_CQE32)SQPOLL:内核线程自旋 SQ,提交零 syscallkvlangKvWatch(..., 30s)Watch是粗糙的 SQPOLL(也是粗糙的完成轮询);若要降延迟,方向是「扩展完成时直接唤醒等待方」,而非缩短 watch 间隔io_uring_enter阻塞;SQPOLL 下自旋)vids无界 strkeymapIOSQE_IO_LINK:链起来才保证提交序=完成序;不链则完成可乱序IORING_REGISTER_BUFFERS/REGISTER_FILES:预注册固定缓冲/fd,免每步 pin/mapResolveReadPath+kvspaceGet借用读 +DecodeHead+GetPart分片(已是零拷贝骨架)multishot:一次提交、多次完成IORING_SETUP_SINGLE_ISSUER:5.19 时唯一需要它的就是URING_CMDvids首队列由多写者经 Ptr 统一写入resolve_path死循环,修法=幂等跳过)。照 uring 的结论:多写者共享一个环必须显式约定所有权,否则就是竞态温床落地方案(可执行清单)
vids加容量上限(计数/条目数),满时 handoff 直接报RuntimeError,不排队。(pc, status, bytes),条目删除只作通知;失败路径有明确表达。明确不做
io_uring依赖,不把vids换成共享内存环:持久可恢复是 kvlang 的红线(PC 是 KV 路径、崩溃可续跑),io_uring 只作机制参照。验收
05-runtime语义/07)或明确否决 + 理由,并入 [RFC] 2-runtime: kvlang-runtime 的概念与调度设计(main/ext + myrwircaps) #189 的裁决记录。error_cases/)。参考
关联:#189(调度设计)、#54(权限/epoch 可合并)、#212 / #268(预注册零拷贝合评)、#305(handoff 相关指针语义已落)。