What is the return value of test_bit() in <asm/bitops.h> on x86_64?

Le Tan tamlokveer at gmail.com
Wed Dec 9 21:49:00 EST 2015


Hi,

2015-12-10 10:20 GMT+08:00 Le Tan <tamlokveer at gmail.com>:
>
> Hi,
> I was shocked when I found that `test_bit()` will return -1 or 0 to denote whether a bit is set or not in a bitmap.
> Looking at its implementation here:
> ```
> static __always_inline int constant_test_bit(long nr, const volatile unsigned long *addr)
> {
>         return ((1UL << (nr & (BITS_PER_LONG-1))) &
>                 (addr[nr >> _BITOPS_LONG_SHIFT])) != 0;
> }
>
> static inline int variable_test_bit(long nr, volatile const unsigned long *addr)
> {
>         int oldbit;
>
>         asm volatile("bt %2,%1\n\t"
>                      "sbb %0,%0"
>                      : "=r" (oldbit)
>                      : "m" (*(unsigned long *)addr), "Ir" (nr));
>
>         return oldbit;
> }
> ```
> The sbb instruction will let `det = dst - (src + CF)`. So it seems that test_bit() will return -1 if a bit is set? And it seems to work that way in my project.
>
> However, when I wrote another toy function to test it, I saw that it will return 1 for those bits set.
> ```
> #define TEST_MAX_BITS 512
>
> static void rr_unit_test(struct kvm_vcpu *vcpu)
> {
> static u64 counter = 0;
> int ret;
> DECLARE_BITMAP(test_map, TEST_MAX_BITS);
> u64 nr;
>
> if (vcpu->vcpu_id != 0)
> return;
> if (counter == 0) {
> ++counter;
> bitmap_zero(test_map, TEST_MAX_BITS);
> ret = test_bit(5, test_map);
> printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret);
> set_bit(5, test_map);
> ret = test_bit(5, test_map);
> printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret);
> ret = test_bit(6, test_map);
> printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret);
> ret = test_bit(512, test_map);
> printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret);
> set_bit(512, test_map);
> ret = test_bit(512, test_map);
> printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret);
> nr = 448;
> ret = test_bit(nr, test_map);
> printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret);
> set_bit(nr, test_map);
> ret = test_bit(nr, test_map);
> printk(KERN_INFO "vcpu=%d ret=%d\n", vcpu->vcpu_id, ret);
> }
> }
> ```
> So why will test_bit() behave differently?
> Thanks very much!
>
> Regards,
> Le Tan

Sorry for my being careless. Though I declared nr variable here, but
it is still __builtin_constant_p. So test_bit() will return -1 for
those nr which are not builtin constant, and return 1 on the other
case.
Sorry for my disturbance! :)

Regards,
Le



More information about the Kernelnewbies mailing list