内核编程十一:进程的数据结构

发布于:2025-03-26 ⋅ 阅读:(17) ⋅ 点赞:(0)

在Linux内核中,task_struct 是用于描述进程的核心数据结构,存储了进程的所有关键信息,包括进程ID、状态、调度信息、内存管理信息、文件描述符等。每个进程在内核中都对应一个 task_struct 结构体。


1. task_struct 的基本定义

task_struct 结构体的定义位于 include/linux/sched.h 头文件中。如下图所示,通过双向循环链表的方式将所有进程关联起来。

此结构体非常庞大, task_struct结构体中又包含了非常多的子结构体

由于task_struct内容较为庞大,这里列出部分关键字段: 

struct task_struct {
    volatile long state;         // 进程状态 (TASK_RUNNING 等)
    struct list_head tasks;      // 进程链表 (所有进程通过该字段连接)
    pid_t pid;                   // 进程 ID
    pid_t tgid;                  // 线程组 ID (线程与主线程共享)
    struct mm_struct *mm;        // 进程的内存管理信息
    struct thread_struct thread; // 进程的 CPU 相关信息 (寄存器等)
    struct list_head children;   // 子进程链表
    struct task_struct *parent;  // 父进程
    struct files_struct *files;  // 进程打开的文件信息
    struct fs_struct *fs;        // 进程的文件系统信息
    struct signal_struct *signal;// 进程的信号处理信息
    struct sched_entity se;      // 进程的调度信息
};

2. task_struct 主要字段解析

(1)进程状态

  • state:表示进程当前的状态,可能的取值包括:

    #define TASK_RUNNING       0  // 运行态或就绪态
    #define TASK_INTERRUPTIBLE 1  // 可中断睡眠状态
    #define TASK_UNINTERRUPTIBLE 2 // 不可中断睡眠状态
    #define TASK_STOPPED       4  // 进程已停止
    #define TASK_TRACED        8  // 进程被调试

(2)进程的标识

  • pid:进程 ID,是 Linux 内核唯一标识一个进程的数值。

  • tgid:线程组 ID,同一进程的多个线程共享相同的 tgid,而主线程的 pid == tgid

(3)进程调度

  • struct sched_entity se:保存进程的调度信息,如优先级、时间片等,供 CFS(Completely Fair Scheduler,完全公平调度器) 使用。

(4)进程的内存管理

  • struct mm_struct *mm:指向进程的内存管理结构,包含代码段、数据段、堆、栈等信息。

    • mm->pgd:页全局目录(Page Global Directory),用于地址转换。

    • mm->mmap:存储该进程的虚拟内存区域(VMA,Virtual Memory Area)。

  • struct fs_struct *fs:文件系统信息,比如 cwd(当前工作目录)。

(5)进程的关系

  • struct task_struct *parent:指向父进程。

  • struct list_head children:指向该进程创建的子进程列表。

(6)进程的文件管理

  • struct files_struct *files:保存进程打开的所有文件的描述符信息,如 fd

3.线程

task_struct 既表示进程,也表示线程
Linux 内核不区分进程和线程,所有的执行实体(tasks)都是 task_struct 结构体的一个实例。

线程和进程的主要区别在于:

  • 进程:有独立的地址空间(mm_struct)。
  • 线程:共享同一个地址空间(mm_struct),但 task_struct 依然是独立的。
  • Linux 线程创建时,调用 clone() 系统调用,最终创建一个新的 task_struct,但其 mm_struct 指针与父线程共享。

在Linux中,线程和进程的主要数据结构都是 task_struct,并不是 thread_info。

task_struct 是 Linux 内核中表示进程和线程的主要数据结构,而 thread_info 只是一个与 task_struct 关联的辅助结构,不能直接等同于线程的数据结构。


4. 进程的创建与 task_struct

Linux 创建进程主要通过 fork()clone()kernel_thread(),内核会:

  1. 调用 copy_process()

    • 为新进程分配 task_struct

    • 复制父进程的部分信息,如 pidmmfiles

    • 根据 clone 标志决定哪些资源共享(如文件、地址空间)。

  2. task_struct 插入进程链表

    • task_struct 通过 tasks 链接到 init_task 全局变量,实现进程管理。


5. task_struct 在内存中的存放

在 Linux 早期版本,task_struct 直接存放在 内核态栈 的底部,但由于 task_struct 变得越来越大,现代 Linux 将其单独分配在 slab 内存池 中。