从一次就绪通知到零悬挂请求:EV-2终点任务
本任务只接上两个缺口:主动让路之后怎样仍记得未读输入,以及调用者超时退出后怎样仍有人收尾。它复用已有背压、设备pin和deadline,不重新实现TCP、内核或垃圾收集器。
阅读入口
核心四站:短返回与背压 → 就绪事件循环 → 设备完成与缓冲所有权 → 取消与退休。这是一条应用问题链,阅读次序不自动成为定义前置。
按需补课:FIFO队列、fd身份、总期限。迁移分支使用长度前缀分帧;更深的内存基础见页pin和回收资格。原有OS隔离与持久化和网络R9继续保持自己的终点,本任务不把安全释放当成掉电持久或业务成功。
入口自测:正长度非阻塞read返回EAGAIN能否当EOF?超时是否允许立即复用仍在途的缓冲?数值fd3重现是否仍是同一对象?三题均为否;应分别找输入结束、目标终结和身份代际的证据。
固定模型与问题
EV-2有单线程事件分派器、有限连接,所有读非阻塞,回调不重入。每轮收取有界通知和清理工作,然后执行一个有界量子;只在没有本地工作时阻塞。注册正确且持续就绪通知最终被交付;单次异步目标最终给出一份终结记录,已接纳取消也最终完成。分派器公平地最终处理每份已接纳的完成和容量恢复事件,借用者最终归还。在这些条件以外,要求安全保留,不声称必达零。
A:两条输入怎样都被读完
A有abcdef,B有XY,初始通知顺序A、B,此后无新输入也无关闭。每轮最多2字节、1次read。写出六次派发、队列及最终输出。再删掉“预算耗尽后回队尾”,分别判断ET与可能重复通知的LT。
还要回答:队列一直有A时,为什么必须继续非阻塞收取新通知?若每轮只限读取字节,不限制EINTR重试,量子是否有界?
B:超时以后谁还能接触B
读请求R=(3,7)使用4096B缓冲。依次发生:提交;deadline到期并发取消C;目标成功,登记一份内部校验借用;借用释放;C报告未找到。每步写L、T、C、d、b和缓冲池状态,指出逻辑完成、缓冲归池、请求身份退休各发生在哪一步。
再分别处理:目标先于deadline;取消成功;不可取消但目标稍后报错;取消标识错误;回调抛错;fd3关闭后被复用;只有逻辑调用退出而没人消费完成队列。说明哪一种情况尚不具备到零的活性前提。
C:预算改成一帧
每帧两字节大端长度、载荷最多3字节,容量9,计已完成帧编码大小加当前帧预留。开始新帧前预留最大5字节,每次只读当前头或载荷所需字节。一次派发最多交付一帧、尝试两次读取。三批输入依次为00、03 43 41、54 00 02 4F 4B。
在CAT完成但未消费时是否可以读下一个头?当消费者释放CAT,为什么没有新ET边沿也能继续?最后OK已完成后,探测EAGAIN之前预留下一帧,会怎样影响峰值账本?
答案与不变量
A答案:六个量子,四次数据进展
依次是 A:ab → B:XY → A:cd → B:EAGAIN → A:ef → A:EAGAIN。每次后的Q为[B,A]、[A,B]、[B,A]、[A]、[A]、[]。实际read六次,其中四次有数据、两次无数据,共8字节;两次初始注册和两份通知另计。输出分别abcdef、XY。
预算分支没有证明耗尽,须保留hint;EAGAIN才撤销。删除续排后一个合法ET执行停在A=ab,源中剩cdef;LT若再次报告A可继续,但不能用这种额外通知承诺替ET补证明。重复通知只在不在队列时追加,故队列集合等于QUEUED身份且无重复。
每轮即使队列非空也收取有界新通知,避免应用自己让新B永远无法入队;实际OS交付仍需明示公平条件。连续EINTR消耗尝试数而非字节数,所以两种预算都必要。若入队后尚余本轮工作≤H,每个前驱量子连下一轮准备≤T,至多N个有效身份且无插队,已入队者等待≤H+(N−1)T;没有有界回调就没有此墙钟界。
B答案:三个不同时间点
| 事件后 | L / T / C | d,b | 池状态 / R |
|---|---|---|---|
| 提交 | WAITING / INFLIGHT / NONE | 1,0 | HELD,保留 |
| deadline | TIMEOUT / INFLIGHT / PENDING | 1,0 | HELD,保留 |
| 目标成功 | TIMEOUT / TERMINAL(ok) / PENDING | 0,1 | HELD,保留 |
| 释放借用 | TIMEOUT / TERMINAL(ok) / PENDING | 0,0 | RETURNED,R仍保留 |
| C未找到 | TIMEOUT / TERMINAL(ok) / DONE | 0,0 | 不再重复归池,R退休 |
目标完成时先登记借用再交还d;每次只消费一次token;HELD→RETURNED也只能一次。逻辑未完成数从第二行起为0,物理未退休数仍为1,最后才为0。目标成功发生在超时之后,不改写原等待结果。R还在等C时,B可以供其他请求使用,因此C必须仅访问R控制记录,不能再按旧B指针处理数据。
目标先完成则定时器不再发C;取消成功仍要处理目标终结;不可取消、标识错误和取消提交失败均保留目标责任,等真实终结后回收。回调抛错走finally归还;有后台接收者则先建立新借用再撤旧。fd只作底层接口参数,事件先在活登记表按种类/槽/代际匹配,不能先解引用旧事件指针。第7代不会命中新建第8代,代号回绕不在模型内。
没人drain时,即使CQE已投递,应用也没有处理终结证据;资源会悬挂。永久故障或不归还的借用者同样没有到零保证,只能隔离并报告,不能把超时当作设备停机证书。最多Q个未退休请求、每块至多M字节才得到保留缓冲≤Q×M;已超时、目标已终结但借用未结束,都继续占准入名额。
对照io_uring时,成功取消有提交返回前目标CQE已投递的具体文档保证;EALREADY仍需等待目标CQE。已投递、已消费和最后借用结束是三个事件,不能合成一项。详细来源及接口限制见取消页。
C答案:容量恢复也是唤醒来源
第一批留下半头,第二批留下CAT的CA,当前帧均保留5字节预算。第三批首字节T补成CAT,占用5;剩余4不足以预留下一帧最大5,所以PAUSED,hint仍为真。OK的四个字节此时留在源中,未被读进无记账临时数组。
消费CAT后占用0,恢复事件按hint重新入队。接着读0002和OK,形成编码大小4的输出。由于还可预留5,下一次EAGAIN探测前总账为4+5=9,故峰值是9,不是5。消费OK后还留空头预留5;本实验再给出有序EOF,释放该预留,最终为0。若连接继续开放,保留这5是明示的准入选择,不是悬挂异步I/O。
归纳证明:新预留只在used+5≤9时发生;读入只使用已预留空间;完成把预留转为实际占用;消费和EOF归还。每一步≤9。帧预算停止和容量暂停不清hint,消费者释放可重排,因此剩余字节不需另等边沿。零长度帧也计一帧;超长头拒绝;半头或半载荷EOF为截断。
运行复算与结构迁移
下载EV-2标准库复算器,以Python 3.9或更新版本运行:
python foundations-event-io-checker.py
python foundations-event-io-checker.py --case readiness --quantum 1 --attempts 2
python -O foundations-event-io-checker.py
默认输出完整JSON账本;首次作者执行为476项显式检查,普通与-O结果一致。不是用可被-O删除的assert冒充验证。--case可以选择readiness、cancellation或framing;预算须为1到10000的整数,非法参数非零退出。
取消部分枚举两种不同条件:读结果回调必须在T之后才能释放,故C/T/L有三种合法次序;如果预先已有一份只保留地址、不读取在途载荷的租约,C/T/L六种次序都可运行。不要用后者为设备写入与CPU并发读取背书。检查器还核对重复终结/重复释放拒绝、后台交接、取消失败、错误代号、EOF、连续EINTR、无drain与ET漏续排反例。
迁移:将后台解码器改成永不归还。正确结论是目标已终结、d=0、b=1,缓冲不可复用,准入槽仍被占用;不是“计时器稍后清零b”。若必须保证最终释放,任务协议必须新增可验证的后台终结/交接条件。另一迁移是允许一个read取多帧:须保存并计费本轮未解析的输入后缀,仍限制本轮解析帧数,不能直接丢弃后缀;本实验通过精确限制读取长度避开这份额外缓冲。
适用边界
这是一份有限、确定的协议模型,不调用epoll、io_uring、DMA或真实socket;不证明内核符合文档,也不测系统调用耗时。单线程稳定边界省去了真实多线程发布屏障,单次完成省去了multishot终止标志。代码中的源字节数组模拟内核输入,不计入应用容量;所有应用预留和输出则计入。其安全性由两页的逐事件不变量说明,最终到零仍依赖已声明的投递、分派和归还条件。