当前位置: 首页 > article >正文

进程存储相关的关键数据结构

以下是Linux内核中进程存储相关的关键数据结构与代码解析:


1. 核心结构体定义(内核源码截取)

task_struct(进程描述符)
// include/linux/sched.h
struct task_struct {
    volatile long state;        // 进程状态(TASK_RUNNING等)
    struct mm_struct *mm;       // 用户空间内存管理器
    struct task_struct __rcu *parent; // 父进程指针
    pid_t pid;                  // 进程ID
    struct files_struct *files; // 打开文件表
    struct vm_struct *stack;    // 内核栈指针(与用户栈分离)
    // ... 其他200+个字段(调度、信号、命名空间等)
};
mm_struct(内存描述符)
// include/linux/mm_types.h
struct mm_struct {
    struct vm_area_struct *mmap;    // VMA链表头
    struct rb_root mm_rb;           // VMA红黑树根节点(加速查找)
    pgd_t * pgd;                    // 页全局目录(对应CR3寄存器值)
    unsigned long start_code, end_code; // 代码段起止地址
    unsigned long start_data, end_data; // 数据段
    unsigned long start_brk, brk;   // 堆区域当前边界
    unsigned long start_stack;      // 用户栈起始地址
    // ... 引用计数、内存策略等字段
};
vm_area_struct(虚拟内存区域)
// include/linux/mm_types.h
struct vm_area_struct {
    unsigned long vm_start;         // 区域起始地址
    unsigned long vm_end;           // 区域结束地址
    struct mm_struct *vm_mm;        // 所属内存描述符
    pgprot_t vm_page_prot;          // 访问权限(RWX)
    unsigned long vm_flags;         // 属性标志(VM_READ等)
    struct file * vm_file;          // 映射文件指针(如.so文件)
    // ... 反向映射、匿名映射等字段
};

2. 关键操作代码示例

进程创建时复制内存描述符(fork实现)
// kernel/fork.c
static int copy_mm(unsigned long clone_flags, struct task_struct *tsk)
{
    if (clone_flags & CLONE_VM) {     // 共享地址空间(线程场景)
        atomic_inc(&current->mm->mm_users);
        tsk->mm = current->mm;
        tsk->active_mm = current->mm;
    } else {
        tsk->mm = dup_mm(tsk);        // 复制父进程mm_struct
        if (!tsk->mm)
            return -ENOMEM;
    }
    return 0;
}
内存扩展(brk系统调用实现)
// mm/mmap.c
SYSCALL_DEFINE1(brk, unsigned long, brk)
{
    struct mm_struct *mm = current->mm;
    unsigned long newbrk = PAGE_ALIGN(brk);
    
    // 锁定内存描述符
    down_write(&mm->mmap_sem);
    
    // 检查堆扩展合法性
    if (check_data_rlimit(rlimit(RLIMIT_DATA), newbrk, mm->start_brk))
        goto out;

    // 调用内部函数调整堆区域
    ret = do_brk(mm->start_brk, newbrk - mm->start_brk);
    mm->brk = brk;

out:
    up_write(&mm->mmap_sem);
    return ret;
}
查找虚拟内存区域(缺页中断处理)
// mm/memory.c
struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
{
    struct rb_node *rb_node;
    struct vm_area_struct *vma;

    // 通过红黑树快速查找
    rb_node = mm->mm_rb.rb_node;
    while (rb_node) {
        vma = rb_entry(rb_node, struct vm_area_struct, vm_rb);
        if (addr < vma->vm_start)
            rb_node = rb_node->rb_left;
        else if (addr >= vma->vm_end)
            rb_node = rb_node->rb_right;
        else
            return vma;
    }
    return NULL;
}

3. 用户态观测工具示例

查看进程内存映射(/proc/PID/maps解析)
# 示例输出(对应vm_area_struct链表)
00400000-00401000 r-xp 00000000 08:01 123456   /path/to/program  # 代码段
00600000-00602000 rw-p 00000000 08:01 123456   /path/to/program  # 数据段
7f8d12345000-7f8d12367000 r-xp 00000000 08:01 7890  /lib/x86_64-linux-gnu/libc.so.6  # 共享库
7ffeefbff000-7ffeefc00000 rw-p 00000000 00:00 0     [stack]      # 用户栈
内核调试示例(通过crash工具)
crash> ps -p 1234  # 查找目标进程的task_struct地址
   PID    PPID  CPU       TASK        ST  %MEM     VSZ    RSS  COMM
   1234   1212   0  ffff88003d45a000  IN   0.2   23456   4567  myapp

crash> struct mm_struct ffff88003d45a000.mm  # 查看mm_struct
struct mm_struct {
  mmap = 0xffff88003a12b000, 
  mm_rb = {
    rb_node = 0xffff88003a12b0a0
  },
  pgd = 0xffff88003d123000,
  start_code = 0x400000,
  end_code = 0x401000,
  start_data = 0x600000,
  end_data = 0x602000,
  // ...其他字段
}

crash> list vm_area_struct -l 0xffff88003a12b000  # 遍历VMA链表
ffff88003a12b000
  vm_start = 0x400000
  vm_end = 0x401000
  vm_flags = VM_READ | VM_EXEC
  vm_file = 0xffff88003d456000 ("/usr/bin/myapp")

4. 物理内存映射关键函数

页表项设置(x86_64架构)
// arch/x86/mm/pgtable.c
void set_pte_vaddr(unsigned long vaddr, pte_t pteval)
{
    pgd_t *pgd = __va(read_cr3_pa());  // 获取当前进程的PGD
    pud_t *pud = pud_offset(pgd, vaddr);
    pmd_t *pmd = pmd_offset(pud, vaddr);
    pte_t *pte = pte_offset_kernel(pmd, vaddr);

    set_pte(pte, pteval);  // 设置具体页表项
    __flush_tlb_one_kernel(vaddr);  // 刷新TLB
}

关键数据流图示

用户进程虚拟地址空间
   |
   |-- 通过vm_area_struct描述每个区域属性
   V
mm_struct (管理整个地址空间)
   |
   |-- pgd指向页表根目录
   V
物理页框 (通过页表项PTE连接)

通过以上代码和结构体,内核精确控制用户进程的内存生命周期。开发调试时可结合/proc文件系统和内核工具进行深度观测。


http://www.kler.cn/a/576423.html

相关文章:

  • 网络编程 day4
  • 使用开源OPUS-MT模型进行文本翻译(python)
  • 针对Ollama进行DeepSeek本地部署存在的安全风险,使用nginx进行反向代理配置是一种有效的解决方案
  • 开发环境搭建-07.后端环境搭建-前后端联调-Nginx反向代理和负载均衡配置
  • 微软发布Dragon Copilot,打造医疗行业首款AI语音助手
  • 深度学习代码解读——自用
  • Qt调试功能使用方法
  • bash: uwsgi: 未找到命令
  • 基于Python+openGauss实现(图形界面)多功能本地视频播放系统
  • 使用 Apache POI 实现 Excel 单元格合并
  • uniapp 安卓app图片回显,默认不支持http图片地址,上传图片和回显图片
  • 腾讯 TDF 即将开源 Kuikly 跨端框架,Kotlin 支持全平台
  • 人工智能与深度学习的应用案例:从技术原理到实践创新
  • 紫光无人机AI飞控平台2.0——航线管理模块
  • ⭐算法OJ⭐N-皇后问题【回溯剪枝】(C++实现)N-Queens
  • 不小心更改了/etc权限为777导致sudo,ssh等软件都无法使用
  • Vue基础之Element-ui
  • 2025-03-07 学习记录--C/C++-PTA 习题8-5 使用函数实现字符串部分复制
  • 【如何删除在 Linux 系统中的删除乱码文件】
  • SpringSecurity认证授权完整流程