项目
PennOS — 类 Unix 教学操作系统
用 C 实现的用户态 Shell、优先级调度器、信号、重定向与 PennFAT 文件系统——附带可在浏览器中运行的在线终端。
CPOSIX threads (spthread)Operating SystemsShellsSchedulingSignalsFilesystemsWebSocketsnode-ptyNext.jsxterm.jsprlimit / systemd sandboxing

概览
用 C 实现的类 Unix 操作系统特性:带作业控制与 I/O 重定向的 Shell、基于 spthread 的 SIGALRM 驱动优先级调度器、含信号与僵尸进程的完整进程生命周期,以及 PennFAT 磁盘文件系统——全部接入本站的沙箱在线终端。
问题
课程规模的操作系统毫不宽容——非法输入、部分写入、信号竞态与糟糕的调度决策都会破坏进程与磁盘状态。挑战在于让这些组件在所有这些情况下都表现可预期,并让真实访客能在浏览器里驾驶它而不危及主机。
我做了什么
用分层的 C 实现:顶层是 Shell 解析器与内建命令,中间是面向用户的 s_* 系统调用,底层是调度器 / 进程与 PennFAT 的 k_* 原语,最底层是 spthread(POSIX 线程 + SIGALRM)。随后把二进制放在一个带类型的 Node WebSocket 边车之后,以逐会话 prlimit 沙箱运行,让任何人都能在浏览器里启动一个真实的 PennOS。
架构
- Shell 层 — 解析器、内建命令(ls、cat、ps、jobs、fg、bg、kill、chmod、nice、sleep)、I/O 重定向(< > >>)与异步后台作业
- 用户 API(s_*)— s_spawn、s_waitpid、s_kill、s_open、s_read、s_write、s_lseek,作为 Shell 与内核之间的系统调用边界
- 进程 / 调度器 — PCB 表、三级优先级(9:6:4 调度比)、SIGALRM 驱动的抢占、僵尸回收、孤儿进程重挂到 init
- PennFAT(k_*)— FAT 风格的磁盘格式:显式超级块、FAT 表与目录项,外加把 Shell fd 映射到内核对象的 fd 表
- spthread 基座 — 基于 POSIX 线程的协作式挂起 / 恢复原语,用于实现上下文切换与信号投递
- 在线终端 — 位于 127.0.0.1:3100 的 Node + ws + node-pty 边车,prlimit 包裹(CPU 120s、RSS 96 MiB、FSIZE 2 MiB、NOFILE 32、NPROC 24),逐会话临时 PennFAT 镜像,空闲 / 硬超时,经 Nginx 以 /ws/pennos 反向代理并按 IP 限流
技术亮点
- 三级优先级调度器,9:6:4 时间片比例,由 SIGALRM 抢占,构建在 spthread 挂起 / 恢复原语之上。
- 终端作业控制:jobs、fg %N、bg %N、Ctrl-C / Ctrl-Z 转发、孤儿重挂到 init、通过 s_waitpid 回收僵尸。
- I/O 重定向(<、>、>>)经由包装 PennFAT k_* 文件操作的 s_* fd 表贯通。
- 以 Shell 命令形式暴露的压力演示:busy、hang、nohang、recur、crash、zombify、orphanify——专为搞坏内核而写,并证明它搞不坏。
- PennFAT 磁盘格式:显式超级块、FAT 风格链表、单根目录、可通过 chmod +/-rwx 设置的文件权限位。
- 浏览器在线会话使用带类型的 JSON 协议走 WS,按 IP 与全局限制会话数,prlimit 包裹子进程,断开时清理逐会话临时目录。
成效
- 构建出一个小而真实的内核表面,在恶意输入下锻炼调度、信号与文件系统代码。
- 以可上手的作品而非压缩包交付:访客可在浏览器里启动沙箱 PennOS,无需我代为运行任何东西。
看它运行
这个项目就在本站运行——无需安装,也无需配置。