RT-Thread源码-__rt_ffs函数剖析

  • 在RT-Thread中,获取已就绪最高优先级线程索引会使用此函数。而此函数所包含的算法为bitmap算法。
  • 为什么使用此函数获取已就绪最高优先级线程索引?为什么使用bitmap算法?目的在于提升索引值获取的执行效率,以及保证系统的稳定执行。
  • 通常,为了获取已就绪最高优先级线程,最简单的方法就是遍历当前线程列表中的每一个线程状态及优先级,通过比较最后获取。而这种方法会随着最大支持线程数的增加而增加时间复杂度O(n)(采用bitmap算法后时间复杂度为O(1)),且执行时间非恒定,影响系统的稳定。
  • 此函数在RT-Thread中实现如下,
const rt_uint8_t __lowest_bit_bitmap[] =
{
    /* 00 */ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 10 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 20 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 30 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 40 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 50 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 60 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 70 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 80 */ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 90 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* A0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* B0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* C0 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* D0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* E0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* F0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};

/**
 * This function finds the first bit set (beginning with the least significant bit)
 * in value and return the index of that bit.
 *
 * Bits are numbered starting at 1 (the least significant bit).  A return value of
 * zero from any of these functions means that the argument was zero.
 *
 * @return return the index of the first bit set. If value is 0, then this function
 * shall return 0.
 */
int __rt_ffs(int value)
{
    if (value == 0) return 0;

    if (value & 0xff)
        return __lowest_bit_bitmap[value & 0xff] + 1;

    if (value & 0xff00)
        return __lowest_bit_bitmap[(value & 0xff00) >> 8] + 9;

    if (value & 0xff0000)
        return __lowest_bit_bitmap[(value & 0xff0000) >> 16] + 17;

    return __lowest_bit_bitmap[(value & 0xff000000) >> 24] + 25;
}
  • 以上C实现中,提供了一个__lowest_bit_bitmap,这个最低位图表是结合系统支持最大线程数(256),提前计算出来的最高优先级结果。假设设置系统最大线程数为32,则通常会使用一个32bit变量来表示所有线程的状态,每一个bit,1表示就绪,0表示挂起,若此变量值为6,则表示当前优先级为1,优先级为2的线程处于就绪态,那么此时的已就绪最高优先级线程索引就为1;若此变量值为15,则表示前四优先级线程均为就绪态,那么此时的已就绪最高优先级线程索引就为0。其余,以此类推。
  • 在最大线程数设置为大于32的情况下,在RT-Thread中采用了二级位图的形式,即将所有线程已8个为一组的方式分为若干组。那么,同理,这时候在获取已就绪最高优先级线程索引前增加一步,获取已就绪最高优先级线程组索引。
  • RT-Thread中还针对各处理器及编译器提供了ARM汇编的优化实现,适配Cortex-M4处理器实现如下:
/**
 * This function finds the first bit set (beginning with the least significant bit)
 * in value and return the index of that bit.
 *
 * Bits are numbered starting at 1 (the least significant bit).  A return value of
 * zero from any of these functions means that the argument was zero.
 *
 * @return return the index of the first bit set. If value is 0, then this function
 * shall return 0.
 */
#if defined(__CC_ARM) || defined(__CLANG_ARM)
__asm int __rt_ffs(int value)
{
	// 判断value是否为0,若为0则直接返回
    CMP     r0, #0x00
    BEQ     exit

    RBIT    r0, r0			// 反转value的高低位
    CLZ     r0, r0			// 计算value低bit位为0的个数
    ADDS    r0, r0, #0x01	// 以上得到的结果+1,则得到为1的最低bit索引

exit
    BX      lr
}
#elif defined(__IAR_SYSTEMS_ICC__)
int __rt_ffs(int value)
{
    if (value == 0) return value;

    asm("RBIT %0, %1" : "=r"(value) : "r"(value));
    asm("CLZ  %0, %1" : "=r"(value) : "r"(value));
    asm("ADDS %0, %1, #0x01" : "=r"(value) : "r"(value));

    return value;
}
#elif defined(__GNUC__)
int __rt_ffs(int value)
{
    return __builtin_ffs(value);
}
#endif
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值