Linux Kernel 由淺入深:從系統調用到進程調度的核心機制剖析
執行摘要
Linux 內核是現代計算基礎設施的核心,從智能手機到超級計算機無處不在。本文將深入剖析 Linux 內核的核心子系統:
- 進程管理:task_struct、調度器、CFS 完全公平調度
- 記憶體管理:虛擬記憶體、頁表、Slab 分配器
- 文件系統:VFS 抽象層、inode、dentry 緩存
- 網路協議棧:Socket、TCP/IP 實現
- 系統調用:用戶空間與內核空間的橋樑
目錄
1. Linux 內核架構總覽
1.1 內核層次結構
flowchart TB
subgraph UserSpace["用戶空間"]
App[應用程式]
Lib[C 標準庫 glibc]
end
subgraph KernelSpace["內核空間"]
subgraph Interface["系統調用介面"]
SCI[System Call Interface]
end
subgraph Subsystems["核心子系統"]
PM[進程管理<br/>Process Management]
MM[記憶體管理<br/>Memory Management]
VFS[虛擬文件系統<br/>Virtual File System]
NET[網路子系統<br/>Network Stack]
IPC[進程間通訊<br/>IPC]
end
subgraph Arch["架構相關層"]
ARCH[x86/ARM/RISC-V...]
end
subgraph Drivers["設備驅動"]
DD[Device Drivers]
end
end
subgraph Hardware["硬體"]
CPU[CPU]
MEM[Memory]
DISK[Storage]
NIC[Network]
end
App --> Lib
Lib --> SCI
SCI --> PM
SCI --> MM
SCI --> VFS
SCI --> NET
PM --> ARCH
MM --> ARCH
VFS --> DD
NET --> DD
ARCH --> CPU
ARCH --> MEM
DD --> DISK
DD --> NIC
1.2 源碼目錄結構
linux/
├── arch/ # 架構相關代碼 (x86, arm, riscv...)
│ └── x86/
│ ├── kernel/ # 核心功能
│ ├── mm/ # 記憶體管理
│ └── entry/ # 系統調用入口
├── kernel/ # 核心子系統
│ ├── sched/ # 調度器
│ ├── time/ # 時間管理
│ └── locking/ # 鎖機制
├── mm/ # 記憶體管理
├── fs/ # 文件系統
│ ├── ext4/ # ext4 文件系統
│ └── proc/ # proc 文件系統
├── net/ # 網路協議棧
│ ├── core/ # 核心功能
│ ├── ipv4/ # IPv4
│ └── socket.c # socket 實現
├── drivers/ # 設備驅動
├── include/ # 頭文件
│ ├── linux/ # 通用頭文件
│ └── asm-generic/ # 架構無關
└── init/ # 初始化代碼
└── main.c # 內核入口 start_kernel()
1.3 內核啟動流程
sequenceDiagram
participant BIOS/UEFI
participant Bootloader
participant Kernel
participant Init
BIOS/UEFI->>Bootloader: 加載 GRUB/systemd-boot
Bootloader->>Bootloader: 選擇內核
Bootloader->>Kernel: 加載 vmlinuz 到記憶體
activate Kernel
Kernel->>Kernel: start_kernel()
Note over Kernel: 1. 初始化 CPU
Note over Kernel: 2. 初始化記憶體管理
Note over Kernel: 3. 初始化調度器
Note over Kernel: 4. 初始化 VFS
Note over Kernel: 5. 掛載根文件系統
Kernel->>Init: 執行 /sbin/init (PID 1)
deactivate Kernel
Init->>Init: systemd 初始化
Note over Init: 啟動各種服務
2. 進程管理與調度
2.1 task_struct 結構
task_struct 是 Linux 中最核心的數據結構,描述一個進程/線程的所有信息:
// include/linux/sched.h
struct task_struct {
// ===== 調度相關 =====
volatile long state; // 進程狀態
int prio; // 動態優先級
int static_prio; // 靜態優先級
int normal_prio; // 正常優先級
unsigned int rt_priority; // 實時優先級
const struct sched_class *sched_class; // 調度類
struct sched_entity se; // CFS 調度實體
struct sched_rt_entity rt; // 實時調度實體
// ===== 進程關係 =====
pid_t pid; // 進程 ID
pid_t tgid; // 線程組 ID
struct task_struct *real_parent; // 真實父進程
struct task_struct *parent; // 父進程(可能被 ptrace)
struct list_head children; // 子進程鏈表
struct list_head sibling; // 兄弟進程鏈表
// ===== 記憶體管理 =====
struct mm_struct *mm; // 記憶體描述符
struct mm_struct *active_mm; // 活動記憶體
// ===== 文件系統 =====
struct fs_struct *fs; // 文件系統信息
struct files_struct *files; // 打開的文件
// ===== 命名空間 =====
struct nsproxy *nsproxy; // 命名空間代理
// ===== 信號處理 =====
struct signal_struct *signal; // 信號處理
struct sighand_struct *sighand; // 信號處理函數
// ===== 時間統計 =====
u64 utime; // 用戶態時間
u64 stime; // 內核態時間
u64 start_time; // 啟動時間
// ===== 棧 =====
void *stack; // 內核棧指針
// ... 更多字段(總共約 600+ 行)
};
2.2 進程狀態
stateDiagram-v2
[*] --> TASK_RUNNING: fork()
TASK_RUNNING: 可運行
TASK_INTERRUPTIBLE: 可中斷睡眠
TASK_UNINTERRUPTIBLE: 不可中斷睡眠
TASK_STOPPED: 停止
TASK_TRACED: 被跟蹤
EXIT_ZOMBIE: 殭屍
EXIT_DEAD: 死亡
TASK_RUNNING --> TASK_INTERRUPTIBLE: 等待資源
TASK_RUNNING --> TASK_UNINTERRUPTIBLE: 等待 I/O
TASK_INTERRUPTIBLE --> TASK_RUNNING: 收到信號/資源就緒
TASK_UNINTERRUPTIBLE --> TASK_RUNNING: I/O 完成
TASK_RUNNING --> TASK_STOPPED: SIGSTOP
TASK_STOPPED --> TASK_RUNNING: SIGCONT
TASK_RUNNING --> TASK_TRACED: ptrace
TASK_TRACED --> TASK_RUNNING: ptrace detach
TASK_RUNNING --> EXIT_ZOMBIE: exit()
EXIT_ZOMBIE --> EXIT_DEAD: wait()
EXIT_DEAD --> [*]
2.3 CFS 完全公平調度器
flowchart TB
subgraph CFS["CFS 調度器"]
RBTree[紅黑樹<br/>按 vruntime 排序]
Min[最左節點<br/>vruntime 最小]
end
subgraph Entities["調度實體"]
E1[Task A<br/>vruntime=100]
E2[Task B<br/>vruntime=120]
E3[Task C<br/>vruntime=150]
end
RBTree --> Min
Min --> E1
E1 --> E2
E2 --> E3
Note1[選擇 vruntime 最小的進程運行]
CFS 核心算法
// kernel/sched/fair.c
// 虛擬運行時間計算
// vruntime = 實際運行時間 * (NICE_0_LOAD / 權重)
static inline u64 calc_delta_fair(u64 delta, struct sched_entity *se) {
if (unlikely(se->load.weight != NICE_0_LOAD))
delta = __calc_delta(delta, NICE_0_LOAD, &se->load);
return delta;
}
// 權重表(nice 值對應的權重)
const int sched_prio_to_weight[40] = {
/* -20 */ 88761, 71755, 56483, 46273, 36291,
/* -15 */ 29154, 23254, 18705, 14949, 11916,
/* -10 */ 9548, 7620, 6100, 4904, 3906,
/* -5 */ 3121, 2501, 1991, 1586, 1277,
/* 0 */ 1024, 820, 655, 526, 423,
/* 5 */ 335, 272, 215, 172, 137,
/* 10 */ 110, 87, 70, 56, 45,
/* 15 */ 36, 29, 23, 18, 15,
};
// 選擇下一個進程
static struct task_struct *pick_next_task_fair(struct rq *rq) {
struct sched_entity *se;
struct cfs_rq *cfs_rq = &rq->cfs;
if (!cfs_rq->nr_running)
return NULL;
// 選擇紅黑樹最左節點(vruntime 最小)
se = pick_next_entity(cfs_rq);
return task_of(se);
}
// 更新 vruntime
static void update_curr(struct cfs_rq *cfs_rq) {
struct sched_entity *curr = cfs_rq->curr;
u64 now = rq_clock_task(rq_of(cfs_rq));
u64 delta_exec;
delta_exec = now - curr->exec_start;
curr->exec_start = now;
curr->sum_exec_runtime += delta_exec;
// 更新虛擬運行時間
curr->vruntime += calc_delta_fair(delta_exec, curr);
update_min_vruntime(cfs_rq);
}
2.4 調度類層次
flowchart LR
subgraph SchedClasses["調度類優先級(高→低)"]
STOP[stop_sched_class<br/>停止調度]
DL[dl_sched_class<br/>Deadline 調度]
RT[rt_sched_class<br/>實時調度]
FAIR[fair_sched_class<br/>CFS 調度]
IDLE[idle_sched_class<br/>空閒調度]
end
STOP --> DL --> RT --> FAIR --> IDLE
3. 記憶體管理
3.1 虛擬記憶體佈局
flowchart TB
subgraph VirtualMemory["64位進程虛擬地址空間"]
K1[內核空間<br/>0xFFFF800000000000+]
K2[...]
U5[Stack<br/>向下增長]
U4[Memory Mapped<br/>共享庫、mmap]
U3[Heap<br/>向上增長 brk/sbrk]
U2[BSS + Data<br/>未初始化/已初始化數據]
U1[Text<br/>代碼段]
U0[保留<br/>0x0]
end
K1 --> K2
K2 --> U5
U5 --> U4
U4 --> U3
U3 --> U2
U2 --> U1
U1 --> U0
3.2 mm_struct 記憶體描述符
// include/linux/mm_types.h
struct mm_struct {
// VMA 紅黑樹根
struct rb_root mm_rb;
// 代碼、數據、堆、棧邊界
unsigned long start_code, end_code;
unsigned long start_data, end_data;
unsigned long start_brk, brk;
unsigned long start_stack;
unsigned long arg_start, arg_end;
unsigned long env_start, env_end;
// 頁表
pgd_t *pgd;
// 引用計數
atomic_t mm_users; // 用戶引用
atomic_t mm_count; // 內核引用
// VMA 數量
int map_count;
// 統計
unsigned long total_vm; // 總頁數
unsigned long locked_vm; // 鎖定頁數
unsigned long pinned_vm; // 固定頁數
unsigned long data_vm; // 數據頁數
unsigned long exec_vm; // 可執行頁數
unsigned long stack_vm; // 棧頁數
// RSS (Resident Set Size)
unsigned long rss_stat[NR_MM_COUNTERS];
};
3.3 頁表結構 (x86_64)
flowchart LR
subgraph VA["虛擬地址 48位"]
PGD_IDX[PGD Index<br/>9 bits]
PUD_IDX[PUD Index<br/>9 bits]
PMD_IDX[PMD Index<br/>9 bits]
PTE_IDX[PTE Index<br/>9 bits]
OFFSET[Page Offset<br/>12 bits]
end
subgraph PageTables["4級頁表"]
PGD[PGD<br/>Page Global Dir]
PUD[PUD<br/>Page Upper Dir]
PMD[PMD<br/>Page Middle Dir]
PTE[PTE<br/>Page Table Entry]
PAGE[物理頁面<br/>4KB]
end
PGD_IDX --> PGD
PGD --> PUD_IDX
PUD_IDX --> PUD
PUD --> PMD_IDX
PMD_IDX --> PMD
PMD --> PTE_IDX
PTE_IDX --> PTE
PTE --> OFFSET
OFFSET --> PAGE
3.4 Slab 分配器
flowchart TB
subgraph SlabAllocator["Slab 分配器"]
Cache[kmem_cache<br/>對象緩存]
subgraph Slabs["Slab 鏈表"]
Full[full slabs<br/>已滿]
Partial[partial slabs<br/>部分使用]
Empty[empty slabs<br/>空閒]
end
subgraph Slab["單個 Slab"]
Obj1[Object 1]
Obj2[Object 2]
Obj3[Object 3]
ObjN[Object N]
end
end
Cache --> Full
Cache --> Partial
Cache --> Empty
Partial --> Slab
// mm/slab.c / mm/slub.c
// 創建對象緩存
struct kmem_cache *kmem_cache_create(
const char *name, // 緩存名稱
unsigned int size, // 對象大小
unsigned int align, // 對齊
slab_flags_t flags, // 標誌
void (*ctor)(void *) // 構造函數
);
// 分配對象
void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags);
// 釋放對象
void kmem_cache_free(struct kmem_cache *cachep, void *objp);
// 常用對象緩存
// task_struct、inode、dentry、file 等都有專用緩存
3.5 頁面回收 (Page Reclaim)
flowchart TB
subgraph LRU["LRU 鏈表"]
Active[Active List<br/>活躍頁面]
Inactive[Inactive List<br/>不活躍頁面]
end
subgraph Pages["頁面類型"]
Anon[Anonymous Pages<br/>匿名頁(堆、棧)]
File[File Pages<br/>文件映射頁]
end
subgraph Actions["回收動作"]
Swap[Swap Out<br/>交換到磁盤]
WriteBack[Write Back<br/>寫回文件]
Drop[Drop<br/>直接丟棄(乾淨頁)]
end
Active --> |降級| Inactive
Inactive --> |訪問| Active
Inactive --> |回收| Actions
Anon --> Swap
File --> WriteBack
File --> Drop
4. 虛擬文件系統 VFS
4.1 VFS 架構
flowchart TB
subgraph UserSpace["用戶空間"]
App[應用程式]
end
subgraph VFS["VFS 抽象層"]
SysCall[系統調用<br/>open/read/write/close]
VFSLayer[VFS 核心]
Dentry[dentry 緩存]
Inode[inode 緩存]
PageCache[Page Cache]
end
subgraph FileSystems["具體文件系統"]
EXT4[ext4]
XFS[xfs]
BTRFS[btrfs]
NFS[nfs]
PROC[proc]
end
subgraph Block["塊層"]
BIO[bio 請求]
Scheduler[I/O 調度器]
end
subgraph Drivers["驅動"]
NVME[NVMe 驅動]
SCSI[SCSI 驅動]
end
App --> SysCall
SysCall --> VFSLayer
VFSLayer --> Dentry
VFSLayer --> Inode
VFSLayer --> PageCache
VFSLayer --> EXT4
VFSLayer --> XFS
VFSLayer --> BTRFS
VFSLayer --> NFS
VFSLayer --> PROC
EXT4 --> BIO
XFS --> BIO
BIO --> Scheduler
Scheduler --> NVME
Scheduler --> SCSI
4.2 核心數據結構
// include/linux/fs.h
// 超級塊 - 文件系統元信息
struct super_block {
struct list_head s_list; // 超級塊鏈表
dev_t s_dev; // 設備號
unsigned long s_blocksize; // 塊大小
loff_t s_maxbytes; // 最大文件大小
struct file_system_type *s_type; // 文件系統類型
const struct super_operations *s_op; // 超級塊操作
struct dentry *s_root; // 根目錄 dentry
// ...
};
// inode - 文件元信息
struct inode {
umode_t i_mode; // 文件類型和權限
kuid_t i_uid; // 所有者 UID
kgid_t i_gid; // 所有者 GID
unsigned int i_flags; // 標誌
const struct inode_operations *i_op; // inode 操作
struct super_block *i_sb; // 所屬超級塊
unsigned long i_ino; // inode 號
loff_t i_size; // 文件大小
struct timespec64 i_atime; // 訪問時間
struct timespec64 i_mtime; // 修改時間
struct timespec64 i_ctime; // 變更時間
const struct file_operations *i_fop; // 文件操作
struct address_space *i_mapping; // 頁緩存
// ...
};
// dentry - 目錄項緩存
struct dentry {
struct dentry *d_parent; // 父目錄
struct qstr d_name; // 文件名
struct inode *d_inode; // 關聯的 inode
const struct dentry_operations *d_op; // dentry 操作
struct super_block *d_sb; // 超級塊
struct list_head d_child; // 父目錄的子項鏈表
struct list_head d_subdirs; // 子目錄鏈表
// ...
};
// file - 打開的文件
struct file {
struct path f_path; // 路徑
struct inode *f_inode; // inode
const struct file_operations *f_op; // 文件操作
spinlock_t f_lock; // 鎖
fmode_t f_mode; // 打開模式
loff_t f_pos; // 當前位置
struct fown_struct f_owner; // 所有者
const struct cred *f_cred; // 憑證
// ...
};
4.3 文件操作接口
// 文件操作函數表
struct file_operations {
loff_t (*llseek)(struct file *, loff_t, int);
ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
int (*open)(struct inode *, struct file *);
int (*release)(struct inode *, struct file *);
int (*mmap)(struct file *, struct vm_area_struct *);
int (*fsync)(struct file *, loff_t, loff_t, int);
// ...
};
// inode 操作函數表
struct inode_operations {
struct dentry * (*lookup)(struct inode *, struct dentry *, unsigned int);
int (*create)(struct mnt_idmap *, struct inode *, struct dentry *, umode_t, bool);
int (*link)(struct dentry *, struct inode *, struct dentry *);
int (*unlink)(struct inode *, struct dentry *);
int (*mkdir)(struct mnt_idmap *, struct inode *, struct dentry *, umode_t);
int (*rmdir)(struct inode *, struct dentry *);
int (*rename)(struct mnt_idmap *, struct inode *, struct dentry *,
struct inode *, struct dentry *, unsigned int);
// ...
};
5. 網路協議棧
5.1 協議棧架構
flowchart TB
subgraph UserSpace["用戶空間"]
App[應用程式]
Socket[socket() API]
end
subgraph Transport["傳輸層"]
TCP[TCP]
UDP[UDP]
end
subgraph Network["網路層"]
IP[IP]
Routing[路由表]
Netfilter[Netfilter/iptables]
end
subgraph Link["鏈路層"]
Device[網路設備抽象]
Driver[網卡驅動]
end
subgraph Hardware["硬體"]
NIC[網卡 NIC]
end
App --> Socket
Socket --> TCP
Socket --> UDP
TCP --> IP
UDP --> IP
IP --> Routing
Routing --> Netfilter
Netfilter --> Device
Device --> Driver
Driver --> NIC
5.2 sk_buff 結構
// include/linux/skbuff.h
// sk_buff 是網路數據包的核心結構
struct sk_buff {
// 鏈表指針
struct sk_buff *next;
struct sk_buff *prev;
// 時間戳
ktime_t tstamp;
// 所屬 socket
struct sock *sk;
// 網路設備
struct net_device *dev;
// 協議頭指針
union {
struct tcphdr *th;
struct udphdr *uh;
struct icmphdr *icmph;
unsigned char *raw;
} h; // 傳輸層頭
union {
struct iphdr *iph;
struct ipv6hdr *ipv6h;
unsigned char *raw;
} nh; // 網路層頭
union {
struct ethhdr *ethernet;
unsigned char *raw;
} mac; // 鏈路層頭
// 數據指針
unsigned char *head; // 緩衝區開始
unsigned char *data; // 數據開始
unsigned char *tail; // 數據結束
unsigned char *end; // 緩衝區結束
unsigned int len; // 數據長度
unsigned int data_len; // 分片數據長度
// 協議信息
__be16 protocol; // 協議類型
__u16 transport_header; // 傳輸層偏移
__u16 network_header; // 網路層偏移
__u16 mac_header; // MAC 層偏移
// ...
};
5.3 數據包接收流程
sequenceDiagram
participant NIC
participant Driver
participant NAPI
participant Netfilter
participant IP
participant TCP
participant Socket
participant App
NIC->>Driver: 硬體中斷
Driver->>Driver: 關閉硬體中斷
Driver->>NAPI: napi_schedule()
Note over NAPI: 軟中斷處理
loop NAPI poll
NAPI->>Driver: napi_poll()
Driver->>NAPI: 分配 sk_buff
NAPI->>NAPI: netif_receive_skb()
end
NAPI->>Netfilter: PREROUTING
Netfilter->>IP: ip_rcv()
IP->>IP: 路由查找
IP->>Netfilter: LOCAL_IN
Netfilter->>TCP: tcp_v4_rcv()
TCP->>TCP: 查找 socket
TCP->>Socket: 放入接收隊列
Socket->>App: 喚醒等待進程
6. 系統調用機制
6.1 系統調用流程 (x86_64)
sequenceDiagram
participant App as 應用程式
participant Glibc as glibc
participant Kernel as 內核
App->>Glibc: read(fd, buf, len)
Glibc->>Glibc: 準備參數到寄存器<br/>rax=0 (syscall號)<br/>rdi=fd, rsi=buf, rdx=len
Glibc->>Kernel: syscall 指令
activate Kernel
Note over Kernel: 1. 保存用戶態寄存器
Note over Kernel: 2. 切換到內核棧
Note over Kernel: 3. 查找系統調用表
Note over Kernel: 4. 調用 ksys_read()
Note over Kernel: 5. 返回結果到 rax
Kernel->>Glibc: sysret 指令
deactivate Kernel
Glibc->>App: 返回讀取字節數
6.2 系統調用表
// arch/x86/entry/syscalls/syscall_64.tbl
// 系統調用號 | ABI | 名稱 | 入口函數
0 common read sys_read
1 common write sys_write
2 common open sys_open
3 common close sys_close
4 common stat sys_newstat
5 common fstat sys_newfstat
...
56 common clone sys_clone
57 common fork sys_fork
58 common vfork sys_vfork
59 common execve sys_execve
60 common exit sys_exit
...
// arch/x86/entry/syscall_64.c
// 系統調用表
asmlinkage const sys_call_ptr_t sys_call_table[] = {
[0] = sys_read,
[1] = sys_write,
[2] = sys_open,
// ...
};
6.3 系統調用入口
// arch/x86/entry/entry_64.S
SYM_CODE_START(entry_SYSCALL_64)
// 交換 GS 寄存器(用戶態 <-> 內核態)
swapgs
// 保存用戶態棧指針
movq %rsp, PER_CPU_VAR(cpu_tss_rw + TSS_sp2)
// 切換到內核棧
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
// 保存寄存器
pushq $__USER_DS // SS
pushq PER_CPU_VAR(cpu_tss_rw + TSS_sp2) // RSP
pushq %r11 // RFLAGS
pushq $__USER_CS // CS
pushq %rcx // RIP
// 調用 C 函數
call do_syscall_64
// 恢復並返回
...
sysretq
SYM_CODE_END(entry_SYSCALL_64)
// arch/x86/entry/common.c
__visible noinstr void do_syscall_64(struct pt_regs *regs, int nr)
{
if (likely(nr < NR_syscalls)) {
nr = array_index_nospec(nr, NR_syscalls);
regs->ax = sys_call_table[nr](regs);
}
}
7. 中斷與異常處理
7.1 中斷處理流程
flowchart TB
subgraph Hardware["硬體"]
Device[設備]
APIC[Local APIC]
IOAPIC[I/O APIC]
end
subgraph Interrupt["中斷處理"]
IDT[IDT 中斷描述符表]
ISR[中斷服務程序]
TopHalf[上半部<br/>關中斷,快速處理]
BottomHalf[下半部<br/>開中斷,延遲處理]
end
subgraph BottomMechanisms["下半部機制"]
SoftIRQ[軟中斷 softirq]
Tasklet[Tasklet]
Workqueue[工作隊列 workqueue]
end
Device --> IOAPIC --> APIC
APIC --> IDT --> ISR
ISR --> TopHalf --> BottomHalf
BottomHalf --> SoftIRQ
BottomHalf --> Tasklet
BottomHalf --> Workqueue
7.2 軟中斷類型
// include/linux/interrupt.h
enum {
HI_SOFTIRQ=0, // 高優先級 tasklet
TIMER_SOFTIRQ, // 定時器
NET_TX_SOFTIRQ, // 網路發送
NET_RX_SOFTIRQ, // 網路接收
BLOCK_SOFTIRQ, // 塊設備
IRQ_POLL_SOFTIRQ, // IRQ 輪詢
TASKLET_SOFTIRQ, // 普通 tasklet
SCHED_SOFTIRQ, // 調度
HRTIMER_SOFTIRQ, // 高精度定時器
RCU_SOFTIRQ, // RCU 回調
NR_SOFTIRQS
};
8. 同步機制
8.1 同步原語對比
flowchart TB
subgraph Primitives["同步原語"]
Spinlock[自旋鎖 spinlock<br/>忙等待]
Mutex[互斥鎖 mutex<br/>睡眠等待]
Semaphore[信號量 semaphore<br/>計數]
RWLock[讀寫鎖 rwlock<br/>讀共享寫互斥]
RCU[RCU<br/>讀無鎖]
end
subgraph UseCase["使用場景"]
UC1[中斷上下文<br/>短時間鎖定]
UC2[進程上下文<br/>可能睡眠]
UC3[資源計數<br/>生產者消費者]
UC4[讀多寫少]
UC5[讀極多寫極少<br/>如路由表]
end
Spinlock --> UC1
Mutex --> UC2
Semaphore --> UC3
RWLock --> UC4
RCU --> UC5
8.2 自旋鎖實現
// include/linux/spinlock.h
typedef struct spinlock {
struct raw_spinlock rlock;
} spinlock_t;
// 獲取鎖
static inline void spin_lock(spinlock_t *lock) {
raw_spin_lock(&lock->rlock);
}
// 釋放鎖
static inline void spin_unlock(spinlock_t *lock) {
raw_spin_unlock(&lock->rlock);
}
// 關中斷 + 獲取鎖
spin_lock_irqsave(lock, flags);
spin_unlock_irqrestore(lock, flags);
8.3 RCU (Read-Copy-Update)
sequenceDiagram
participant Reader1
participant Reader2
participant Writer
participant Memory
Note over Memory: old_data
Reader1->>Memory: rcu_read_lock()
Reader1->>Memory: 讀取 old_data
Writer->>Memory: 分配 new_data
Writer->>Memory: 複製並修改
Writer->>Memory: rcu_assign_pointer(ptr, new_data)
Note over Memory: ptr 指向 new_data
Reader2->>Memory: rcu_read_lock()
Reader2->>Memory: 讀取 new_data
Reader1->>Memory: rcu_read_unlock()
Writer->>Writer: synchronize_rcu()
Note over Writer: 等待所有舊讀者完成
Writer->>Memory: kfree(old_data)
總結
Linux 內核的設計體現了多個核心原則:
| 設計原則 | 實現 | 優勢 |
|---|---|---|
| 單體內核 | 所有組件在同一地址空間 | 高性能,低延遲 |
| 模組化 | 可動態載入/卸載模組 | 靈活性 |
| 抽象層 | VFS、設備模型 | 可擴展性 |
| 精細鎖粒度 | 每 CPU 變量、RCU | 可擴展性 |
| 零拷貝 | sendfile、splice | 高吞吐 |
參考資料
本文基於 Linux 6.x 內核分析。