文章

Linux 内核学习笔记:操作系统结构

Linux 内核学习笔记:操作系统结构

这一篇记录操作系统结构里和 Linux 内核学习直接相关的部分:内核能力、用户态/内核态、系统调用、Linux 的多任务/SMP/ELF/宏内核设计,以及少量 Windows 内核对照。

问题索引

主题本篇记录
内核是什么内核作为应用和硬件之间的管理层
内核有哪些能力进程调度、内存管理、硬件通信、系统调用
内核怎么工作用户空间、内核空间、用户态、内核态
Linux 的设计MultiTask、SMP、ELF、Monolithic Kernel
Windows 设计NT、混合内核、PE 文件格式
内核架构类型宏内核、微内核、混合内核

1. 内核:应用和硬件之间的管理层

应用程序不直接管理 CPU、内存、磁盘、网卡、键盘等硬件。内核负责把硬件能力包装成稳定接口,并负责隔离、调度、权限和错误处理。

可以先用这张表记内核能力:

能力基础解释Linux 落点
进程和线程管理决定哪个执行流使用 CPUtask_struct、调度器、runqueue
内存管理分配、回收、隔离虚拟地址空间mm_struct、VMA、页表、page fault
文件系统把持久化数据组织成文件和目录VFS、dentry、inode、page cache
设备管理让进程通过统一接口访问硬件driver model、IRQ、DMA、/sys
网络栈管理 socket、协议栈、收发包sk_buff、NAPI、TCP/IP、qdisc
系统调用给用户态程序提供受控入口syscall table、syscall ABI、copy_to_user()

这张表就是后续 Linux 笔记的骨架。每一个能力都会落到具体结构体、状态转换和源码路径。

2. 用户空间、内核空间、用户态、内核态

现代 OS 会把执行权限和地址空间分层。应用程序运行在用户态,内核运行在内核态。

名词记录
用户空间普通进程使用的虚拟地址空间区域
内核空间内核代码和内核数据所在区域
用户态CPU 低权限级别,普通程序在这里执行
内核态CPU 高权限级别,内核可以访问核心资源和硬件

用户态程序不能随意访问硬件、改页表、关中断、读写任意内存。需要内核服务时,通过系统调用进入内核。

系统调用的最小路径:

1
2
3
4
5
6
7
用户态程序
  -> libc 包装函数
  -> syscall 指令 / trap
  -> syscall entry
  -> 内核检查参数和权限
  -> 执行内核服务
  -> 返回用户态

Linux 落点:

问题Linux 入口
syscall 从哪里进arch/x86/entry/
syscall 怎么分发syscall number、syscall table
用户指针怎么访问copy_from_user()、copy_to_user()
当前进程是谁current、task_struct
参数错了怎么办errno、信号、失败返回

read()、write()、mmap()、clone()、execve()、ioctl() 都属于这条边界。

3. 系统调用、异常、中断

用户程序进入内核时,内核学习里需要把三类入口分开记。

入口来源例子和当前 task 的关系
系统调用用户程序主动请求内核read()、mmap()、clone()当前 task 主动进入内核
异常当前指令执行出问题或需要内核介入page fault、除零、非法指令通常处理当前 task 的上下文
中断外部硬件或定时器事件网卡收包、磁盘完成、timer不一定属于当前 task

这一区分会影响能不能睡眠。

上下文能否睡眠说明
进程上下文通常可以内核代码代表某个 task 执行,可以被调度走再恢复
中断上下文不能随便睡眠没有普通进程上下文,路径要短,常把工作推给 softirq/workqueue

后续设备管理、网络系统、BPF tracing 都会用到这个边界。

4. Linux 设计点:MultiTask

MultiTask 表示多任务。单核上多个任务交替运行,形成并发;多核上多个任务可以同时运行,形成并行。

概念记录
并发一段时间内多个任务都在推进,单核也可以做到
并行同一时刻多个任务真的在不同 CPU 上执行
时间片调度器给普通任务分配 CPU 时间的一种模型
抢占当前任务运行中也可能被调度器换下

Linux 落点:

对象作用
task_struct调度和管理的执行实体
runqueue每个 CPU 上的可运行任务集合
scheduling class不同任务类型的调度策略
schedule()调度入口之一
sched_switch调度切换 tracepoint

观测入口:

命令记录
ps -eLf进程和线程
vmstat 1runnable 数、上下文切换
pidstat -w 1进程上下文切换
perf sched latency调度延迟

5. Linux 设计点:SMP

SMP 是对称多处理。多个 CPU 地位相同,共享同一套内存和硬件资源,任务可以被调度到不同 CPU 上运行。

Linux 学习里 SMP 带来几个具体问题:

问题说明
多 CPU runqueue每个 CPU 有自己的调度队列,需要负载均衡
task migration任务迁移到别的 CPU 可能丢失 Cache 热数据
并发访问共享数据需要锁、原子操作、RCU、per-CPU 数据
中断分布硬件中断可能集中在某些 CPU 上
NUMA多路机器上访问本地/远端内存成本不同

观测入口:

命令 / 路径用途
lscpuCPU、核心、NUMA、Cache 信息
taskset -p <pid>CPU affinity
/proc/interrupts中断在 CPU 上的分布
mpstat -P ALL 1各 CPU 使用率

6. Linux 设计点:ELF

ELF 是 Linux 上常见的可执行文件和共享库格式。源代码经过编译、汇编、链接后形成 ELF 文件;执行时,内核和动态链接器把它装载到进程地址空间。

最小链路:

1
2
3
4
5
6
7
C 源码
  -> 编译
  -> 汇编
  -> 链接
  -> ELF 可执行文件
  -> execve()
  -> 装载到进程地址空间

Linux 落点:

概念Linux 落点
execve()替换当前进程的用户态程序映像
Program header描述运行时需要映射的段
动态链接器装载共享库、处理动态符号
地址空间text、data、heap、mmap、stack
/proc/<pid>/maps查看 ELF 段和共享库映射

ELF 和后续进程模型、虚拟内存、execve() 路径直接相关。

7. Linux 设计点:宏内核

Linux 是宏内核。进程调度、内存管理、文件系统、网络栈、设备驱动等大部分核心服务运行在内核态。

架构记录
宏内核核心服务集中在内核态,函数调用路径短,性能好,内核内部错误影响面大
微内核内核只保留最小能力,文件系统/驱动等服务可放用户态,隔离好,跨边界通信成本高
混合内核结合两者设计,具体系统实现差异大

Linux 也支持动态加载模块。很多驱动可以作为内核模块加载和卸载,但模块加载后仍运行在内核态。

机制记录
kernel module动态加载内核代码
Kconfig配置功能是否编进内核或作为模块
lsmod查看已加载模块
modinfo查看模块信息
dmesg查看内核日志

宏内核对学习路径的影响:读 Linux 时经常需要跨子系统看调用链,例如 read() 会同时碰到 syscall、VFS、page cache、调度和设备 I/O。

8. Windows 对照:只保留边界

Windows NT 和 Linux 的对照只记录三个边界。

对照点记录
内核架构Linux 是宏内核;Windows NT 通常归为混合内核
可执行文件Linux 常见 ELF;Windows 常见 PE
源码可得性Linux 内核源码开放,适合学习源码路径和做实验

这个系列后续只展开 Linux。Windows 对照用于理解不同 OS 可以采用不同内核组织方式。

压缩表

概念Linux 笔记落点
内核kernel/、mm/、fs/、net/、drivers/
用户态/内核态syscall、exception、interrupt、权限边界
MultiTasktask_struct、调度器、runqueue
SMPper-CPU runqueue、负载均衡、锁、RCU、CPU affinity
ELFexecve()、程序装载、/proc/<pid>/maps
Monolithic KernelVFS、网络栈、驱动、内存管理都在内核态协作

检查点与参考回答

问题参考回答
内核提供哪些基本能力?进程和线程管理、内存管理、硬件设备管理、文件系统、网络栈和系统调用接口。
用户态和内核态怎么区分?用户态运行普通应用,权限低;内核态运行内核代码,权限高,可以管理页表、设备、中断等核心资源。
系统调用是什么?系统调用是用户态程序请求内核服务的受控入口,内核会检查参数、权限和用户地址,再执行对应服务。
syscall、异常、中断有什么区别?syscall 是用户主动请求;异常来自当前指令,例如 page fault;中断来自外部硬件或定时器,和当前 task 不一定有关。
Linux 的 MultiTask 和 SMP 分别是什么意思?MultiTask 表示支持多个任务并发/并行推进;SMP 表示多个 CPU 地位对称,共享内存和硬件资源。
ELF 和 execve() 有什么关系?ELF 是可执行文件格式;execve() 会让当前进程装载新的 ELF 程序映像,替换原用户态地址空间内容。
宏内核对 Linux 学习有什么影响?很多核心服务都在内核态,真实路径经常跨多个子系统,例如 read() 会穿过 syscall、VFS、page cache、调度和设备 I/O。

本篇参考

  • Remzi H. Arpaci-Dusseau and Andrea C. Arpaci-Dusseau, Operating Systems: Three Easy Pieces
  • Michael Kerrisk, The Linux Programming Interface
  • Robert Love, Linux Kernel Development
  • Linux Kernel Documentation
本文由作者按照 CC BY 4.0 进行授权