Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] bitops: generic find_{next,first}{,_zero}_bit()

This patch introduces the C-language equivalents of the functions below:

unsigned logn find_next_bit(const unsigned long *addr, unsigned long size,
unsigned long offset);
unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
unsigned long offset);
unsigned long find_first_zero_bit(const unsigned long *addr,
unsigned long size);
unsigned long find_first_bit(const unsigned long *addr, unsigned long size);

In include/asm-generic/bitops/find.h

This code largely copied from: arch/powerpc/lib/bitops.c

Signed-off-by: Akinobu Mita <mita@miraclelinux.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Akinobu Mita and committed by
Linus Torvalds
c7f612cd 2dfc383a

+97 -34
+13
include/asm-generic/bitops/find.h
··· 1 + #ifndef _ASM_GENERIC_BITOPS_FIND_H_ 2 + #define _ASM_GENERIC_BITOPS_FIND_H_ 3 + 4 + extern unsigned long find_next_bit(const unsigned long *addr, unsigned long 5 + size, unsigned long offset); 6 + 7 + extern unsigned long find_next_zero_bit(const unsigned long *addr, unsigned 8 + long size, unsigned long offset); 9 + 10 + #define find_first_bit(addr, size) find_next_bit((addr), (size), 0) 11 + #define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0) 12 + 13 + #endif /*_ASM_GENERIC_BITOPS_FIND_H_ */
+84 -34
lib/find_next_bit.c
··· 11 11 12 12 #include <linux/bitops.h> 13 13 #include <linux/module.h> 14 + #include <asm/types.h> 14 15 15 - int find_next_bit(const unsigned long *addr, int size, int offset) 16 + #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) 17 + 18 + /** 19 + * find_next_bit - find the next set bit in a memory region 20 + * @addr: The address to base the search on 21 + * @offset: The bitnumber to start searching at 22 + * @size: The maximum size to search 23 + */ 24 + unsigned long find_next_bit(const unsigned long *addr, unsigned long size, 25 + unsigned long offset) 16 26 { 17 - const unsigned long *base; 18 - const int NBITS = sizeof(*addr) * 8; 27 + const unsigned long *p = addr + BITOP_WORD(offset); 28 + unsigned long result = offset & ~(BITS_PER_LONG-1); 19 29 unsigned long tmp; 20 30 21 - base = addr; 31 + if (offset >= size) 32 + return size; 33 + size -= result; 34 + offset %= BITS_PER_LONG; 22 35 if (offset) { 23 - int suboffset; 24 - 25 - addr += offset / NBITS; 26 - 27 - suboffset = offset % NBITS; 28 - if (suboffset) { 29 - tmp = *addr; 30 - tmp >>= suboffset; 31 - if (tmp) 32 - goto finish; 33 - } 34 - 35 - addr++; 36 + tmp = *(p++); 37 + tmp &= (~0UL << offset); 38 + if (size < BITS_PER_LONG) 39 + goto found_first; 40 + if (tmp) 41 + goto found_middle; 42 + size -= BITS_PER_LONG; 43 + result += BITS_PER_LONG; 36 44 } 37 - 38 - while ((tmp = *addr) == 0) 39 - addr++; 40 - 41 - offset = (addr - base) * NBITS; 42 - 43 - finish: 44 - /* count the remaining bits without using __ffs() since that takes a 32-bit arg */ 45 - while (!(tmp & 0xff)) { 46 - offset += 8; 47 - tmp >>= 8; 45 + while (size & ~(BITS_PER_LONG-1)) { 46 + if ((tmp = *(p++))) 47 + goto found_middle; 48 + result += BITS_PER_LONG; 49 + size -= BITS_PER_LONG; 48 50 } 51 + if (!size) 52 + return result; 53 + tmp = *p; 49 54 50 - while (!(tmp & 1)) { 51 - offset++; 52 - tmp >>= 1; 53 - } 54 - 55 - return offset; 55 + found_first: 56 + tmp &= (~0UL >> (BITS_PER_LONG - size)); 57 + if (tmp == 0UL) /* Are any bits set? */ 58 + return result + size; /* Nope. */ 59 + found_middle: 60 + return result + __ffs(tmp); 56 61 } 57 62 58 63 EXPORT_SYMBOL(find_next_bit); 64 + 65 + /* 66 + * This implementation of find_{first,next}_zero_bit was stolen from 67 + * Linus' asm-alpha/bitops.h. 68 + */ 69 + unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, 70 + unsigned long offset) 71 + { 72 + const unsigned long *p = addr + BITOP_WORD(offset); 73 + unsigned long result = offset & ~(BITS_PER_LONG-1); 74 + unsigned long tmp; 75 + 76 + if (offset >= size) 77 + return size; 78 + size -= result; 79 + offset %= BITS_PER_LONG; 80 + if (offset) { 81 + tmp = *(p++); 82 + tmp |= ~0UL >> (BITS_PER_LONG - offset); 83 + if (size < BITS_PER_LONG) 84 + goto found_first; 85 + if (~tmp) 86 + goto found_middle; 87 + size -= BITS_PER_LONG; 88 + result += BITS_PER_LONG; 89 + } 90 + while (size & ~(BITS_PER_LONG-1)) { 91 + if (~(tmp = *(p++))) 92 + goto found_middle; 93 + result += BITS_PER_LONG; 94 + size -= BITS_PER_LONG; 95 + } 96 + if (!size) 97 + return result; 98 + tmp = *p; 99 + 100 + found_first: 101 + tmp |= ~0UL << size; 102 + if (tmp == ~0UL) /* Are any bits zero? */ 103 + return result + size; /* Nope. */ 104 + found_middle: 105 + return result + ffz(tmp); 106 + } 107 + 108 + EXPORT_SYMBOL(find_next_zero_bit);