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

Linux中进程创建和缓存对象初始化fork_init、proc_caches_init和buffer_init

初始化进程创建 fork_init

void __init fork_init(unsigned long mempages)
{
#ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR
#ifndef ARCH_MIN_TASKALIGN
#define ARCH_MIN_TASKALIGN      L1_CACHE_BYTES
#endif/* create a slab on which task_structs can be allocated */task_struct_cachep =kmem_cache_create("task_struct", sizeof(struct task_struct),ARCH_MIN_TASKALIGN, SLAB_PANIC, NULL, NULL);
#endif/** The default maximum number of threads is set to a safe* value: the thread structures can take up at most half* of memory.*/max_threads = mempages / (8 * THREAD_SIZE / PAGE_SIZE);/** we need to allow at least 20 threads to boot a system*/if(max_threads < 20)max_threads = 20;init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
}

函数功能概述

fork_init 函数用于初始化进程创建(fork)相关的子系统,包括任务结构缓存池的创建和线程数量限制的设置

代码详细解释

第一部分:任务结构缓存池初始化

#ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR
#ifndef ARCH_MIN_TASKALIGN
#define ARCH_MIN_TASKALIGN      L1_CACHE_BYTES
#endif
  • 条件编译检查:如果没有定义架构特定的任务结构分配器(__HAVE_ARCH_TASK_STRUCT_ALLOCATOR),则使用默认的 slab 分配器
  • 对齐设置:如果没有定义架构最小任务对齐(ARCH_MIN_TASKALIGN),则默认使用 L1 缓存行大小作为对齐值,这有利于缓存性能
        task_struct_cachep =kmem_cache_create("task_struct", sizeof(struct task_struct),ARCH_MIN_TASKALIGN, SLAB_PANIC, NULL, NULL);
#endif
  • 创建 slab 缓存:使用 kmem_cache_create 创建一个专门用于分配 task_struct 的 slab 缓存池
  • 参数说明
    • "task_struct":缓存名称
    • sizeof(struct task_struct):每个对象的大小
    • ARCH_MIN_TASKALIGN:对齐要求
    • SLAB_PANIC:标志位,表示如果创建失败则系统崩溃
    • NULL, NULL:构造函数和析构函数(这里不需要)

第二部分:最大线程数计算

        max_threads = mempages / (8 * THREAD_SIZE / PAGE_SIZE);
  • 计算最大线程数:基于系统内存页数计算最大允许的线程数量
  • 计算公式mempages / (8 * THREAD_SIZE / PAGE_SIZE)
    • THREAD_SIZE 是每个线程内核栈的大小
    • PAGE_SIZE 是页面大小
    • 8 * THREAD_SIZE / PAGE_SIZE 计算每个线程需要的内存页数
    • 8 是经验值,确保其他结构有内存预留
        if(max_threads < 20)max_threads = 20;
  • 最小线程数保障:确保系统至少有 20 个线程的容量,这是系统启动所需的最小线程数

第三部分:进程数资源限制设置

        init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
  • 设置进程数限制:为初始进程(init_task)设置 RLIMIT_NPROC 资源限制
  • 限制值:当前值(rlim_cur)和最大值(rlim_max)都设置为最大线程数的一半
  • RLIMIT_NPROC:限制每个用户能够创建的进程数量

函数功能总结

  1. 任务结构缓存初始化:为 task_struct 创建专用的内存缓存池,提高进程创建时的内存分配效率
  2. 线程数量限制计算:根据系统内存大小动态计算最大线程数,确保系统稳定性
  3. 资源限制设置:设置每个用户能够创建的进程数上限,防止资源耗尽

初始化进程管理相关的各种内核缓存proc_caches_init

void __init proc_caches_init(void)
{sighand_cachep = kmem_cache_create("sighand_cache",sizeof(struct sighand_struct), 0,SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);signal_cachep = kmem_cache_create("signal_cache",sizeof(struct signal_struct), 0,SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);files_cachep = kmem_cache_create("files_cache",sizeof(struct files_struct), 0,SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);fs_cachep = kmem_cache_create("fs_cache",sizeof(struct fs_struct), 0,SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);vm_area_cachep = kmem_cache_create("vm_area_struct",sizeof(struct vm_area_struct), 0,SLAB_PANIC, NULL, NULL);mm_cachep = kmem_cache_create("mm_struct",sizeof(struct mm_struct), 0,SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
}

函数功能概述

proc_caches_init 函数用于初始化进程管理相关的各种内核缓存(slab cache),这些缓存用于高效分配进程相关的数据结构

代码详细解释

第一部分:信号处理相关缓存初始化

        sighand_cachep = kmem_cache_create("sighand_cache",sizeof(struct sighand_struct), 0,SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
  • 信号处理结构缓存:创建用于分配 sighand_struct 的 slab 缓存
  • 数据结构sighand_struct 管理进程的信号处理程序(信号处理器函数指针数组)
  • 标志SLAB_HWCACHE_ALIGN 确保缓存行对齐,提高缓存性能
  • 大小sizeof(struct sighand_struct) 根据架构不同通常为几百字节
        signal_cachep = kmem_cache_create("signal_cache",sizeof(struct signal_struct), 0,SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
  • 信号状态结构缓存:创建用于分配 signal_struct 的 slab 缓存
  • 数据结构signal_struct 包含进程的信号状态信息(待处理信号、信号阻塞掩码等)
  • sighand_struct 的区别
    • sighand_struct:信号处理行为(怎么做)
    • signal_struct:信号状态信息(有什么信号)

第二部分:文件系统相关缓存初始化

        files_cachep = kmem_cache_create("files_cache",sizeof(struct files_struct), 0,SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
  • 文件描述符表缓存:创建用于分配 files_struct 的 slab 缓存
  • 数据结构files_struct 管理进程打开的文件描述符表
  • 重要性:每个进程都有独立的文件描述符表,频繁创建和销毁
        fs_cachep = kmem_cache_create("fs_cache",sizeof(struct fs_struct), 0,SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
  • 文件系统状态缓存:创建用于分配 fs_struct 的 slab 缓存
  • 数据结构fs_struct 包含进程的文件系统相关信息(根目录、当前工作目录等)

第三部分:内存管理相关缓存初始化

        vm_area_cachep = kmem_cache_create("vm_area_struct",sizeof(struct vm_area_struct), 0,SLAB_PANIC, NULL, NULL);
  • 虚拟内存区域缓存:创建用于分配 vm_area_struct 的 slab 缓存
  • 数据结构vm_area_struct 描述进程地址空间的一个虚拟内存区域
  • 特点:没有使用 SLAB_HWCACHE_ALIGN,因为 VMA 访问模式对缓存不敏感
  • 使用频率:非常高频,进程可能有数十到数百个 VMA
        mm_cachep = kmem_cache_create("mm_struct",sizeof(struct mm_struct), 0,SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
  • 内存描述符缓存:创建用于分配 mm_struct 的 slab 缓存
  • 数据结构mm_struct 是进程内存管理的核心结构,包含所有内存区域信息
  • 重要性:每个进程都有一个 mm_struct(内核线程除外)

关键参数说明

SLAB 标志位

  • SLAB_HWCACHE_ALIGN:确保对象在缓存行边界对齐,减少伪共享
  • SLAB_PANIC:如果缓存创建失败,直接内核崩溃(因为这些缓存是系统运行必需的)

初始化缓冲区头buffer_init

void __init buffer_init(void)
{int nrpages;bh_cachep = kmem_cache_create("buffer_head",sizeof(struct buffer_head), 0,SLAB_PANIC, init_buffer_head, NULL);/** Limit the bh occupancy to 10% of ZONE_NORMAL*/nrpages = (nr_free_buffer_pages() * 10) / 100;max_buffer_heads = nrpages * (PAGE_SIZE / sizeof(struct buffer_head));hotcpu_notifier(buffer_cpu_notify, 0);
}

函数功能概述

buffer_init 函数用于初始化缓冲区头(buffer_head)缓存系统,这是 Linux 块设备 I/O 子系统的重要组成部分,用于管理页缓存和块设备之间的数据传递

代码详细解释

第一部分:缓冲区头缓存创建

        bh_cachep = kmem_cache_create("buffer_head",sizeof(struct buffer_head), 0,SLAB_PANIC, init_buffer_head, NULL);
  • 缓存名称"buffer_head" - 明确标识这是缓冲区头对象的缓存
  • 对象大小sizeof(struct buffer_head)
  • 对齐参数0 - 使用默认对齐方式
  • 标志SLAB_PANIC - 如果创建失败则系统崩溃,因为这是关键基础设施
  • 构造函数init_buffer_head - 重要的初始化函数(后面详细解释)
  • 析构函数NULL - 不需要特殊的析构处理

第二部分:缓冲区头数量限制计算

        /** Limit the bh occupancy to 10% of ZONE_NORMAL*/nrpages = (nr_free_buffer_pages() * 10) / 100;max_buffer_heads = nrpages * (PAGE_SIZE / sizeof(struct buffer_head));
  • 限制缓冲区头占用 ZONE_NORMAL 区域的 10%
  • ZONE_NORMAL 是内核直接映射的物理内存区域

计算过程:

  1. nr_free_buffer_pages() - 获取可用的缓冲区页数

    • 这个函数返回 ZONE_NORMAL 中可用于缓冲区缓存的内存页数
  2. (nr_free_buffer_pages() * 10) / 100 - 计算 10% 的可用页数

    • 这是系统为缓冲区头分配预留的内存页数上限
  3. PAGE_SIZE / sizeof(struct buffer_head) - 计算每页可以存放的缓冲区头数量

  4. max_buffer_heads = nrpages * (PAGE_SIZE / sizeof(struct buffer_head))

    • 最终计算出系统允许的最大缓冲区头数量

第三部分:CPU热插拔通知器注册

        hotcpu_notifier(buffer_cpu_notify, 0);
  • hotcpu_notifier - 注册一个CPU热插拔通知回调函数
  • buffer_cpu_notify - 当CPU状态变化时被调用的函数
  • 优先级0 - 标准优先级

创建新的 buffer_head 对象时进行初始化init_buffer_head

static void
init_buffer_head(void *data, kmem_cache_t *cachep, unsigned long flags)
{if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==SLAB_CTOR_CONSTRUCTOR) {struct buffer_head * bh = (struct buffer_head *)data;memset(bh, 0, sizeof(*bh));INIT_LIST_HEAD(&bh->b_assoc_buffers);}
}

函数功能概述

init_buffer_head 是 buffer_head 对象的 slab 构造函数,用于在 slab 分配器创建新的 buffer_head 对象时进行初始化

代码详细解释

第一部分:函数签名和参数

static void
init_buffer_head(void *data, kmem_cache_t *cachep, unsigned long flags)
  • static:函数只在当前文件内可见
  • void:没有返回值
  • 参数说明
    • void *data:指向要初始化的 slab 对象的指针(这里是 buffer_head)
    • kmem_cache_t *cachep:指向所属 slab 缓存的指针
    • unsigned long flags:构造标志位,控制初始化行为

第二部分:条件检查

        if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==SLAB_CTOR_CONSTRUCTOR) {
  • 位掩码操作flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)
    • SLAB_CTOR_VERIFY:验证模式标志
    • SLAB_CTOR_CONSTRUCTOR:构造函数模式标志
  • 条件判断:检查是否处于纯构造函数模式(不是验证模式)
  • 为什么需要这个检查
    • slab 分配器可能在多种场景下调用这个函数
    • 只有在真正创建新对象时才需要初始化
    • 验证模式只需要检查对象状态,不需要重新初始化

第三部分:类型转换和内存清零

                struct buffer_head * bh = (struct buffer_head *)data;memset(bh, 0, sizeof(*bh));
  • 类型转换(struct buffer_head *)data

    • 将泛型 void 指针转换为具体的 buffer_head 指针
    • 这样可以直接访问 buffer_head 的各个字段
  • 内存清零memset(bh, 0, sizeof(*bh))

    • 将整个 buffer_head 结构体所有字节设置为 0
    • sizeof(*bh) 获取 buffer_head 的实际大小
    • 优点:一次性清除所有字段,包括未来可能新增的字段

第四部分:链表初始化

                INIT_LIST_HEAD(&bh->b_assoc_buffers);}
  • INIT_LIST_HEAD:Linux 内核的链表初始化宏
  • b_assoc_buffers:buffer_head 的关联缓冲区链表
  • 链表作用:用于将相关的 buffer_head 连接在一起

CPU 热插拔时缓冲区头的清理机制buffer_cpu_notify

static int buffer_cpu_notify(struct notifier_block *self,unsigned long action, void *hcpu)
{if (action == CPU_DEAD)buffer_exit_cpu((unsigned long)hcpu);return NOTIFY_OK;
}
static void buffer_exit_cpu(int cpu)
{int i;struct bh_lru *b = &per_cpu(bh_lrus, cpu);for (i = 0; i < BH_LRU_SIZE; i++) {brelse(b->bhs[i]);b->bhs[i] = NULL;}
}
static inline void brelse(struct buffer_head *bh)
{if (bh)__brelse(bh);
}
void __brelse(struct buffer_head * buf)
{if (atomic_read(&buf->b_count)) {put_bh(buf);return;}printk(KERN_ERR "VFS: brelse: Trying to free free buffer\n");WARN_ON(1);
}
static inline void put_bh(struct buffer_head *bh)
{smp_mb__before_atomic_dec();atomic_dec(&bh->b_count);
}

整体功能概述

这些函数组成了 CPU 热插拔时缓冲区头(buffer_head)的清理机制,确保当 CPU 离线时,该 CPU 的缓冲区缓存被正确清理

代码详细解释

第一部分:CPU 通知器回调函数

static int buffer_cpu_notify(struct notifier_block *self,unsigned long action, void *hcpu)
{if (action == CPU_DEAD)buffer_exit_cpu((unsigned long)hcpu);return NOTIFY_OK;
}
  • 参数说明

    • self:指向通知器块本身的指针
    • action:CPU 状态变化动作(CPU_UP_PREPARE, CPU_STARTING, CPU_DEAD 等)
    • hcpu:受影响的 CPU 编号(void* 类型,需要转换)
  • 条件判断if (action == CPU_DEAD)

    • 只在 CPU 离线时执行清理操作
    • 其他状态(如 CPU 上线)不需要特殊处理
  • 函数调用buffer_exit_cpu((unsigned long)hcpu)

    • hcpu 从 void* 转换为 unsigned long(CPU 编号)
    • 调用具体的清理函数
  • 返回值return NOTIFY_OK;

    • 表示这个通知已处理完成
    • 允许其他通知器继续处理同一事件

第二部分:CPU 缓冲区清理函数

static void buffer_exit_cpu(int cpu)
{int i;struct bh_lru *b = &per_cpu(bh_lrus, cpu);for (i = 0; i < BH_LRU_SIZE; i++) {brelse(b->bhs[i]);b->bhs[i] = NULL;}
}
  • 参数int cpu - 要清理的 CPU 编号

  • 局部变量

    • int i:循环计数器
    • struct bh_lru *b:指向该 CPU 的缓冲区 LRU 缓存
  • per_cpu 变量&per_cpu(bh_lrus, cpu)

    • bh_lrus 是 per-CPU 变量,每个 CPU 有自己的缓冲区 LRU 缓存
    • 获取指定 CPU 的 bh_lru 结构指针
  • 循环清理for (i = 0; i < BH_LRU_SIZE; i++)

    • BH_LRU_SIZE 通常是 4 或 8,定义每个 CPU 缓存的缓冲区数量
    • 遍历 LRU 数组中的所有缓冲区
  • 清理操作

    • brelse(b->bhs[i]):释放缓冲区引用
    • b->bhs[i] = NULL:将槽位置空,防止悬空指针

第三部分:缓冲区释放函数链

static inline void brelse(struct buffer_head *bh)
{if (bh)__brelse(bh);
}
  • static inline:内联函数,减少函数调用开销
  • 空指针检查if (bh)
    • 确保不会对空指针进行操作
  • 实际调用__brelse(bh) - 调用实际的释放函数

第四部分:缓冲区释放核心逻辑

void __brelse(struct buffer_head * buf)
{if (atomic_read(&buf->b_count)) {put_bh(buf);return;}printk(KERN_ERR "VFS: brelse: Trying to free free buffer\n");WARN_ON(1);
}
  • 引用计数检查if (atomic_read(&buf->b_count))

    • b_count 是缓冲区的引用计数
    • atomic_read 原子性地读取计数值
    • 如果计数 > 0,说明缓冲区正在被使用
  • 正常释放路径

    • put_bh(buf):减少引用计数
    • return:正常返回
  • 错误检测

    • 如果引用计数已经是 0,说明重复释放
    • printk(KERN_ERR ...):输出错误日志到内核日志
    • WARN_ON(1):触发内核警告,可能生成堆栈跟踪

第五部分:原子引用计数减少

static inline void put_bh(struct buffer_head *bh)
{smp_mb__before_atomic_dec();atomic_dec(&bh->b_count);
}
  • 内存屏障smp_mb__before_atomic_dec()

    • 在多核系统中确保内存操作的顺序性
    • 防止指令重排序导致的数据不一致
  • 原子操作atomic_dec(&bh->b_count)

    • 原子性地将引用计数减 1
http://www.dtcms.com/a/503853.html

相关文章:

  • 学校网站的作用和意义珠海仿站定制模板建站
  • 云原生网络基础:IP、端口与网关实战
  • 郑州网站优化平台做网站需要营业执照吗
  • 企业app商城开发网站建设wordpress userpro
  • C++与C#使用GDI+创建PNG并旋转文本的对比实现
  • 动图在线制作网站烟台广告公司网站建设
  • react.js做的网站学室内装修设计
  • 如何处理大数处理技巧(vpa函数
  • 设计模式举例
  • 【Spring Security】安全过滤链
  • 小区媒体网站建设wordpress简易主题
  • 手机网站经典案例wordpress负载均衡上传附件
  • 银川网站建站中企动力做的网站价格区间
  • 兴义网站开发杭州赛虎网站建设
  • 数据库基础概念体系梳理
  • Kotlin Flow 的使用
  • 网站如何做seo上海网站推广方法
  • Qwen2.5技术报告解读:Qwen2.5 Technical Report
  • 操作系统:进程同步问题(一)
  • Linux---终端 I/O 控制接口开发<termios.h>终端输入输出系统
  • Linux 之 【Linux权限】
  • 网站建设策划书范文案例重庆百度关键词推广
  • 健身器材 网站模版wordpress用户系统
  • 两款实用工具分享:下载与网速测试的轻量级解决方案
  • DVWA靶场实战:Web四大经典漏洞攻防全解析
  • 海外网站测速本地网站建设开发信息大全
  • PowerCat命令操作:PowerShell版的Netcat在渗透测试中的应用
  • 域名注册最好的网站南京设计公司前十名
  • 快速定位源码问题:SourceMap的生成/使用/文件格式与历史
  • 湖南移动官网网站建设wordpress 菜单 分隔