graph TB
A["中断到达"] --> B["中断处理程序"]
B --> C{"耗时操作?"}
C -->|"是"| D["阻塞中断太久"]
C -->|"否"| E["快速完成"]
D -.->|系统卡顿| F["❌"]
E -.->|理想| G["✅"]
D -.->|解决| H["下半部机制"]
H --> H1["softirq"]
H --> H2["tasklet"]
H --> H3["workqueue"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFF9C4,stroke:#F9A825,color:#333
style D fill:#FFB3C6,stroke:#F48FB1,color:#333
style E fill:#B5EAD7,stroke:#80CBC4,color:#333
style F fill:#F48FB1,stroke:#FFB3C6,color:#333
style G fill:#80CBC4,stroke:#B5EAD7,color:#333
style H fill:#FFDAB9,stroke:#FFAB76,color:#333
style H1 fill:#FFF9C4,stroke:#F9A825,color:#333
style H2 fill:#FFF9C4,stroke:#F9A825,color:#333
style H3 fill:#FFF9C4,stroke:#F9A825,color:#333
核心原则:
中断处理 = 快进快出(不阻塞)
耗时操作 = 推迟到下半部
中断上下文不可睡眠 → 下半部也要分”可睡眠/不可睡眠”
一、中断上下半部模型
1.1 经典模型
graph TB
A["硬件中断"] --> B["上半部(Top Half)"]
B --> B1["最小操作\n响应硬件"]
B --> C["下半部(Bottom Half)"]
C --> C1["耗时操作\n完成实际工作"]
C1 --> D["唤醒等待进程"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style B1 fill:#FFF9C4,stroke:#F9A825,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style C1 fill:#FFF9C4,stroke:#F9A825,color:#333
style D fill:#B5EAD7,stroke:#80CBC4,color:#333
1.2 网络收包示例
sequenceDiagram
participant Nic as 网卡
participant Top as 上半部
participant Bot as 下半部
participant App as 应用进程
Nic->>Top: 接收中断
Top->>Top: 复制数据到 skb\n标记 softirq
Top-->>Nic: ACK
Note over Top: 上半部结束
Bot->>Bot: 在合适时机执行\nnet_rx_action
Bot->>Bot: 处理 skb\n提交协议栈
Bot->>App: 唤醒等待
二、Softirq
2.1 原理
graph TB
A["raise_softirq()"] --> B["标记 pending"]
B --> C["do_softirq()"]
C --> D["遍历每个 softirq"]
D --> E["有 pending?"]
E -->|"是"| F["执行 handler"]
E -->|"否"| G["跳过"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style D fill:#FFB3C6,stroke:#F48FB1,color:#333
style E fill:#FFF9C4,stroke:#F9A825,color:#333
style F fill:#B5EAD7,stroke:#80CBC4,color:#333
style G fill:#FFF9C4,stroke:#F9A825,color:#333
graph TB
A["softirq 执行点"] --> B["1. 中断退出"]
A --> C["2. ksoftirqd 内核线程"]
A --> D["3. 显式调用"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style D fill:#FFB3C6,stroke:#F48FB1,color:#333
注意:softirq 在中断上下文执行——不能睡眠。
2.5 关键启示
softirq = 最快下半部
静态注册(内核预定义 10 个)
不可睡眠
三、Tasklet
3.1 原理
graph TB
A["tasklet_schedule()"] --> B["标记 tasklet 状态"]
B --> C["触发 TASKLET_SOFTIRQ"]
C --> D["softirq 执行 tasklet"]
D --> E["调用 tasklet func"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style D fill:#FFB3C6,stroke:#F48FB1,color:#333
style E fill:#B5EAD7,stroke:#80CBC4,color:#333
graph TB
A["schedule_work()"] --> B["加入 workqueue"]
B --> C["worker 线程"]
C --> C1["wq_thread"]
C1 --> D["执行 work func"]
D --> E["可睡眠\n进程上下文"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style C1 fill:#FFB3C6,stroke:#F48FB1,color:#333
style D fill:#B5EAD7,stroke:#80CBC4,color:#333
style E fill:#FFF9C4,stroke:#F9A825,color:#333
graph TB
A["需要下半部?"] --> B{"能睡眠?"}
B -->|"否\n极快"| C{"同类型并发 OK?"}
B -->|"是"| E["workqueue"]
C -->|"是"| D["softirq\n(内核级)"]
C -->|"否\n需要序列化"| F["tasklet"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#FFF9C4,stroke:#F9A825,color:#333
style C fill:#FFF9C4,stroke:#F9A825,color:#333
style D fill:#B5EAD7,stroke:#80CBC4,color:#333
style E fill:#B5EAD7,stroke:#80CBC4,color:#333
style F fill:#FFDAB9,stroke:#FFAB76,color:#333
六、第 18 章:内核模块
6.1 什么是内核模块?
graph TB
A["内核"] --> B["静态编译\n直接编进内核"]
A --> C["动态加载\ninsmod / modprobe"]
B --> B1["kernel.img\n(大)"]
C --> C1[".ko 文件\n(可独立)"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style B1 fill:#FFF9C4,stroke:#F9A825,color:#333
style C1 fill:#FFF9C4,stroke:#F9A825,color:#333
graph TB
A[".ko 文件"] --> B[".text\n代码"]
A --> C[".data\n初始化数据"]
A --> D[".bss\n未初始化数据"]
A --> E[".modinfo\n模块信息"]
A --> F[".symtab\n符号表"]
A --> G[".strtab\n字符串表"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style D fill:#FFB3C6,stroke:#F48FB1,color:#333
style E fill:#B5EAD7,stroke:#80CBC4,color:#333
style F fill:#FFF9C4,stroke:#F9A825,color:#333
style G fill:#FFF9C4,stroke:#F9A825,color:#333
7.3 模块加载过程
sequenceDiagram
participant User as 用户
participant Mod as modprobe
participant Kern as 内核
User->>Mod: modprobe hello
Mod->>Mod: 解析依赖
Mod->>Kern: load_module
Kern->>Kern: 解析 ELF
Kern->>Kern: 重定位
Kern->>Kern: 解决符号
Kern->>Kern: 调 module_init
Kern-->>Mod: 成功
Mod-->>User: 完成
graph TB
A["中断下半部 + 模块核心"] --> B["softirq\n最快下半部"]
A --> C["tasklet\n序列化下半部"]
A --> D["workqueue\n进程上下文"]
A --> E["内核模块\n动态加载"]
A --> F["EXPORT_SYMBOL\n模块间共享"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style D fill:#FFB3C6,stroke:#F48FB1,color:#333
style E fill:#B5EAD7,stroke:#80CBC4,color:#333
style F fill:#FFF9C4,stroke:#F9A825,color:#333