Linux Kernel 由淺入深:從系統調用到進程調度的核心機制剖析


執行摘要

Linux 內核是現代計算基礎設施的核心,從智能手機到超級計算機無處不在。本文將深入剖析 Linux 內核的核心子系統:

  • 進程管理:task_struct、調度器、CFS 完全公平調度
  • 記憶體管理:虛擬記憶體、頁表、Slab 分配器
  • 文件系統:VFS 抽象層、inode、dentry 緩存
  • 網路協議棧:Socket、TCP/IP 實現
  • 系統調用:用戶空間與內核空間的橋樑

目錄

  1. Linux 內核架構總覽
  2. 進程管理與調度
  3. 記憶體管理
  4. 虛擬文件系統 VFS
  5. 網路協議棧
  6. 系統調用機制
  7. 中斷與異常處理
  8. 同步機制

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 內核分析。