鸿蒙内核源码分析(位图管理篇) | 谁能一分钱分两半用 | 百篇博客分析OpenHarmony源码 | v19.03
百篇博客系列篇.本篇为:
先看四个宏定义,进程和线程(线程就是任务)最高和最低优先级定义,[0,31]区间,即32级,优先级用于调度,CPU根据这个来决定先运行哪个进程和任务。
#define OS_PROCESS_PRIORITY_HIGHEST 0 //进程最高优先级
#define OS_PROCESS_PRIORITY_LOWEST 31 //进程最低优先级
#define OS_TASK_PRIORITY_HIGHEST 0 //任务最高优先级,软时钟任务就是最高级任务,见于 OsSwtmrTaskCreate
#define OS_TASK_PRIORITY_LOWEST 31 //任务最低优先级
为何进程和线程都是32个优先级?
回答这个问题之前,先回答另一个问题,为什么人类几乎所有的文明都是用十进制的计数方式。答案掰手指就知道了,因为人有十根手指头。玛雅人的二十进制那是把脚指头算上了,但其实也算是十进制的表示。
这是否说明一个问题,认知受环境的影响,方向是怎么简单/方便怎么来。这也可以解释为什么人类语言发音包括各种方言对妈妈这个词都很类似,因为婴儿说mama是最容易的。 注意认识这点很重要!
而计算机的世界是二进制的,是是非非,清清楚楚,特别的简单,二进制已经最简单了,到底啦,不可能有更简单的了。还记得双向链表篇中说过的吗,因为简单所以才不简单啊,大道若简,计算机就靠着这01码,表述万千世界。
但人类的大脑不擅长存储,二进制太长了数到100就撑爆了大脑,记不住,为了记忆和运算方便,编程常用靠近10进制的 16进制来表示 ,0x9527ABCD 看着比 0011000111100101010100111舒服多了。
应用开发和内核开发有哪些区别?
区别还是很大的,这里只说一点,就是对位的控制能力,内核会出现大量的按位运算(&,|,~,^) , 一个变量的不同位表达不同的含义,但这在应用程序员那是很少看到的,他们用的更多的是逻辑运算(&&,||,!)
#define OS_TASK_STATUS_INIT 0x0001U //初始化状态
#define OS_TASK_STATUS_READY 0x0002U //就绪状态的任务都将插入就绪队列
#define OS_TASK_STATUS_RUNNING 0x0004U //运行状态
#define OS_TASK_STATUS_SUSPEND 0x0008U //挂起状态
#define OS_TASK_STATUS_PEND 0x0010U //阻塞状态
这是任务各种状态(注者后续将比如成贴标签)表述,将它们还原成二进制就是:
0000000000000001 = 0x0001U
0000000000000010 = 0x0002U
0000000000000100 = 0x0004U
0000000000001000 = 0x0008U
0000000000010000 = 0x0010U
发现二进制这边的区别没有,用每一位来表示一种不同的状态,1表示是,0表示不是。
这样的好处有两点:
1.可以多种标签同时存在 比如 0x07 = 0b00000111,对应以上就是任务有三个标签(初始,就绪,和运行),进程和线程在运行期间是允许多种标签同时存在的。
2.节省了空间,一个变量就搞定了,如果是应用程序员要实现这三个标签同时存在,习惯上要定义三个变量的,因为你的排他性颗粒度是一个变量而不是一个位。
而对位的管理/运算就需要有个专门的管理器:位图管理器 (见源码 los_bitmap.c )
什么是位图管理器?
直接上部分代码,代码关键地方都加了中文注释,简单说就是对位的各种操作,比如如何在某个位上设1?如何找到最高位为1的是哪个位置?这些函数都是有大用途的。
//对状态字的某一标志位进行置1操作
VOID LOS_BitmapSet(UINT32 *bitmap, UINT16 pos)
{
if (bitmap == NULL) {
return;
}
*bitmap |= 1U << (pos & OS_BITMAP_MASK);//在对应位上置1
}
//对状态字的某一标志位进行清0操作
VOID LOS_BitmapClr(UINT32 *bitmap, UINT16 pos)
{
if (bitmap == NULL) {
return;
}
*bitmap &= ~(1U << (pos & OS_BITMAP_MASK));//在对应位上置0
}
/********************************************************
杂项算术指令
CLZ 用于计算操作数最高端0的个数,这条指令主要用于一下两个场合
计算操作数规范化(使其最高位为1)时需要左移的位数
确定一个优先级掩码中最高优先级
********************************************************/
//获取状态字中为1的最高位 例如: 00110110 返回 5
UINT16 LOS_HighBitGet(UINT32 bitmap)
{
if (bitmap == 0) {
return LOS_INVALID_BIT_INDEX;
}
return (OS_BITMAP_MASK - CLZ(bitmap));
}
//获取状态字中为1的最低位, 例如: 00110110 返回 2
UINT16 LOS_LowBitGet(UINT32 bitmap)
{
if (bitmap == 0) {
return LOS_INVALID_BIT_INDEX;
}
return CTZ(bitmap);//
}
位图在哪些地方应用?
内核很多模块在使用位图,这里只说进程和线程模块,还记得开始的问题吗,为何进程和线程都是32个优先级?因为他们的优先级是由位图管理的,管理一个UINT32的变量,所以是32级,一个位一个级别,最高位优先级最低。
UINT32 priBitMap; /**< BitMap for recording the change of task priority, //任务在执行过程中优先级会经常变化,这个变量用来记录所有曾经变化
the priority can not be greater than 31 */ //过的优先级,例如 ..01001011 曾经有过 0,1,3,6 优先级
这是任务控制块中对调度优先级位图的定义,注意一个任务的优先级在运行过程中可不是一成不变的,内核会根据运行情况而改变它的,这个变量是用来保存这个任务曾经有过的所有优先级历史记录。
比如 任务A的优先级位图是 00000001001011 ,可以看出它曾经有过四个调度等级记录,那如果想知道优先级最低的记录是多少时怎么办呢?
诶,上面的位图管理器函数 UINT16 LOS_HighBitGet(UINT32 bitmap) 就很有用啦 ,它返回的是1在高位出现的位置,可以数一下是 6
因为任务的优先级0最大,所以最终的意思就是A任务曾经有过的最低优先级是6
一定要理解位图的操作,内核中大量存在这类代码,尤其到了汇编层,对寄存器的操作大量的出现。
比如以下这段汇编代码。
MSR CPSR_c, #(CPSR_INT_DISABLE | CPSR_SVC_MODE) @禁止中断并切到管理模式
LDRH R1, [R0, #4] @将存储器地址为R0+4 的低16位数据读入寄存器R1,并将R1的高16 位清零
ORR R1, #OS_TASK_STATUS_RUNNING @或指令 R1=R1|OS_TASK_STATUS_RUNNING
STRH R1, [R0, #4] @将寄存器R1中的低16位写入以R0+4为地址的存储器中
编程实例
对数据实现位操作,本实例实现如下功能:
- 某一标志位置1。
- 获取标志位为1的最高bit位。
- 某一标志位清0。
- 获取标志位为1的最低bit位。
#include "los_bitmap.h"
#include "los_printf.h"
static UINT32 Bit_Sample(VOID)
{
UINT32 flag = 0x10101010;
UINT16 pos;
dprintf("\nBitmap Sample!\n");
dprintf("The flag is 0x%8x\n", flag);
pos = 8;
LOS_BitmapSet(&flag, pos);
dprintf("LOS_BitmapSet:\t pos : %d, the flag is 0x%0+8x\n", pos, flag);
pos = LOS_HighBitGet(flag);
dprintf("LOS_HighBitGet:\t The highest one bit is %d, the flag is 0x%0+8x\n", pos, flag);
LOS_BitmapClr(&flag, pos);
dprintf("LOS_BitmapClr:\t pos : %d, the flag is 0x%0+8x\n", pos, flag);
pos = LOS_LowBitGet(flag);
dprintf("LOS_LowBitGet:\t The lowest one bit is %d, the flag is 0x%0+8x\n\n", pos, flag);
return LOS_OK;
}
结果验证
Bitmap Sample!
The flag is 0x10101010
LOS_BitmapSet: pos : 8, the flag is 0x10101110
LOS_HighBitGet:The highest one bit is 28, the flag is 0x10101110
LOS_BitmapClr: pos : 28, the flag is 0x00101110
LOS_LowBitGet: The lowest one bit is 4, the flag is 0x00101110
鸿蒙内核源码分析.总目录
v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 百篇博客分析 | 51.c.h .o
百万汉字注解.百篇博客分析
百万汉字注解 >> 精读鸿蒙源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee| github| csdn| coding >
百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点定期更新中< 51cto| csdn| harmony| osc >
关注不迷路.代码即人生
QQ群:790015635 | 入群密码: 666
原创不易,欢迎转载,但请注明出处.
鸿蒙内核源码分析(位图管理篇) | 谁能一分钱分两半用 | 百篇博客分析OpenHarmony源码 | v19.03的更多相关文章
- 鸿蒙内核源码分析(fork篇) | 一次调用,两次返回 | 百篇博客分析OpenHarmony源码 | v45.03
百篇博客系列篇.本篇为: v45.xx 鸿蒙内核源码分析(Fork篇) | 一次调用,两次返回 | 51.c.h .o 进程管理相关篇为: v02.xx 鸿蒙内核源码分析(进程管理篇) | 谁在管理内 ...
- 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念 | 百篇博客分析OpenHarmony源码 | v25.01
百篇博客系列篇.本篇为: v25.xx 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...
- 鸿蒙源码分析系列(总目录) | 百万汉字注解 百篇博客分析 | 深入挖透OpenHarmony源码 | v8.23
百篇博客系列篇.本篇为: v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 百篇博客分析 | 51.c.h .o 百篇博客.往期回顾 在给OpenHarmony内核源码加注过程中,整理出以下 ...
- 鸿蒙内核源码分析(任务管理篇) | 任务池是如何管理的 | 百篇博客分析OpenHarmony源码 | v5.05
百篇博客系列篇.本篇为: v05.xx 鸿蒙内核源码分析(任务管理篇) | 任务池是如何管理的 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁 ...
- 鸿蒙内核源码分析(进程管理篇) | 谁在管理内核资源 | 百篇博客分析OpenHarmonyOS | v2.07
百篇博客系列篇.本篇为: v02.xx 鸿蒙内核源码分析(进程管理篇) | 谁在管理内核资源 | 51.c.h .o 进程管理相关篇为: v02.xx 鸿蒙内核源码分析(进程管理篇) | 谁在管理内核 ...
- 鸿蒙内核源码分析(中断管理篇) | 江湖从此不再怕中断 | 百篇博客分析OpenHarmony源码 | v44.02
百篇博客系列篇.本篇为: v44.xx 鸿蒙内核源码分析(中断管理篇) | 江湖从此不再怕中断 | 51.c.h .o 硬件架构相关篇为: v22.xx 鸿蒙内核源码分析(汇编基础篇) | CPU在哪 ...
- 鸿蒙内核源码分析(时间管理篇) | 谁是内核基本时间单位 | 百篇博客分析OpenHarmony源码 | v35.02
百篇博客系列篇.本篇为: v35.xx 鸿蒙内核源码分析(时间管理篇) | 谁是内核基本时间单位 | 51.c.h .o 本篇说清楚时间概念 读本篇之前建议先读鸿蒙内核源码分析(总目录)其他篇. 时间 ...
- 鸿蒙内核源码分析(内存管理篇) | 虚拟内存全景图是怎样的 | 百篇博客分析OpenHarmony源码 | v12.04
百篇博客系列篇.本篇为: v12.xx 鸿蒙内核源码分析(内存管理篇) | 虚拟内存全景图是怎样的 | 51.c.h .o 内存管理相关篇为: v11.xx 鸿蒙内核源码分析(内存分配篇) | 内存有 ...
- 鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 | 百篇博客分析OpenHarmony源码 | v70.01
百篇博客系列篇.本篇为: v70.xx 鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...
随机推荐
- Docker创建seafile搭建私有云
docker-compose.yml version: '2.0' services: db: image: mariadb:10.1 container_name: seafile-mysql en ...
- ATM取款机优化需求的用例设计
案例设计需求 有一个ATM取款系统,现对于取款功能进行了如何需求变更:碑只能取面额是100元(如取500,输出5张100元),现在功能修改为,可以取面额是10元.50元和100元的,其余功能不变,用户 ...
- uniapp封装小程序雷达图组件实现
效果图: view <canvas id="radar-canvas" class="radar-canvas" type="2d"& ...
- explorer.exe
explorer.exe是Windows程序管理器或者文件资源管理器, 它用于管理Windows图形壳,包括桌面和文件管理,删除该程序会导致Windows图形界面无法使用. 终止: taskkill ...
- ArcGIS图层添加字段出现:“定义了过多字段”
首先,我图层数据格式为mdb,也就是Access数据库 Access一个表最大支持255个字段,可是我的才添加第一个字段就出现"定义了过多字段"的错误 打开ArcMap添加字段也是 ...
- (2)hadoop之-----配置免密码登录
ssh-keygen -t rsa 然后一路回车 在家目录下会生成 .ssh 目录 ls -la 查看 进入 .ssh cd .ssh cp ~/.s ...
- 关于oracle样例数据库emp、dept、salgrade的mysql脚本复杂查询分析
大家可以自行网上找资源(网上资源比较多,不建议下载我的),也可以在我这里下载: 1.取得每个部门最高薪水的人员名称:正确 一共有4个单位,要进行左外连接 其中一个单位没得员工 SELECT dep ...
- Faiss使用多线程出现的性能问题
Faiss使用多线程出现的性能问题 faiss在增加CPU的情况下,反而出现效率低下的问题. 从理论上看,作为一个CPU/GPU计算型的应用,更多的核意味着更大的计算吞吐能力,性能只会越来越好才是. ...
- vue 引用省市区三级联动(element-ui Cascader)
npm 下载 npm install element-china-area-data -S main.js import {provinceAndCityData,regionData,provinc ...
- Object-源码
Object的结构 类构造器 一个类必须要有一个构造器的存在 , Object类源码中,是看不到构造器的,系统会自动添加一个无参构造器. Object obj = new Object(): equa ...