Temporarily allow recursion on locks to deal with a double lock in the
[dragonfly.git] / sys / vfs / gnu / ext2fs / i386-bitops.h
1 /* $FreeBSD: src/sys/gnu/ext2fs/i386-bitops.h,v 1.5 1999/11/15 23:16:06 obrien Exp $ */
2 /* $DragonFly: src/sys/vfs/gnu/ext2fs/i386-bitops.h,v 1.2 2003/06/17 04:28:34 dillon Exp $ */
3 /*
4  * this is mixture of i386/bitops.h and asm/string.h
5  * taken from the Linux source tree 
6  *
7  * XXX replace with Mach routines or reprogram in C
8  */
9 #ifndef _SYS_GNU_EXT2FS_I386_BITOPS_H_
10 #define _SYS_GNU_EXT2FS_I386_BITOPS_H_
11
12 /*
13  * Copyright 1992, Linus Torvalds.
14  */
15
16 /*
17  * These have to be done with inline assembly: that way the bit-setting
18  * is guaranteed to be atomic. All bit operations return 0 if the bit
19  * was cleared before the operation and != 0 if it was not.
20  *
21  * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
22  */
23
24 /*
25  * Some hacks to defeat gcc over-optimizations..
26  */
27 struct __dummy { unsigned long a[100]; };
28 #define ADDR (*(struct __dummy *) addr)
29
30 static __inline__ int set_bit(int nr, void * addr)
31 {
32         int oldbit;
33
34         __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
35                 :"=r" (oldbit),"=m" (ADDR)
36                 :"ir" (nr));
37         return oldbit;
38 }
39
40 static __inline__ int clear_bit(int nr, void * addr)
41 {
42         int oldbit;
43
44         __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
45                 :"=r" (oldbit),"=m" (ADDR)
46                 :"ir" (nr));
47         return oldbit;
48 }
49
50 static __inline__ int change_bit(int nr, void * addr)
51 {
52         int oldbit;
53
54         __asm__ __volatile__("btcl %2,%1\n\tsbbl %0,%0"
55                 :"=r" (oldbit),"=m" (ADDR)
56                 :"ir" (nr));
57         return oldbit;
58 }
59
60 /*
61  * This routine doesn't need to be atomic, but it's faster to code it
62  * this way.
63  */
64 static __inline__ int test_bit(int nr, void * addr)
65 {
66         int oldbit;
67
68         __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
69                 :"=r" (oldbit)
70                 :"m" (ADDR),"ir" (nr));
71         return oldbit;
72 }
73
74 /*
75  * Find-bit routines..
76  */
77 static __inline__ int find_first_zero_bit(void * addr, unsigned size)
78 {
79         int res;
80         int _count = (size + 31) >> 5;
81
82         if (!size)
83                 return 0;
84         __asm__("                       \n\
85                 cld                     \n\
86                 movl $-1,%%eax          \n\
87                 xorl %%edx,%%edx        \n\
88                 repe; scasl             \n\
89                 je 1f                   \n\
90                 xorl -4(%%edi),%%eax    \n\
91                 subl $4,%%edi           \n\
92                 bsfl %%eax,%%edx        \n\
93 1:              subl %%ebx,%%edi        \n\
94                 shll $3,%%edi           \n\
95                 addl %%edi,%%edx"
96                 : "=c" (_count), "=D" (addr), "=d" (res)
97                 : "0" (_count), "1" (addr), "b" (addr)
98                 : "ax");
99         return res;
100 }
101
102 static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
103 {
104         unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
105         int set = 0, bit = offset & 31, res;
106         
107         if (bit) {
108                 /*
109                  * Look for zero in first byte
110                  */
111                 __asm__("                       \n\
112                         bsfl %1,%0              \n\
113                         jne 1f                  \n\
114                         movl $32, %0            \n\
115 1:                      "
116                         : "=r" (set)
117                         : "r" (~(*p >> bit)));
118                 if (set < (32 - bit))
119                         return set + offset;
120                 set = 32 - bit;
121                 p++;
122         }
123         /*
124          * No zero yet, search remaining full bytes for a zero
125          */
126         res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
127         return (offset + set + res);
128 }
129
130 /*
131  * ffz = Find First Zero in word. Undefined if no zero exists,
132  * so code should check against ~0UL first..
133  */
134 static __inline__ unsigned long ffz(unsigned long word)
135 {
136         __asm__("bsfl %1,%0"
137                 :"=r" (word)
138                 :"r" (~word));
139         return word;
140 }
141
142 /* 
143  * memscan() taken from linux asm/string.h
144  */
145 /*
146  * find the first occurrence of byte 'c', or 1 past the area if none
147  */
148 static __inline__ char * memscan(void * addr, unsigned char c, int size)
149 {
150         if (!size)
151                 return addr;
152         __asm__("                       \n\
153                 cld                     \n\
154                 repnz; scasb            \n\
155                 jnz 1f                  \n\
156                 dec %%edi               \n\
157 1:              "
158                 : "=D" (addr), "=c" (size)
159                 : "0" (addr), "1" (size), "a" (c));
160         return addr;
161 }
162
163 #endif /* !_SYS_GNU_EXT2FS_I386_BITOPS_H_ */