C in the Linux Kernel

Lobsters Hottest 工具

摘要

本文深入介绍了 Linux 内核中 C 语言与普通用户空间 C 的区别,涵盖资源管理、错误处理、并发、日志记录、静态分析等核心技巧,使用了大量 GNU C 扩展和内核特有模式。

<p><a href="https://lobste.rs/s/q7e7hp/c_linux_kernel">Comments</a></p>
查看原文
查看缓存全文

缓存时间: 2026/06/27 17:56

**TL;DR:** Linux 内核中的 C 语言与普通用户空间 C 完全不同,它在资源管理、错误处理、并发、日志和静态分析等方面使用了许多 GNU C 扩展和内核特有的模式与宏,以提升安全性和可维护性。 ## 资源管理:从手动释放到自动清理 普通 C 语言没有 RAII,每次获取内存后都必须手动 `free`。但 Linux 内核使用带有 GNU 扩展的 C,其中 `__attribute__((cleanup))` 可以让编译器在函数退出时自动释放变量。此外,早期驱动使用大量 `goto` 标签来组织错误处理路径;从内核 2.6.21 起,引入了托管设备 API,自动管理每次分配的内存,使驱动的错误处理大大简化。 ## 并发与锁:守卫和安全作用域 内核高度并行,多用户空间应用可能同时访问设备。驱动中通常使用互斥锁(mutex)保护共享数据。旧模式是手动加锁/解锁并配合 `goto` 清理;现代驱动则使用 `guard` 和 `scoped guard`。`guard` 在当前函数结束时自动解锁,`scoped guard` 在离开作用域时解锁,特别适合需要多次加解锁的场景。 ## 错误处理:IS_ERR、ERR_PTR 的神奇玩法 由于没有 Rust 的 `Result` 枚举,内核利用保留地址空间来实现指针同时携带错误码。内核保留了最高 4095 个地址(访问会导致内核 panic),`ERR_PTR` 将负数错误码转换为对应的保留地址,`IS_ERR` 检查指针是否落在该范围内。这样同一个函数就能既返回有效指针又返回错误码。而在内核 Rust 代码中,则正常使用 `Result` 枚举并转换错误码。 ## 日志记录:时间戳、驱动名与可读的错误码 日志是调试的主要手段。现代内核日志输出具有漂亮的时间戳、驱动名称、SPI 总线位置和自定义消息。错误码不再显示数字,而是转换为可读文本。同时,内核开发者热衷于重构旧代码,在简化逻辑的同时修复常见的错误处理 bug。 ## 断言:从 BUG_ON 到 WARN_ON Linus 强烈反对使用 `BUG_ON` 直接杀死内核,尤其是驱动中。现在推荐使用 `WARN_ON`,它会打印堆栈跟踪并继续运行,尽力保持系统稳定。 ## 编译时检查:__must_check 与静态分析器 许多内核函数标记了 `__must_check` 属性,强制调用者检查返回值,否则编译器会警告。此外,内核内置了两个静态分析器: - **sparse**:检测 `__user` 标记的指针错误(如直接解引用用户空间缓冲区),报告锁上下文不平衡、RCU 解引用等问题。 - **smatch**:传统分析器,能捕获空指针解引用、数组越界、内存泄漏、忘记解锁等。 ## 分支预测:likely 和 unlikely `likely()` 和 `unlikely()` 宏将重要代码保持在热路径中。如果某个条件极不可能发生,标记为 `unlikely` 后,编译器会生成汇编,把异常路径移到函数末尾,优先执行正常路径,从而利用 CPU 缓存行预取。但研究表明人类有 39% 的概率猜错 `likely` 分支,建议只在确信大概率有收益时使用(如 `WARN_ON`、`IS_ERR_VALUE`)。 ## 内核数据结构:侵入式链表与 container_of 内核拥有自己的数据结构集合(链表、哈希映射、红黑树等),其中最常用的是侵入式链表(`list_head`)。需要直接将 `list_head` 成员嵌入结构体。初始化时用 `INIT_LIST_HEAD` 使头节点自指;添加元素时用 `list_add`。遍历使用 `list_for_each_entry` 宏,它通过 `container_of` 宏从链表节点指针反推出宿主结构体的起始地址。`container_of` 通过指针运算和 `offsetof` 实现,本质上是利用结构体内存布局来模拟泛型,是内核实现继承和多态的基础。 ## 赞助环节:Let's Get Rusty 本视频由 Let's Get Rusty 赞助。自内核 6.1 起,可以用 Rust 编写驱动,且每个新版本增加更多子系统抽象。Let's Get Rusty 提供专注于系统编程的结构化 Rust 培训,已帮助数千开发者。有兴趣可访问 letsgetrusty.com/startwithmas 或查看视频下方置顶评论链接。 --- **Source:** [C in the Linux Kernel - YouTube](https://www.youtube.com/watch?v=iqqf8YWJhSs)

相似文章

https://www.youtube.com/watch?v=qRLyoP8zOyQ

YouTube AI Channels

一篇介绍如何编写自定义CUDA内核以突破深度学习框架瓶颈的技术文章/书籍摘要,涵盖从基础到优化的完整路径。

关于C扩展、可移植性和替代编译器

Lobsters Hottest

本文讨论了编写可移植C代码的实际挑战,这些挑战源于对非标准编译器扩展和glibc条件头文件的依赖,并通过构建C编译器的示例进行说明。