第37期 | 一万行里,只有两个活物

操作系统 · · 九羲科技

一、两个活物,一张六十四格的登记簿:1991 年开机那一刻

1991 年 9 月 17 日,Linux 0.01 发布。机器加电,内核安顿好自己,世界上第一个 Linux"社会"开张——成员,一共两个。

先画格子。include/linux/sched.h 第 4 行:#define NR_TASKS 64。再住人,kernel/sched.c 第 33 行:struct task_struct * task[NR_TASKS] = {&(init_task.task),};。六十四格的登记簿,开机只填了第 0 格,剩下六十三个全是 NULL。新进程想落户?kernel/fork.c 里的 find_empty_process() 从第 1 格开始往后扫,遇见 NULL 就住下。

格子不是白画的。每个进程在 GDT 里占两格——TSS 一格、LDT 一格(_TSS/_LDT 宏算出来的)。六十四个进程,就是一百二十八格 GDT 预留。1991 年的办法很"土":不搞动态分配,先把格子焊死。土,但跑得起来。INIT_TASK 宏上面还跟一句警告:"touch at your own risk!"——动它,后果自负。

然后 main() 办开张,init/main.c 第 92 到 103 行,三步:move_to_user_mode() 跳进用户态;if (!fork()) init();——旁边跟一句注释,"we count on this going ok",我们指望这次 fork 能成。二十一岁,理直气壮。然后 task0 留守原地:for(;;) pause();,空转,等调度。

Linux 0.01 的进程登记簿(kernel/sched.c:33)与 main() 造出第二个进程的三行(init/main.c:92-103)。来源:kernel.org historic 源码包。

task[0] 是 idle,内核态的兜底;task[1] 是 init,用户态的母亲。init() 一睁眼,先 fork 出 /bin/update——刷脏块的守护进程。注意:0.01 第一天就有"后台守护"这个概念了。然后 open /dev/tty0,dup 成 0、1、2,打印两行:"N buffers = M bytes buffer space",换行," Ok."。一个操作系统对自己说:行了,成了。再 fork 出 /bin/sh,wait 它;孩子退出就打印 "child %d died with code %04x",sync 一把,_exit。

贝塔朗菲在《General System Theory》(1968)里讲:整体的性质,要素单独拿出来是没有的。一个 task_struct 拆下来只是一堆字节——只有住进 task[64] 这张表、被 schedule() 轮起来,它才是"进程"。进程不是东西,是位置加关系。

0.01 没发明进程表,Unix 的思想 1970 年代就有了。它赢在"先实际后原理":六十四格先焊死,跑起来再说。当年追原理完美的 GNU Hurd,1991 年还不能用。

二、AI 的第一个进程,不该叫 init

如果 AI 的 OS 先出现

假如先有大模型,后有操作系统,"init"大概不会再生 shell。0.01 的 init 干三件事:起守护(update)、开交互(sh)、收尸(wait)。AI-native 的 init 也干三件,只是换了内容:起"世界模型"(常驻预测,像 update 一样在后台默默刷)、开"对话"(agent runtime 就是它的 /bin/sh)、收"上下文"(checkpoint 写盘,相当于 sync)。

那两个最初的活物也会换人。task0 的 idle 是"没事干就空转";AI OS 的 task0 该是"没事干就预测"——算力闲着也是闲着,不如 roll 一遍世界模型。task1 不再是 init 进程,而是一个"首席 agent":系统的第一个居民,之后所有的 agent 都是它的 fork。

范式之眼在这里收紧:六十四格登记簿是"管理对象"的思维——进程是固定对象,编号管理,一格一主。而 AI 负载里 agent 是流动的、上下文是弹性的,"槽位"装不下"关系"。旧抽象管的是"谁在格子里",新系统要管的是"谁和谁连着、连多紧"。从对象到关系,登记簿得换一本。

照见之镜问两句。可能性:操作系统"开机"变成"醒来"——世界模型常驻,第一个动作不是 fork shell,而是读入第一条提示词。落地还差几步:agent 的"进程"还没有统一模样,checkpoint/restore 缺标准,上下文配额没有 cgroup 式的机制。谁来做?大概率推理框架先长出来——vLLM 的 serving 引擎已经是应用层的 init 了,再往下沉。三到五年。

三、数一遍六十四个槽位:今晚就能做的三件事

第一,下载 1991 年的源码包,71KB:curl -sL https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/linux-0.01.tar.gz -o linux-0.01.tar.gz && tar xzf linux-0.01.tar.gz。亲手看那张登记簿:grep -n 'task\[NR_TASKS\] =' linux/kernel/sched.c。再看那句二十一岁的注释:grep -n "count on" linux/init/main.c。

第二,在手边任何一台 Linux 机器上,对比今昔:ps -e | wc -l 数数今天开机有多少进程;cat /proc/1/comm 看看今天的"init"叫什么名字。1991 年开机是 2 个,今天是几百个——格子还是格子,只是住满了。

第三,映射到今天的实践:在一台能跑本地模型的机器上,常驻的模型服务就是今天的"init 之子"——常驻、被看着、死了会被拉起来;边缘小盒子上任务少、算力固定,0.01 式"格子焊死"反而是优点,简单可靠;视频 AI 平台上每路视频一个常驻推理进程,就是现代版的 task 数组,一格一路;企业私有智能中心里几位常驻智能体,也是"各有各的槽位,各有各的看门人"。发展性研究的路子从来这样:别先设计完美的进程管理,先让六十四格跑起来。

觉 然 小 注

「是法平等,无有高下。」六十四个槽位,idle 和 init 坐的是同一种格子。别执着谁是主进程——每个位置,都有它的活法。

引 用 与 出 处

  1. Linux 0.01 源码包(kernel.org historic;include/linux/sched.h、kernel/sched.c、kernel/fork.c、init/main.c 为一手核对),https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/linux-0.01.tar.gz
  2. Bertalanffy, L. von, General System Theory: Foundations, Development, Applications, George Braziller, 1968("整体的性质为要素所无"思想化用),https://en.wikipedia.org/wiki/Ludwig_von_Bertalanffy

· · ·

← 返回资讯中心