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

Linux中初始化空循环次数和pid位图初始化

校准处理器速度calibrate_delay

void __devinit calibrate_delay(void)
{unsigned long ticks, loopbit;int lps_precision = LPS_PREC;if (preset_lpj) {loops_per_jiffy = preset_lpj;printk("Calibrating delay loop (skipped)... ""%lu.%02lu BogoMIPS preset\n",loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ)) % 100);} else {loops_per_jiffy = (1<<12);printk(KERN_DEBUG "Calibrating delay loop... ");while ((loops_per_jiffy <<= 1) != 0) {/* wait for "start of" clock tick */ticks = jiffies;while (ticks == jiffies)/* nothing */;/* Go .. */ticks = jiffies;__delay(loops_per_jiffy);ticks = jiffies - ticks;if (ticks)break;}/** Do a binary approximation to get loops_per_jiffy set to* equal one clock (up to lps_precision bits)*/loops_per_jiffy >>= 1;loopbit = loops_per_jiffy;while (lps_precision-- && (loopbit >>= 1)) {loops_per_jiffy |= loopbit;ticks = jiffies;while (ticks == jiffies)/* nothing */;ticks = jiffies;__delay(loops_per_jiffy);if (jiffies != ticks)   /* longer than 1 tick */loops_per_jiffy &= ~loopbit;}/* Round the value and print it */printk("%lu.%02lu BogoMIPS (lpj=%lu)\n",loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ)) % 100,loops_per_jiffy);}}

函数功能概述

这个函数用于校准处理器速度,计算 loops_per_jiffy(每个时钟节拍可以执行的循环次数),从而确定系统的 BogoMIPS 值。BogoMIPS 是一个粗略的处理器速度指标,BogoMIPS = Bogus(虚假的/伪造的) + MIPS(每秒百万条指令),表示处理器在一秒内可以执行空循环的次数(以百万为单位)

代码详细解释

第一部分:变量声明和预设值检查

void __devinit calibrate_delay(void)
{unsigned long ticks, loopbit;int lps_precision = LPS_PREC;if (preset_lpj) {loops_per_jiffy = preset_lpj;printk("Calibrating delay loop (skipped)... ""%lu.%02lu BogoMIPS preset\n",loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ)) % 100);}
  • __devinit 表示这个函数在设备初始化期间使用,初始化完成后可能被释放
  • 声明变量:ticks 用于时间测量,loopbit 用于二分查找,lps_precision 设置校准精度
  • 如果 preset_lpj(预设的 loops_per_jiffy)不为0,直接使用预设值
  • 计算并打印 BogoMIPS 值:loops_per_jiffy/(500000/HZ) 计算整数部分,(loops_per_jiffy/(5000/HZ)) % 100 计算小数部分

第二部分:粗略校准 - 寻找数量级

    } else {loops_per_jiffy = (1<<12);printk(KERN_DEBUG "Calibrating delay loop... ");while ((loops_per_jiffy <<= 1) != 0) {/* wait for "start of" clock tick */ticks = jiffies;while (ticks == jiffies)/* nothing */;/* Go .. */ticks = jiffies;__delay(loops_per_jiffy);ticks = jiffies - ticks;if (ticks)break;}
  • 如果没有预设值,从 4096(1<<12)开始
  • 进入循环,每次将 loops_per_jiffy 左移一位(加倍)
  • while (ticks == jiffies) 等待下一个时钟节拍开始
  • 执行 __delay(loops_per_jiffy) 运行指定次数的空循环
  • 计算实际消耗的时间节拍数
  • 如果消耗了时间(ticks != 0),说明循环次数足够多,跳出循环

第三部分:精确校准 - 二分查找

        loops_per_jiffy >>= 1;loopbit = loops_per_jiffy;while (lps_precision-- && (loopbit >>= 1)) {loops_per_jiffy |= loopbit;ticks = jiffies;while (ticks == jiffies)/* nothing */;ticks = jiffies;__delay(loops_per_jiffy);if (jiffies != ticks)   /* longer than 1 tick */loops_per_jiffy &= ~loopbit;}
  • loops_per_jiffy >>= 1 回退到上一次成功的值
  • loopbit = loops_per_jiffy 初始化二分查找的步长
  • 循环 lps_precision 次进行精确校准
  • loops_per_jiffy |= loopbit 尝试增加当前精度位
  • 同样等待时钟节拍开始,然后执行延迟
  • 如果执行时间超过1个节拍(jiffies != ticks),说明循环次数过多,清除该精度位

第四部分:结果输出

        /* Round the value and print it */printk("%lu.%02lu BogoMIPS (lpj=%lu)\n",loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ)) % 100,loops_per_jiffy);}
}
  • 打印最终的校准结果,格式为:“整数.小数 BogoMIPS (lpj=实际循环次数)”

关键概念说明

  • jiffy: 系统时钟节拍,通常是 1ms、4ms 或 10ms,取决于 HZ 值
  • loops_per_jiffy: 在一个 jiffy 内可以执行的空循环次数
  • BogoMIPS: “Bogus MIPS” - 一个近似的处理器速度指标
  • 二分查找: 用于精确确定最大的不超时的循环次数

这个函数通过动态测试确定了处理器执行空循环的速度,为系统中的时间延迟函数提供了准确的基准

初始化PID位图pidmap_init

void __init pidmap_init(void)
{int i;pidmap_array->page = (void *)get_zeroed_page(GFP_KERNEL);set_bit(0, pidmap_array->page);atomic_dec(&pidmap_array->nr_free);/** Allocate PID 0, and hash it via all PID types:*/for (i = 0; i < PIDTYPE_MAX; i++)attach_pid(current, i, 0);
}

函数功能概述

这个函数用于初始化进程ID(PID)位图,并设置PID 0为已使用状态。PID 0通常分配给内核的空闲进程(swapper进程)

代码详细解释

第一部分:变量声明和基础初始化

void __init pidmap_init(void)
{int i;pidmap_array->page = (void *)get_zeroed_page(GFP_KERNEL);
  • __init 表示这个函数在系统初始化期间调用,初始化完成后内存会被释放
  • 声明循环变量 i,用于遍历所有PID类型
  • get_zeroed_page(GFP_KERNEL) 申请一个物理内存页并将其内容清零
    • GFP_KERNEL 是内存分配标志,表示内核正常优先级分配
    • 返回的是页的虚拟地址
  • 将获取的页赋值给 pidmap_array->page,这个位图用于跟踪PID的分配状态

第二部分:保留PID 0

        set_bit(0, pidmap_array->page);atomic_dec(&pidmap_array->nr_free);
  • set_bit(0, pidmap_array->page) 将位图的第0位设置为1
    • 在位图中,1表示已使用,0表示空闲
    • PID 0被保留,不能被普通进程使用
  • atomic_dec(&pidmap_array->nr_free) 原子操作减少空闲PID计数器
    • atomic_dec 保证在多处理器环境下的原子性
    • nr_free 记录当前可用的PID数量
    • 由于PID 0被占用,空闲PID数量减1

第三部分:为所有PID类型注册PID 0

        /** Allocate PID 0, and hash it via all PID types:*/for (i = 0; i < PIDTYPE_MAX; i++)attach_pid(current, i, 0);
}
  • 分配PID 0,并通过所有PID类型进行哈希处理
  • for (i = 0; i < PIDTYPE_MAX; i++) 遍历所有PID类型
    • PIDTYPE_MAX 是PID类型的最大值,通常包括:
      • PIDTYPE_PID:进程ID
      • PIDTYPE_TGID:线程组ID
      • PIDTYPE_PGID:进程组ID
      • PIDTYPE_SID:会话ID
  • attach_pid(current, i, 0) 为当前进程附加PID 0到每种PID类型的哈希表中
    • current 指向当前正在执行的进程(内核的swapper进程)
    • i 是PID类型
    • 0 是PID值

关键数据结构

PID位图结构

struct pidmap {atomic_t nr_free;        // 空闲PID数量void *page;              // 位图页面
};

PID类型枚举

enum pid_type {PIDTYPE_PID,      // 进程IDPIDTYPE_TGID,     // 线程组IDPIDTYPE_PGID,     // 进程组IDPIDTYPE_SID,      // 会话IDPIDTYPE_MAX       // PID类型数量
};

内存布局示意图

pidmap_array->page 位图内存页:
+---+---+---+---+---+---+
| 1 | 0 | 0 | 0 | 0 | ... |  (4096字节,32768个PID)
+---+---+---+---+---+---+^   ^   ^   ^   ^|   |   |   |   |
PID0 PID1 PID2 PID3 PID4...
  • 第0位:设置为1(PID 0已使用)
  • 其他位:初始为0(空闲状态)

将进程关联到指定的PID attach_pid

int fastcall attach_pid(task_t *task, enum pid_type type, int nr)
{struct pid *pid, *task_pid;task_pid = &task->pids[type];pid = find_pid(type, nr);if (pid == NULL) {hlist_add_head(&task_pid->pid_chain,&pid_hash[type][pid_hashfn(nr)]);INIT_LIST_HEAD(&task_pid->pid_list);} else {INIT_HLIST_NODE(&task_pid->pid_chain);list_add_tail(&task_pid->pid_list, &pid->pid_list);}task_pid->nr = nr;return 0;
}

函数功能概述

这个函数负责将进程任务关联到指定的PID编号和类型,管理Linux内核中复杂的PID组织结构。它处理PID哈希表和进程链表的维护,支持多线程共享同一PID的场景

代码逐行详细解释

第一部分:函数声明和变量定义

int fastcall attach_pid(task_t *task, enum pid_type type, int nr)
{struct pid *pid, *task_pid;
  • fastcall:这是一个函数调用约定修饰符,指示编译器使用寄存器来传递参数,而不是通过堆栈,这样可以提高函数调用速度。在x86架构中,前两个参数通常通过ECX和EDX寄存器传递

  • 参数分析

    • task_t *task:指向进程任务描述符的指针,即需要关联PID的进程
    • enum pid_type type:PID类型枚举,包括:
      • PIDTYPE_PID - 进程ID
      • PIDTYPE_TGID - 线程组ID
      • PIDTYPE_PGID - 进程组ID
      • PIDTYPE_SID - 会话ID
    • int nr:具体的PID数值
  • 局部变量

    • struct pid *pid:用于指向在全局哈希表中查找到的现有PID结构
    • struct pid *task_pid:指向当前任务内部的PID结构

第二部分:获取任务PID结构和查找全局PID

        task_pid = &task->pids[type];pid = find_pid(type, nr);
  • task_pid = &task->pids[type]

    • 从任务结构体中获取对应类型的PID结构指针
    • task->pids 是一个数组,每个元素对应一种PID类型
    • 例如:task->pids[PIDTYPE_PID] 是进程ID结构
    • 这个操作获取了任务内部存储PID信息的位置
  • pid = find_pid(type, nr)

    • 调用 find_pid 函数在全局PID哈希表中查找指定的PID
    • 查找过程:pid_hash[type][pid_hashfn(nr)] → 遍历哈希链表
    • 如果找到匹配的PID,返回该PID结构指针
    • 如果没找到,返回NULL

第三部分:处理新PID的情况(首次分配)

        if (pid == NULL) {hlist_add_head(&task_pid->pid_chain,&pid_hash[type][pid_hashfn(nr)]);INIT_LIST_HEAD(&task_pid->pid_list);
  • if (pid == NULL):条件判断,如果该PID在全局哈希表中不存在

  • hlist_add_head(&task_pid->pid_chain, &pid_hash[type][pid_hashfn(nr)])

    • pid_hashfn(nr):计算PID的哈希值,将PID数值映射到哈希桶索引
    • pid_hash[type][...]:二维哈希表,第一维是PID类型,第二维是哈希桶
    • hlist_add_head:将任务的pid_chain节点添加到哈希链表的头部
    • 这使该任务成为该PID在哈希表中的第一个代表
  • INIT_LIST_HEAD(&task_pid->pid_list)

    • 初始化一个空的双向链表头
    • 这个链表用于存储所有共享同一PID的任务
    • 对于新PID,当前只有这一个任务,所以初始化空链表

第四部分:处理现有PID的情况(共享PID)

        } else {INIT_HLIST_NODE(&task_pid->pid_chain);list_add_tail(&task_pid->pid_list, &pid->pid_list);}
  • else:如果该PID已经在全局哈希表中存在

  • INIT_HLIST_NODE(&task_pid->pid_chain)

    • 初始化哈希链表节点,但不将其加入任何哈希表
    • 因为该PID已经在全局哈希表中存在,不需要重复添加
    • 只是确保节点的状态正确,防止未定义行为
  • list_add_tail(&task_pid->pid_list, &pid->pid_list)

    • 将当前任务的pid_list节点添加到现有PID的进程链表尾部
    • 这实现了多个任务共享同一PID的功能
    • 例如:线程组中的所有线程共享同一个TGID

第五部分:设置PID数值并返回

        task_pid->nr = nr;return 0;
}
  • task_pid->nr = nr

    • 设置PID结构中的数值字段
    • 无论新旧PID,都需要记录具体的PID数值
    • 这个数值用于后续的PID查找和比较
  • return 0

    • 函数总是返回成功(0)
    • 因为所有错误情况都应该在调用前被处理

数据结构关系详解

PID结构定义

struct pid {int nr;                      // PID数值struct hlist_node pid_chain; // 哈希表链表节点struct list_head pid_list;   // 共享同一PID的任务链表
};

场景1:新PID创建

执行前:
全局哈希表: 空
任务PID结构: 未初始化执行过程:
1. 将任务PID结构加入哈希表: pid_hash[type][hash] → task_pid
2. 初始化空进程链表: task_pid→pid_list → [空]
3. 设置PID数值: task_pid→nr = nr执行后:
全局哈希表: pid_hash[type][hash] → task_pid (通过pid_chain连接)
任务链表: task_pid→pid_list 指向空链表头

场景2:共享现有PID

执行前:
全局哈希表: pid_hash[type][hash] → existing_pid
现有PID链表: existing_pid→pid_list → task1 → task2执行过程:
1. 初始化task_pid的pid_chain(不加入哈希表)
2. 将task_pid加入现有PID的进程链表: existing_pid→pid_list → task1 → task2 → task_pid
3. 设置PID数值: task_pid→nr = nr执行后:
全局哈希表: 不变,仍然指向existing_pid
现有PID链表: 新增task_pid在尾部
http://www.dtcms.com/a/500571.html

相关文章:

  • js网站模板下载天水有做网站的地方吗
  • 做门户网站最重要的是什么公司网站建设存在问题
  • 广元网站建设专业人员wordpress没有写权限
  • 沈阳高端网站设计中信建设有限责任公司领导班子
  • 福州最好的网站建设公司山西国人伟业网站
  • wap网站价格怎么做好网络销售
  • 用dw制作影视网站怎样做平台代理是什么工作
  • 一般的学校网站怎么做网站建设学什么语言
  • 专业微网站建设公司首选百度后台登录
  • 免费网站怎么注册.net可以做网站做游戏 博客园
  • 网站开发接入本地天地图东莞食品公司东莞网站建设
  • Linux文件处理
  • LeetCode 刷题【124. 二叉树中的最大路径和、125. 验证回文串】
  • 股票网站建设ppt素材大全免费下载
  • 国内企业网站建设装修app排行榜前5名
  • 成都金融网站建设公司排名北京网页设计公司兴田德润怎么样
  • 网站外链接自己可以怎么做的做的网站怎么上传图片
  • 网页制作中的网站维护阿里巴巴国际站跨境电商平台
  • 建设网站 请示 报告wordpress微信关注查看
  • DEM生产坡度图、坡向图、山体阴影图、地形图、等高线图原理以及如何实现
  • java.time 包详解
  • 网站发布的方法有几种临沂建设局网站质量三监督
  • 重庆网站建设哪家有域名值多少钱
  • 营销类网站 英文建站本
  • 咖啡网站开发背景苏宁网站开发人员工资
  • 沧州网站优化可以做游戏广告的网站
  • 九江专业制作网站小程序产品销售型的网站
  • 深圳公司网站设计电商网站开发流程list
  • 中国石家庄网站wordpress相册插件下载
  • 微信电影网站建设教程推广引流客源