标签
Stumpalo 是一个新的高性能 Rust 内存块分配器(bump allocator),在各类内存分配操作的基准测试中,其性能显著优于 blink 和 bumpalo 等现有替代方案。它还支持作用域栈,并已作为 Rust crate 发布。
# 终端背后的秘密:终端模拟器、TTY 与 Shell 作为开发者,我们每天都在使用终端。但你有没有想过,当你打开一个"终端窗口"时,究竟发生了什么?你输入的字符经过怎样的路径,最终变成命令的输出? 大多数人将整个体验笼统地称为"终端",但实际上,这背后存在三个截然不同的层次,它们各司其职、协同工作。理解这三个层次,不仅能帮助你排查奇怪的问题,更能让你对自己每天使用的工具有更深刻的认识。 ## 三个层次概览 在深入细节之前,先来认识这三位主角: 1. **终端模拟器(Terminal Emulator)**:你在屏幕上看到的那个窗口 2. **TTY / 伪终端(Pseudo-terminal)**:操作系统内核中的一个抽象层 3. **Shell**:真正解释并执行你命令的程序 它们的关系可以这样理解: ``` 你的键盘输入 ↓ 终端模拟器(GUI 窗口) ↓ 伪终端(内核层,PTY) ↓ Shell(bash / zsh / fish …) ↓ 命令输出原路返回 ``` --- ## 第一层:终端模拟器 ### 它是什么 终端模拟器是一个**图形界面程序**。常见的有 iTerm2、GNOME Terminal、Alacritty、Windows Terminal、Kitty 等。它的核心职责是: - 渲染文字到屏幕上 - 捕获你的键盘输入 - **模拟**老式硬件终端(如 VT100、xterm)的行为 "模拟器"这个词至关重要。在个人电脑普及之前,终端是一台真实的硬件设备——一台带显示器和键盘的哑终端,通过串口连接到大型主机。现代的终端模拟器用软件重现了那台硬件的行为。 ### 它做什么 当你按下键盘上的一个键,终端模拟器会将这个按键**转换成字节序列**,然后写入伪终端。例如,方向键 `↑` 通常被转换为转义序列 `\x1b[A`。 反过来,当程序向终端写入转义序列时,终端模拟器负责**解释**这些序列,并作出相应动作,例如: ``` \x1b[31m → 将后续文字渲染为红色 \x1b[2J → 清空整个屏幕 \x1b[1A → 光标上移一行 ``` 这就是为什么同一个程序(比如 `vim`)在不同的终端模拟器里,行为可能略有差异——不同的模拟器对转义序列的支持程度不同。 ### 一个常见的误解 很多人以为终端模拟器"运行"了 Shell。实际上,终端模拟器只是**启动**了 Shell,并为它提供一个可以读写的伪终端接口。之后,终端模拟器和 Shell 是两个独立运行的进程,通过内核中的伪终端相互通信。 --- ## 第二层:TTY 与伪终端(PTY) 这是三层中最容易被忽视、也最难理解的一层,但它是整个系统的**核心枢纽**。 ### TTY 的历史渊源 TTY 是 **Teletype**(电传打字机)的缩写。在计算机的早期历史中,人们用电传打字机与计算机交互——输入字符,打印机打印出响应。这套设备通过串口连接到计算机。 Unix 操作系统从一开始就将这些串口设备抽象为文件,放在 `/dev/tty*` 路径下。程序只需要读写这些文件,就能与用户交互,而不需要关心底层是什么硬件。 ### 伪终端(PTY)的出现 当我们转向图形界面,不再有真实的硬件串口时,Unix 需要一种方式来保持这套抽象,同时支持终端模拟器这样的软件。于是**伪终端(Pseudo-Terminal,PTY)**诞生了。 PTY 是内核提供的一对相互连接的虚拟设备: - **主端(master side)**:终端模拟器持有这一端 - **从端(slave side)**:Shell 及其子进程持有这一端,对应 `/dev/pts/0`、`/dev/pts/1` 这样的设备文件 你可以把它想象成一条**双向管道**,但这条管道远比普通管道聪明——它内置了一个叫做**行规程(line discipline)**的模块。 ### 行规程:被遗忘的功能 行规程是 TTY 层中最精妙的设计之一。它在内核中处理大量"低级"的终端行为,让每个 Shell 和应用程序不必自己重新实现这些功能: | 功能 | 说明 | |------|------| | **回显(Echo)** | 将你输入的字符显示在屏幕上 | | **行编辑** | `Backspace` 删除字符,`Ctrl+U` 清除整行 | | **信号生成** | `Ctrl+C` 发送 `SIGINT`,`Ctrl+Z` 发送 `SIGTSTP` | | **规范模式** | 缓冲整行输入,直到你按下回车 | 这解释了一个有趣的现象:即使在 Shell 还没启动、或 Shell 崩溃的情况下,`Backspace` 键依然"有效"——因为删除字符这个操作是由**内核**在 TTY 层处理的,而不是由 Shell 处理的。 ### 用命令亲眼验证 在终端里输入: ```bash tty ``` 你会看到类似这样的输出: ``` /dev/pts/3 ``` 这就是当前 Shell 正在使用的伪终端从端设备文件。你可以用 `ls -la /dev/pts/` 查看系统中所有活跃的伪终端。 更有趣的是,你可以直接向另一个终端窗口写入文字: ```bash # 在终端 A 中运行 tty,假设输出是 /dev/pts/3 # 然后在终端 B 中运行: echo "你好,终端 A" > /dev/pts/3 ``` 终端 A 的屏幕上会直接出现这段文字——这直观地展示了 TTY 设备文件的本质。 --- ## 第三层:Shell Shell 是你**最熟悉**却往往被与终端混为一谈的那一层。 ### Shell 是一个普通进程 Shell(bash、zsh、fish 等)本质上是一个**普通的用户空间进程**。它的特别之处在于: - 它将 `/dev/pts/N` 作为自己的**标准输入(stdin)**、**标准输出(stdout)**和**标准错误(stderr)** - 它读取你输入的文本,解析为命令,然后通过 `fork()` + `exec()` 创建子进程来执行这些命令 - 子进程同样继承了对 TTY 设备的连接 ### 原始模式 vs 规范模式 Shell 在启动后,通常会让 TTY 层工作在**规范模式(canonical mode)**下。此时行规程会帮 Shell 缓冲输入、处理退格键等,Shell 直接读取一整行已处理好的输入。 但当你运行 `vim` 或其他全屏程序时,情况就不同了。`vim` 会将 TTY 切换到**原始模式(raw mode)**: - 行规程的大部分处理被**绕过** - 每个按键立即传递给应用程序 - 应用程序自行决定如何处理每一个字节 这就是为什么在 `vim` 里,`Backspace` 的行为可以被完全自定义,而在普通 Shell 提示符下,`Backspace` 的行为是由内核保证的。 ### Shell 不是终端 这个区别在实践中非常重要。考虑以下场景: ```bash # 这会失败,因为 ssh 命令没有分配 TTY ssh user@host vim /etc/hosts # 这会成功,-t 参数强制分配一个伪终端 ssh -t user@host vim /etc/hosts ``` `vim` 需要一个真实的 TTY 才能工作(它需要将终端切换到原始模式)。当 `ssh` 不分配 TTY 时,远端的 `vim` 无法正常运行——因为它的标准输入只是一个普通管道,而不是一个 TTY 设备。 --- ## 三层如何协同工作:一次完整的按键之旅 让我们追踪一次按键——假设你在 Shell 提示符下输入字母 `l`,准备输入 `ls` 命令: ``` 1. 你按下键盘上的 "l" 键 2. 操作系统检测到按键事件 3. 终端模拟器收到按键事件, 将其编码为字节 0x6C(ASCII 'l'), 写入 PTY 主端 4. 内核 TTY 层(行规程)收到这个字节: - 将字节追加到输入缓冲区 - 因为开启了回显,将 'l' 写回 PTY 主端 5. 终端模拟器从 PTY 主端读取到回显的 'l', 将其渲染到屏幕上 (这就是你"看到"自己输入的原因) 6. Shell 此时还没有收到任何东西—— 它在等待一个完整的行(规范模式) 7. 你继续输入 "s",然后按下回车 8. 行规程收到回车,将完整的行 "ls\n" 送入 Shell 可读取的队列 9. Shell 的 read() 调用返回,得到 "ls\n" 10. Shell 解析命令,fork() 出子进程, exec() 执行 /bin/ls 11. ls 将输出写入其标准输出(同一个 PTY 从端) 12. 内核 TTY 层将输出传递到 PTY 主端 13. 终端模拟器读取输出,渲染到屏幕上 ``` 整个过程在毫秒之内完成,但涉及了用户空间和内核空间之间多次切换,以及三个独立组件的协作。 --- ## 为什么这些知识对开发者有用 理解这三个层次,能帮助你解释和解决很多实际问题: **1. 为什么有些程序检测到自己的输出被重定向后,行为会改变?** ```bash ls --color=auto # 输出彩色 ls --color=auto | cat # 输出变成黑白 ``` `ls` 通过检查标准输出是否是 TTY(使用 `isatty()` 系统调用)来决定是否输出颜色代码。管道不是 TTY,所以颜色被关闭。 **2. 为什么 `sudo` 有时会提示输入密码失败?** `sudo` 需要从 TTY 读取密码。如果你在一个没有 TTY 的环境中运行 `sudo`(例如某些 CI 环境),它就无法工作。 **3. 为什么 `screen` 和 `tmux` 能"保持"会话?** `screen` 和 `tmux` 本身就是终端模拟器(运行在终端里的终端模拟器)。它们创建自己的 PTY,Shell 连接到这个 PTY。当你断开 SSH 连接时,真正的终端模拟器消失了,但 `tmux` 创建的 PTY 和连接到它的 Shell 仍然存在于服务器上。 **4. 理解 `stty` 命令** `stty` 命令直接操作 TTY 层的设置: ```bash stty -echo # 关闭回显(输入密码时脚本里常用) stty echo # 重新开启回显 stty -a # 查看当前 TTY 的所有设置 ``` --- ## 总结 | 层次 | 代表 | 职责 | |------|------|------| | 终端模拟器 | iTerm2, GNOME Terminal, Alacritty | 图形渲染、转义序列解释、按键捕获 | | TTY / PTY | `/dev/pts/N`(内核模块) | 数据路由、行规程、信号生成 | | Shell | bash, zsh, fish | 命令解析、进程管理、脚本执行 | 这三层各自解决了不同的问题,通过清晰的接口相互协作。Unix 的设计哲学在这里体现得淋漓尽致:每个组件做好一件事,通过标准化的接口(文件描述符、设备文件)组合在一起,形成一个灵活而强大的整体。 下次当你打开终端窗口,看到那个闪烁的光标时,你知道自己看到的不只是一个"终端"——而是三个精心设计的软件层,在内核与用户空间之间默默协作的成果。
Fil-C 是一种开创性的新编程语言,承诺通过内存安全性彻底革新软件生态系统。
一篇系统编程入门文章,涵盖诸如位操作、解析、文件系统、系统调用和内存管理等基础知识,面向程序员。
Spectre 是一种用于安全、基于合约的低级系统编程的新编程语言,默认强制不可变性,并支持编译时/运行时合约检查。它通过 QBE IR 编译,并包含将 C 代码转换为 Spectre 的功能。
本文在 2026 年的背景下对比了 Zig 和 Rust,认为编程代理通过自动化生成 Rust 代码,削弱了 Zig 在人机交互体验上的优势。
Zero-native 是一个新工具,用于使用 Zig 和 WebView 构建轻量级原生桌面应用,生成的二进制文件小于 1MB,支持快速重新构建并可直接访问 C 库。
With 编程语言通过集成 PCRE2 支持正则表达式并实现隐式 main 函数,达到了一个重要里程碑。该更新支持单行命令,并包含具有内置 LSP 支持的自托管编译器。
斯坦福大学 CS153 系统课程 2026 年的讲座视频已整理成专属播放列表,这些内容会定期上传至斯坦福官方 YouTube 频道。
本文介绍了 'ymawky',一个完全用 aarch64 汇编为 macOS 编写的最小 HTTP Web 服务器,使用原始系统调用而无需 libc 包装器,以探索底层系统机制。
TokioConf 2026 的一篇演讲/博客文章探讨了如何通过为复杂指针结构实现追踪式垃圾回收,将安全 Rust 推向极限,并分享处理循环引用与原始指针 GC 设计的技巧。
Verus 是一款针对 Rust 的静态验证工具,利用 SMT 求解在不引入运行时检查的前提下,证明底层系统代码的完整功能正确性。
Paul McKenney 讨论了非常规和边界情况的 RCU(读-拷贝-更新)实现,包括早期 Unix 系统中使用的定时等待 RCU 方法,以及与内存隔离相关的固定缓冲区 RCU 概念,展示了内核开发中具有创造性但潜在危险的同步技术。
# kefir:独立 C17/C23 编译器 源码:[https://sr.ht/~jprotopopov/kefir/](https://sr.ht/~jprotopopov/kefir/) [723abe5](https://git.sr.ht/~jprotopopov/kefir/commit/723abe5)`重构目标 IR 指令存储以实现更安全的原地初始化` 8 小时前 [c1c07bf](https://git.sr.ht/~jprotopopov/kefir/commit/c1c07bf)`实现原地目标 IR 指令构造` 1 天前 Kefir 是一个面向 C17/C23 编程语言的独立编译器,由 [Jevgenij Protopopov](https://sr.ht/~jprotopopov) 开发
# Rust 零拷贝页面:我是如何停止焦虑并爱上生命周期的 来源:[https://redixhumayun.github.io/databases/2026/04/14/zero-copy-pages-in-rust.html](https://redixhumayun.github.io/databases/2026/04/14/zero-copy-pages-in-rust.html) *你可以在[这里](https://github.com/redixhumayun/simpledb/)找到该项目的源代码* 零拷贝是一种旨在消除内核与用户空间缓冲区之间 CPU 数据复制的技术,尤其在数据处理等高吞吐量应用中极具价值。
Rust 主源代码仓库,包含编译器、标准库和文档,强调性能、可靠性与生产力,配套 Cargo、rustfmt、Clippy 和 rust-analyzer 等工具链。
这是一个用于 University of Illinois Urbana-Champaign 的 CS 341 课程的开源系统编程教材仓库,提供以 C 语言编写的教育材料,用于学习 Linux 内核编程。