从零编写操作系统 30 - 综合演示与交付验证
前 29 篇已经分别证明了引导、内存、调度、用户态、文件系统、Shell、管道和窗口终端。单项实验通过仍留下两个问题:这些机制能否在同一次启动中连续工作,系统重启后能否得到同样的结果? 最终实验把答案压进一条固定操作链:列出 FAT16 根目录,读取文件,通过管道统计字节,从磁盘加载 DEMO.EXE,并发运行两个计数进程和一个越界进程。越界进程被终止后,两个计数进程必须继续增长;所有子进程退出后,Shell 还要执行下一条命令并完整释放资源。相同场景随后经历一次同进程 hard reset 和一次新 QEMU 进程复跑。 补齐最终场景缺少的两个入口 Day 29 的 Shell 能打开已知文件,却不能询问卷上有哪些文件;Day 19 的 DEMO 则以内嵌 ELF 运行,尚未走 FAT16 装载路径。Day 30 只补这两个缺口,不重写已经通过的机制。 最终镜像增加 syscall 12: 12345678#define SYS_READDIR 12ustruct fat_dirent { char name[13]; uint8_t attribute...
Untitled
Day 30 evidence Date: 2026-09-22 Source baseline Integrated-demo implementation commit: 07d63e7 Final kernel binary SHA-256: a5209e8fd220c64e3d7b3e3b2449d16e8f2f4e315db5562bc3e5c2a5390fc470 Final kernel ELF SHA-256: 80a6d0825b79c0749d2cfa5951a42c334a30a7d64a0742bc4399ad77cb3bd45e Final disk image SHA-256: 4c4a315af550ee8f38dd8c1fa5fd2c067d2a4077d28b793b67fc36edae5e48d2 DEMO.EXE SHA-256: a246a279682e38bea0a2613800599f69d4dd54161b6e2bf2dc95dbe6ae1f5474 First/reset/fresh screenshot SHA-256: aa1...
从零编写操作系统 29 - 窗口终端:把用户态 Shell 接进图形界面
Day 28 的窗口能接收字符,却还只是把字符追加到内核数组。Day 23 的 Shell 则已经在 Ring 3 中运行,能从 FAT16 加载命令、等待子进程和连接管道,但输出只能到文本控制台。把两者接起来,关键不是再写一套命令解释器,而是保持 Shell 只认识 fd 0/1/2,让窗口成为终端字节流的生产者和消费者。 本篇新增一个固定的图形终端窗口。键盘字符进入 64 字节输入队列,Shell 输出进入另一条 64 字节队列,UI 每轮只消费一小批字符,再处理鼠标和重绘。这样既能复用原来的用户态程序,也能用真实的满队列阻塞检查长输出期间的调度与界面响应。 复用 Shell,先固定身份证据 mbr-window-shell.img 使用图形版 stage2,但 FAT16 分区直接来自 Day 23 的 fat16-shell.bin。启动 Shell 的路径没有绕过文件系统: 123456FAT16 /SHELL.EXE → file_open + file_pread → elf_load_source → user_space_build_stack → p...
Untitled
Day 29 evidence Date: 2026-09-20 Source baseline Window-terminal implementation commit: 9fea4ca Text kernel SHA-256: 26f1bc26360ddf4c9b7d984d4fc6706eaa445207ee4095a2386bda2dd7cf8386 Window-terminal kernel SHA-256: 5b5a68d52f37d4c768abb1f3b5e0fb6d30910b00d32b5ae55be9f58d7a354e42 Window-terminal disk image SHA-256: 8c23eefb8b9583945a3f521b91906aec7da5441fdab9f2ced4016a3a59414b81 SHELL.EXE/day23-user.elf SHA-256: b44b54cef5743aaa2c8423492cc5d15e96f567802256cbcd25186a7b493bc8b9 Screenshot SHA-25...
计算机网络 27:QUIC 为什么重新实现传输机制,包号、流、恢复、拥塞与迁移
HTTP/2 已经把一个 TCP 连接里的 HTTP 消息拆成多条流。它解决了 HTTP/1.1 响应必须排队返回的问题,却没有解决 TCP 字节流自己的等待:一个 TCP 段丢失后,内核不能把后面的字节先交给上层,即使那些字节只属于另一条 HTTP/2 流。应用层分帧已经知道“这几个字节属于流 3”,TCP 仍然只看到“前面的字节没齐”。 QUIC 的入口问题就在这里:如果应用已经需要多流、加密、恢复、拥塞控制和连接迁移,为什么还要把这些能力放在内核 TCP 之上,再在上层补一套绕不过去的状态?QUIC 的选择是把传输机制搬到 UDP 之上,由端点实现包号、流、恢复、拥塞控制、TLS 集成和路径变化处理。许多实现选择用户态,这是部署方式,不是 QUIC 规范要求。UDP 在这里不是可靠传输,只是报文承载;它也可能被网络策略阻断。 前置是第 17 篇超时与重传、第 18 篇流量控制、第 19 篇拥塞控制、第 24 篇 TLS 身份验证和第 25 篇会话恢复。本篇只讨论 QUIC 传输机制。HTTP/3 怎样把请求、响应、控制流和 QPACK 映射到 QUIC,放到下一篇。文中的验...
计算机图形学 26:软件管线怎样映射为着色器
第 11 篇的软件光栅器已经能把网格变成颜色图,第 16 篇又把局部变换串成世界变换。到了 WebGPU,顶点变换、属性插值、深度测试和纹理采样由固定功能与着色器共同完成。迁移的难点在于让两条管线对同一批字节、坐标和颜色作出同一种解释。 本篇固定一个 128×128 场景:两个有重叠的倾斜四边形,共享一张 8×8 纹理,使用同一组 float32 MVP 矩阵。CPU 生成参考缓冲与诊断图,浏览器在真实 WebGPU 设备上渲染并读回颜色、辅助数据和深度附件。内部像素要求数值一致;几何边界单独统计,不把两种光栅器不同的覆盖规则伪装成错误。 先运行同场景实验 打开 CPU 与 WebGPU 对照实验。点击“运行 GPU 并核对 CPU”,再依次查看纹理颜色、UV、原始深度和差异位置。页面显示的是 GPU 附件读回值,不是 CPU 图片或预存截图。 实际验证日期为 2026-09-22。Codex 内嵌浏览器报告 Chrome/153.0.0.0,安全上下文为 true,适配器 vendor 为 apple、architecture 为 metal-3;device 与 desc...
分布式系统(26):Spanner 的时间区间、提交等待与一致快照
一笔转账同时修改两个分片。两边最终都提交,只解决了共同终局;报表还需要在一次读取中看到完整的转账结果。如果转账已经向客户端报告成功,随后发起的强一致读取也不能因为选择了较慢的时钟而退回转账之前。 分布式系统(25):分布式事务的决定、补偿与消息边界 Spanner 把这些要求组合在同一个数据库里:每个复制组保存可恢复的状态,跨组事务决定共同结果,并发控制约束冲突操作,时间戳和多版本读取决定快照内容。TrueTime 提供带误差边界的时间区间,提交等待把时间戳顺序与真实先后连接起来。机制推导以 OSDI 2012 原论文为准,课程结构对应 MIT 6.5840 和 Stanford CS244b;现行云产品的隔离级别单独说明。 复制、事务与时间各自约束什么 设账户 x 位于组 A,账户 y 位于组 B。一次事务要从 x 扣款并向 y 加款。每个组内部有多个副本,通过 Paxos 复制状态;A、B 作为两个业务参与组,通过两阶段提交协调这笔转账。组内复制多数与跨组全部参与者是两个不同集合:A 的多数派确认,不能代替 B 的准备结果。 flowchart TB T[跨分片转账 T]...
分布式系统(25):分布式事务的决定、补偿与消息边界
订单记录已经提交,支付消息却没有发出。把顺序反过来,支付消息可能已经被处理,订单事务随后回滚。两个系统各自正确地完成一次操作,仍然不能保证这两次操作具有共同的结果。 分布式系统(24):分片与在线迁移的归属边界 前篇解决一个分片迁移后由谁服务。跨分片下单还需要回答另一件事:订单、库存和支付分别位于不同资源时,哪些变化必须一起提交,哪些中间结果允许出现,失败后还剩什么义务。站内既有的分布式事务覆盖更多方案名称;这里沿同一条订单链路推导失败路径,再用本地实验检查原子边界。 两次成功调用之间存在失败窗口 先限定业务含义。订单服务创建的是“待支付订单”,消息是“请求扣款”,消费者在自己的账本里扣款。订单创建成功不代表支付完成。若业务要求两个资源共同提交或共同中止,需要跨资源原子提交;若还要求读者看不到部分结果,还必须设计跨资源的隔离与读规则。若允许订单先进入待处理状态,则可以持久保存后续动作,由工作流继续推进。这是对可观察行为的选择。 sequenceDiagram participant S as 订单服务 participant D as 订单库 participant ...
计算机网络 26:HTTP/2 的多路复用解决了哪一层阻塞,帧、流、HPACK 与窗口
一个慢响应还没结束,同一连接上的小响应能不能先完成?如果能,为什么丢失一个 TCP 段仍可能让多个响应一起等待?这两个问题分别涉及 HTTP 消息的组织方式和底层字节流的交付条件。 前置是第 18 篇接收窗口、第 22 篇消息边界与第 24 篇 TLS。本篇把流标识、字段压缩、接收窗口和 TCP 顺序交付分开,避免把“多路复用”解释成每个请求拥有独立网络通道。 消息拆成帧后,响应可以交错 HTTP/1.1 流水线允许前一个请求尚未收到响应时继续发送请求,但响应仍按请求顺序返回。一个响应占用字节流时,后一个响应不能随意把正文插进去,否则接收者无法按原有消息规则区分归属。 HTTP/2 在帧头中携带流标识。接收端先识别帧,再把内容交给相应的流。一个连接可以同时存在多个未关闭的流,因此服务器能够在一个大响应的两个 DATA 帧之间发送另一个流的响应。请求和响应仍保留 HTTP 语义,改变的是表达方式。 RFC 9113 §4.1规定固定 9 字节帧头,包括长度、类型、标志和流标识。长度描述帧载荷,不包含这 9 字节。流标识 0 用于连接范围的控制,不能当成普通请求编号;客户端发起的流使...
从零编写操作系统 28 - 窗口管理:Z 序、焦点与拖动
Day 27 已经把鼠标字节变成坐标、按键和边沿,但屏幕上仍然只有一个直接重绘的字符终端。窗口管理要再回答三件事:重叠位置显示谁,点击交给谁,拖动过程中谁持续拥有指针。 本篇实现一个固定双窗口管理器。窗口表保存几何和文本,Z 序单独保存遮挡关系;命中从顶向底查找,绘制从底向顶执行。左键按下标题栏后建立拖动捕获,键盘字符只写入焦点窗口。每次状态变化仍重建完整 320×200 画面,以最小机制先验证所有权和遮挡恢复。 窗口表与 Z 序承担不同职责 两个窗口的内容放在固定表中: 1234567891011121314struct demo_window { int32_t x, y; uint32_t width, height; uint8_t body_color; char name; char text[8]; uint32_t text_length;};struct demo_window windows[2] = { {20, 40, 150, 100, 1, 'A',...





