2.2 LOS_BitmapClr()对状态字的某一标志位进行清0操作
对状态字的某一标志位进行清0操作,代码和置1操作对应,比较简单,~(1U << (pos & OS_BITMAP_MASK))
表示需要改变内容的状态字的bit
位为0,其余位为1,然后通过按位与运算设置状态字UINT32 *bitmap
的指定bit
位的内容为0。
VOID LOS_BitmapClr(UINT32 *bitmap, UINT16 pos)
{
if (bitmap == NULL) {
return;
}
*bitmap &= ~(1U << (pos & OS_BITMAP_MASK));
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
2.3 LOS_HighBitGet()获取状态字中为1的最高位
代码中CLZ(bitmap)
是宏,展开为(__builtin_clz(bitmap))
,这是编译器内置的高效位运算的库函数,clz
是count leading zeros
的缩写,就是统计二进制数值中高位区开头的全是0的数目。使用OS_BITMAP_MASK
减去该值,结果就是状态字中的1的最高位。
UINT16 LOS_HighBitGet(UINT32 bitmap)
{
if (bitmap == 0) {
return LOS_INVALID_BIT_INDEX;
}
return (OS_BITMAP_MASK - CLZ(bitmap));
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
2.4 LOS_LowBitGet()获取状态字中为1的最低位
代码其中CTZ(bitmap)
是宏,展开为(__builtin_ctz(value))
,这是编译器内置的高效位运算的库函数,ctz
是count trailing zeros
的缩写,就是统计二进制数值中低位区结尾的全是0的数目,该结果就是状态字中的1的最低位。
UINT16 LOS_LowBitGet(UINT32 bitmap)
{
if (bitmap == 0) {
return LOS_INVALID_BIT_INDEX;
}
return CTZ(bitmap);
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
2.5 LOS_BitmapSetNBits()对状态字的连续标志位进行置1操作
可以使用LOS_BitmapSetNBits()
函数对状态字的连续比特位进行置1操作,第一个参数是需要改变bit
位内容的状态字UINT32 *bitmap
,第二个参数是需要置1的bit
位开始数start
,第三个参数是需要置1的数量numsSet
。由于bit
位开始数start
并没有限制在[0,31],所以实际上设置的可能是UINT32 *bitmap
状态字后面的状态字,需要根据业务实际情况进行设置,避免覆写其他内存。同样,需要置1的数量numsSet
也可能跨多个状态字。如图所示:

我们看下代码,⑴处计算出需要操作的状态字,其中BITMAP_WORD(start)
计算相对状态字bitmap
需要偏移的数量,如果start处于区间[0,31],BITMAP_WORD(start)
等于0,操作的就是状态字bitmap
。如果start处于区间[32,63],BITMAP_WORD(start)
等于1,操作的就是状态字bitmap
后面的第一个状态字,以此类推。⑵处size
可以和bit
位开始数start
结合来理解,size
就是需要置1的bit
位结束位数。⑶处需要置1操作的bit
位的位数,⑷是对应需要置1操作的bit
位的掩码。
⑸处如果条件成立,说明需要置1操作需要跨多个状态字进行操作,代码会一个状态字处理完毕,再去处理下一个状态字。⑹处把当前状态字的相应的bit
位进行置1操作,然后执行⑺把剩余需要置1的位数减去已经置1的位数。⑻处更新bitsToSet
和maskToSet
,然后指针p
指向下一个状态字。⑼处如果需要置1的位数大于0,并且此时已经可以在一个状态字内完成操作,执行⑽处计算需要置1操作的掩码,从bit
开始位到结束位需要进行置1。⑾处代码执行置1操作,完成对状态字的连续标志位进行置1操作。
VOID LOS_BitmapSetNBits(UINTPTR *bitmap, UINT32 start, UINT32 numsSet)
{
⑴ UINTPTR *p = bitmap + BITMAP_WORD(start);
⑵ const UINT32 size = start + numsSet;
⑶ UINT16 bitsToSet = BITMAP_BITS_PER_WORD - (start % BITMAP_BITS_PER_WORD);
⑷ UINTPTR maskToSet = BITMAP_FIRST_WORD_MASK(start);
⑸ while (numsSet > bitsToSet) {
⑹ *p |= maskToSet;
⑺ numsSet -= bitsToSet;
⑻ bitsToSet = BITMAP_BITS_PER_WORD;
maskToSet = OS_BITMAP_WORD_MASK;
p++;
}
⑼ if (numsSet) {
⑽ maskToSet &= BITMAP_LAST_WORD_MASK(size);
*p |= maskToSet;
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
2.6 LOS_BitmapClrNBits()对状态字的连续标志位进行清0操作
可以使用LOS_BitmapClrNBits()
函数对状态字的连续比特位进行清0操作,第一个参数是需要改变bit
位内容的状态字UINT32 *bitmap
,第二个参数是需要清0的bit
位开始数start
,第三个参数是需要清0的数量numsClear
。该函数是函数LOS_BitmapSetNBits()
的反向操作,代码解释可以参考函数LOS_BitmapSetNBits()
。
VOID LOS_BitmapClrNBits(UINTPTR *bitmap, UINT32 start, UINT32 numsClear)
{
UINTPTR *p = bitmap + BITMAP_WORD(start);
const UINT32 size = start + numsClear;
UINT16 bitsToClear = BITMAP_BITS_PER_WORD - (start % BITMAP_BITS_PER_WORD);
UINTPTR maskToClear = BITMAP_FIRST_WORD_MASK(start);
while (numsClear >= bitsToClear) {
*p &= ~maskToClear;
numsClear -= bitsToClear;
bitsToClear = BITMAP_BITS_PER_WORD;
maskToClear = OS_BITMAP_WORD_MASK;
p++;
}
if (numsClear) {
maskToClear &= BITMAP_LAST_WORD_MASK(size);
*p &= ~maskToClear;
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
2.8 LOS_BitmapFfz()获取从最低有效位开始的第一个0的bit位
可以使用LOS_BitmapFfz()
函数获取从最低有效位开始的第一个0的bit
位位数,第一个参数是需要改变bit
位内容的状态字UINT32 *bitmap
,第二个参数numBits
表示最大的位数,对返回值进行限制,需要在指定的位数内找到符合条件的位数,否则返回-1。
在看函数代码之前,先了解下Ffz()
函数,如下:调用内嵌函数__builtin_ffsl()
可以获取一个unsigned long类型数字的二进制形式的从左开始的第一个1的位数,这个位数从1开始计数。比如对于二进制数字0110,该函数会返回2。在下面的函数中,给函数__builtin_ffsl()
传入的参数进行了取反,并减去了1,所以Ffz()
函数返回一个数字从左开始的第一个0的位数,这个位数从0开始计数。
/* find first zero bit starting from LSB */
STATIC INLINE UINT16 Ffz(UINTPTR x)
{
return __builtin_ffsl(~x) - 1;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
我们接着看下函数LOS_BitmapFfz()
的代码。⑴处根据位数numBits
计算出对应的状态字的数量,然后依次循环每一个状态字,⑵处如果状态字全为1,则继续循环,否则执行⑶。执行到⑶说明,,前面有i
个状态字的各个位全为1。i * BITMAP_BITS_PER_WORD + Ffz(bitmap[i])
就表示各个状态字的二进制位中,从左到右第一个0的位置。⑷处如果获取的位数小于第二个参数,则返回获取的位数,否则返回-1。如下图所示:

源代码如下:
INT32 LOS_BitmapFfz(UINTPTR *bitmap, UINT32 numBits)
{
INT32 bit, i;
⑴ for (i = 0; i < BITMAP_NUM_WORDS(numBits); i++) {
⑵ if (bitmap[i] == OS_BITMAP_WORD_MASK) {
continue;
}
⑶ bit = i * BITMAP_BITS_PER_WORD + Ffz(bitmap[i]);
⑷ if (bit < numBits) {
return bit;
}
return -1;
}
return -1;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
小结
本文带领大家一起剖析了鸿蒙轻内核的位操作模块的源代码。
如果大家想更加深入的学习 OpenHarmony 开发的内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:

- 搭建开发环境
- Windows 开发环境的搭建
- Ubuntu 开发环境搭建
- Linux 与 Windows 之间的文件共享
- ……

- 构建子系统
- 启动流程
- 子系统
- 分布式任务调度子系统
- 分布式通信子系统
- 驱动子系统
- ……



写在最后
- 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
- 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
- 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
- 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:
https://qr21.cn/FV7h05

data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/maniuT/article/details/139600616","extend1":"pc","ab":"new"}">>
id="blogExtensionBox" style="width:400px;margin:auto;margin-top:12px" class="blog-extension-box"> class="blog_extension blog_extension_type2" id="blog_extension">
class="extension_official" data-report-click="{"spm":"1001.2101.3001.6471"}" data-report-view="{"spm":"1001.2101.3001.6471"}">
class="blog_extension_card_left">
class="blog_extension_card_cont">
鸿蒙开发学习资料领取!!!
class="blog_extension_card_cont_r">
微信名片
评论记录:
回复评论: