Bit operation is common in kernel, the following is an example of the __set_bit function to analyze its principle:
The kernel/include/asm-generic/bitops/non-atomic.h header file has the following
- /**
- * __set_bit-set a bit in memory
- * @nr: The bit to set
- * @addr: The address to start counting from
- *
- * Unlike Set_bit (), this function was non-atomic and may be reordered.
- * If it ' s called on the same region of memory simultaneously, the effect
- * May is and only one operation succeeds.
- */
- static inline void __set_bit(int nr, volatile unsigned long *addr)
- {
- unsigned long mask = bit_mask(NR);
- unsigned long *p = ((unsigned long *) addr) + Bit_word(NR);
- *p |= Mask;
- }
There are bit_mask in Kernel/include/linux/bitops.h ,bit_word
Click (here) to collapse or open
- ......
- #include <asm/types.h>
- ......
- #define BIT (NR) (1UL << (NR))
- #define Bit_mask(NR) (1UL << (NR)% Bits_per_long)
- #define Bit_word(NR) ((NR)/Bits_per_long)
There are bits_per_long in Kernel/arch/arm/include/asm/types.h.
Click (here) to collapse or open
- #define Bits_per_long 32
So the __set_bit function content equivalent is expressed as follows:
Click (here) to collapse or open
- static inline void __set_bit (int nr, volatile unsigned long *addr)
- {
- addr[nr/32] |= (1UL << (nr%));
- or addr[nr >> 5] |= (1UL << (nr &));
- }
Addr is an array of type unsigned long, which nr/32 gets the bit nr to set in which unsigned long in the array.
Then, by (nr%32) get the unsigned Long integer (No. 0 bit, 1th bit 、... or 31st place?) needs to be set.
Finally, by addr[NR/32] |= (1UL <<(nr%)) to set the corresponding bit in the unsigned long integer.
The 32bit bitmap referred to by the addr address is as follows:
________________
0 <---|_|_|_|_|_|_|_|_|...._|
1 <---|____________...._|
2 <---|____________...._|
. <---|____________...._|
. <---|____________...._|
NR/32 <---|____________...._|
Understanding the above code, the otherbit-Action APIIt's easy to understand.
__clear_bit: Addr The value of the address at the point of the Nr position 0, method General Addr[nr/32] & 11111011111
__change_bit: To reverse the value of NR at the address referred to by addr, the method is generally addr[nr/32] ^ 00000100000
__test_and_set_bit: Place the value of addr at the address indicated in NR position 1, returning the bit original value (0 or 1);
__test_and_clear_bit: The value of NR at the address referred to by addr is cleared at 0, returning the bit original value (0 or 1);
__test_and_change_bit: Reverse the value of NR at the address referred to by addr and return the bit original value (0 or 1);
Test_bit: That is, the test nr bit is set, the position returned 1;
——————————————————————————————————————————————
bit operations are used everywhere in the code, and the flexibility to use these operations can greatly improve the performance of the system, as illustrated below:
1. Application of bitops in process scheduling in Linux 2.6
The Linux 2.6 kernel overrides this part of the process scheduling, which has a time complexity of O (1)
Each CPU has its own separate run queue runqueues, and each running queue divides the process into the active process queue and the expired process queue.
- struct Prio_array {
- unsigned int nr_active; Current number of queue processes
- Declare_bitmap (BITMAP, max_prio+1);//bitmap, each representing the corresponding level of process list whether there is a process
- struct List_head Queue[max_prio]; Process linked list, total Max_prio (140) level, the process is stored in this list by its priority
- };
On each schedule, select the first process from the highest priority list of the active process queue as next.
Let's see how it's chosen.
Let's look at Queue[max_prio in Prio_arry], the process is placed in this queue by priority, all processes in queue[0] have a priority of 0, it has the highest priority, all processes in queue[1] have a priority of 1, and the lower priority value runs first.
0~max_rt_prio (100) is the priority of the real-time process, and Max_rt_prio~max_prio (140) is the priority of the normal process.
The bitmap is 5 32-bit integers, and its first 140 bits correspond to 140 priorities, such as the 5th position of bitmap 1, which represents a process that has a process queue with a priority of 5.
IDX = Sched_find_first_bit (array->bitmap) is to find the first 1 bit in bitmap, then the process queue with the highest current priority can be obtained.
2. Application of Bitops in input subsystem of Linux
Click (here) to collapse or open
- struct Input_dev {
- const char *name;
- const char *phys;
- const char *uniq;
- struct INPUT_ID ID;
- /*
* An array of type unsigned long is established based on the types of input signals.
* Each 1bit of an array represents a type of signal,
* The kernel will set or clear the operation to indicate the occurrence and processing of events.
*/
- unsigned long propbit[bits_to_longs (input_prop_cnt)];
- unsigned long evbit[bits_to_longs (ev_cnt)];
- unsigned long keybit[bits_to_longs (key_cnt)];
- unsigned long relbit[bits_to_longs (rel_cnt)];
- unsigned long absbit[bits_to_longs (abs_cnt)];
- unsigned long mscbit[bits_to_longs (msc_cnt)];
- unsigned long ledbit[bits_to_longs (led_cnt)];
- unsigned long sndbit[bits_to_longs (snd_cnt)];
- unsigned long ffbit[bits_to_longs (ff_cnt)];
- unsigned long swbit[bits_to_longs (sw_cnt)];
- ...............................
- }
3. Application of Bitops in port
4. Application of Bitops in VLAN (1-4094)
"Turn" "Linux" to understand __set_bit in Bitops and its application