Use of rbtree for Linux Kernel Analysis

Source: Internet
Author: User
Tags first string

I. Theoretical Basis

The red/black tree is a binary search tree with a color attribute on each node. The color is red or black. In addition to the mandatory requirements for binary tree search, the following additional requirements are added for any valid red/black tree:

Property 1. nodes are red or black.

Property 2. The root is black.

Properties 3. All leaves are black (the leaves are nil nodes ).

Property 4. The two subnodes of each Red node are black. (There cannot be two consecutive red nodes in all paths from each leaf to the root)

5. All simple paths from any node to each of its leaves contain the same number of black nodes.

 

Rbtree with the following properties.
1. Every node has a value.
2. The value of any node is greater than the value of its left child and less than the value of its right child.
3. Every node is colored either red or black.
4. Every red node that is not a leaf has only black children.
5. Every path from the root to a leaf contains the same number of black nodes.
6. The root node is black.

  In addition to a key, three pointers: parent, left, and right, each node of the red/black tree has another attribute: color. If the corresponding pointer field does not exist, set to nil.

What we really care about is the key domain. We need to build an rbtree to minimize the time required to search for the key domain and ensure it is O (logn ).

Of course, some insertion and deletion times are sacrificed. To ensure the five features of rbtree, each insertion or deletion of a node must be

To ensure that the five features still exist, we need to perform more operations.

In the figure, the key field is a number, and the size is good. The key on the left subtree of any node must be smaller than the key on the right subtree.

 

II. Implementation of rbtree in Linux

 Code Location

Kernel/lib/rbtree. c

Kernel/include/Linux/rbtree. h

Kernel/documentation/rbtree. TX // instructions on how to use the red/black tree

Typedef struct st_rb_node {

/**

* The structure is 4-byte aligned, so the two low bits in the address are always 0. // Why?

* Linux kernel developers are very fond of memory. They use an idle bit to store color information.

* The parent_color member actually contains the parent node pointer and its own color information.

*/

Unsigned long parent_color; // Save the pointer value of the parent node (the address of the parent node) and save the color of the node

# Define rb_red 0

# Define rb_black 1

Structst_rb_node * left, * right;

}__ Attribute _ (aligned (sizeof (long) rb_node;

But there is no key field in the implementation of Linux, which is already a major feature of the Linux data structure, that is, the structure does not include data, but the data and basic structure are included in the same struct. (Just as there is no data field in list_head, you need to use the struct of the linked list to include the list_head field.) The macro container_of is used to obtain data information, it utilizes some compiler features. If you are interested, refer to the Linux linked list source code.

The rb_node struct is encapsulated by a "_ attribute _ (aligned (sizeof (long)" (this is very important, and the technique is here !),

"_ Attribute _ (aligned (sizeof (long)" means to align the structure address with "sizeof (long,

For 32-bit machines, sizeof (long) is 4 (that is, the Data Type address in the Structure Body is a multiple of 4 ). For 64-bit machines, sizeof (long) is 8 (the address of the Data Type in the Structure Body is a multiple of 8). In this case, we need to supplement the knowledge of byte alignment:

<In-depth understanding of computer systems> section 3.10

The alignment policy used in Linux is that the address of the 2-byte data type (for example, short) must be a multiple of 2, and the larger data type (for example, Int, int *, the float and double addresses must be multiples of 4, and these two requirements mean that the addresses of a short type object must be equal to 0 (the minimum value of 1 must be a singular address ), the minimum two addresses of any int type object or pointer must be 0 (only the minimum two are 0 to divide 4 ).

 

 

 

Therefore, an address that is multiples of 4 (or 8) is represented in binary format and is characterized by a multiple of 4 (byte alignment ).Address(32-bit machine) the last two digits must be zero (the address of the storage variable, not the variable). For 64-bit machines, the last three digits must be zero.

ForRB-treeEach node in must be marked with a color (there are only two options:RedVSBlack), And the technique here is "_ attribute _ (aligned (sizeof (long)", because every node in the red/black tree is represented by the rb_node structure, with the byte alignment technique, the addresses of any rb_node struct must be zero at least. Instead of being empty, it is better to use them to represent the face color. There are two colors, in fact, one is enough. The unsigned long rb_parent_color variable has the following two functions ):

1. store the address of the parent node (note that the address of the parent node of ia32 is a multiple of 4, and the two digits after the address are not used. If IA64 is used, the address of the parent node is a multiple of 8, the three digits after the address are not used ).

2. Use the last two digits to identify the color (:RedVSBlack)

Include/Linux/rbtree. h contains several rb_parent_color-related macros # definerb_parent (R) (struct rb_node *) (R)-> rb_parent_color &~ 3) // get the address of the parent node of the r node, that is, clear the last two digits of the r node and perform operations with the parent node stored in the r node. // Assume that the content of R-> rb_parent_color is 0x20000001 (indicating that the address of the parent node is 0x20000000, and the color of the node is black). // after this operation, obtain the address of the parent node as 0x20000000 # definerb_color (R)-> rb_parent_color & 1) // set the color of the r node to black, you only need to check the last digit. # definerb_is_red (R )(! Rb_color (R) // test whether the r node is red # definerb_is_black (r) rb_color (r) // test whether the r node is black # definerb_set_red (r) do {(r) -> rb_parent_color & = ~ 1;} while (0) // set the r node to Red # definerb_set_black (r) do {(R)-> rb_parent_color | = 1;} while (0) // set the r node to a black node // inline function, and set the node's parent node static inline voidrb_set_parent (struct rb_node * RB, struct rb_node * P) {RB-> rb_parent_color = (RB-> rb_parent_color & 3) | (unsigned long) P ;}// inline function, set the color static inline voidrb_set_color (struct rb_node * RB, int color) {RB-> rb_parent_color = (RB-> rb_parent_color &~ 1) | color ;}

In this way, to extract the parent pointer, you only need to clear the lower two digits of the rb_parent_color member:

# Define rb_parent (R) (struct rb_node *) (R)-> rb_parent_color &~ 3 ))

You only need to check the last digit for the color:

# Define rb_color (R)-> rb_parent_color & 1)

Testing colors and setting colors are also a matter of course. Specifically, the following inline function is required:

Static inline void rb_link_node (struct rb_node * node, struct rb_node * parent, struct rb_node ** rb_link );

It sets the parent as the parent node of the node and points rb_link to the node.

 

Two basic operations: Left and Right

_ Rb_rotate_left is to left the node in the tree root, __rb_rotate_right is to right. These two functions provide services for insertion and deletion, rather than external interfaces.

The remaining several interfaces are relatively simple.

Struct rb_node * rb_first (struct rb_root * root );

Find and return the smallest node in the tree with root as the root node, as long as you keep walking from the root node to the left. 3 In

Struct rb_node * rb_last (struct rb_root * root );

Is to find and return the largest one, always to the right. In 47

Struct rb_node * rb_next (struct rb_node * node); // note that the concept of next is determined not based on the node location, but by its key field,

// The rbtree itself is ordered, so there can be pre-order, middle-order, and subsequent traversal methods

Returns the successor of the node in the tree, which is a little more complex. If the right child of node is not empty, it only needs to return the smallest node in the right subtree of node (the next of center 17 is 19); if it is empty, it needs to look up, find the child node whose child id is the parent node and return the child node whose child id is 17 (next of 16 is 17 ). If it reaches the root node, null is returned.

Struct rb_node * rb_prev (struct rb_node * node );

Returns the node precursor, which is symmetric with the operations in rb_next.

Void rb_replace_node (struct rb_node * victim, structrb_node * New, struct rb_root * root );

Replace the victim node in the tree with "new" as the root.

3. How to build an rbtree when the key field is a string?

When the key field is a string, the foundation for building an rbtree is that the string can be compared to the size.

Starting with the strcmp function, the strcmp function compares the size of two strings and returns the comparison result. The general form is:

I = strcmp (string 1, string 2 );

Both string 1 and string 2 can be string constants or variables. I is an integer variable used to store comparison results. The comparison result is as follows:

① If string 1 is less than string 2, The strcmp function returns a negative value;

② If String 1 is equal to string 2, The strcmp function returns zero;

③ If string 1 is greater than string 2, The strcmp function returns a positive value;

How can we compare the character sizes? Let's look at an example.

In fact, strings are compared to the ASCII code of each pair of characters in strings. First, compare the first character of the two strings. If they are not equal, stop the comparison and obtain the result greater than or less than. If they are equal, then compare the second character and the third character. If the characters before the two strings are always equal, like "disk" and "disks", the first four characters are the same, and then the fifth character is compared, the first string "disk" has only the terminator '/0', And the last string "disks" has 'S ', the '/0' ASCII code is less than the 's' ASCII code, so the result is obtained. Therefore, no matter what the two strings are, the strcmp function can obtain the result by comparing a string with the terminator '/0' at most.

Note: strings are arrays rather than simple types and cannot be compared by relational operations.

If ("ABC"> "def")/* incorrect string comparison */

If (strcmp ("ABC", "def")/* correct string comparison */

With this theoretical basis, we can build an rbtree with the key field of the string type. For the construction method, see

./Kernel/documentation/rbtree.txt. The excerpt is as follows:

 

Creating a New rbtree

---------------------

Data nodes in an rbtree tree are structurescontaining a struct rb_node member:

Struct mytype

{

Struct rb_node node;

Char * keystring;

};

When dealing with a pointer to the embeddedstruct rb_node, The containing data structure may be accessed with the standardcontainer_of () Macro. in addition, individual members may be accessed directly via rb_entry (node, type, member ).

At the root of each rbtree is an rb_rootstructure, Which is initialized to be empty:

Struct rb_root mytree = rb_root;

Searching for a value in an rbtree

----------------------------------

Writing a search function for your tree isfairly straightforward: start at the root, compare each value, and follow theleft or right branch as necessary.

Example:

Struct mytype * my_search (struct rb_root * root, char * string)

{

Struct rb_node * node = root-> rb_node;

While (node)

{

Struct mytype * Data = container_of (node, struct mytype, node );

Int result;

// Compare strings

Result = strcmp (string, data-> keystring );

If (result <0)

Node = node-> rb_left; // It is smaller than the current node, so you can keep searching to the left.

Else if (result> 0)

Node = node-> rb_right; // if it is larger than the current node, you can always search for it on the right.

Else

Return data;

}

Return NULL;

}

Inserting data into an rbtree

-----------------------------

Inserting Data in the tree involves firstsearching for the place to insert the new node, then inserting the node andrebalancing ("recoloring") the tree.

The search for insertion differs from theprevious search by finding the location of the pointer on which to graft thenew node. The new node also needs a link to its parent node for rebalancingpurposes.

Example:

Int my_insert (struct rb_root * root, struct mytype * Data)

{

Struct rb_node ** new = & (root-> rb_node), * parent = NULL;

/* Figure out where to put new node */

While (* New)

{

Struct mytype * This = container_of (* New, struct mytype, node );

Int result = strcmp (data-> keystring, this-> keystring );

Parent = * New;

If (result <0)

New = & (* New)-> rb_left );

Else if (result> 0)

New = & (* New)-> rb_right );

Else

Return false;

}

/* Add new node and rebalance tree .*/

Rb_link_node (data-> node, parent, new );

Rb_insert_color (data-> node, root );

Return true;

}

Removing or replacing existing data in anrbtree

------------------------------------------------

To remove an existing node from a tree, call:

Void rb_erase (struct rb_node * victim, struct rb_root * tree );

Example:

Struct mytype * Data = MySearch (mytree, "Walrus ");

If (data)

{

Rb_erase (data-> node, mytree );

Myfree (data );

}

To replace an existing node in a tree with anew one with the same key, call:

Voidrb_replace_node (struct rb_node * Old, struct rb_node * New, struct rb_root * tree );

Replacing a node this way does not re-sortthe tree: if the new node doesn' t have the same key as the old node, the rbtreewill probably become upted.

Iterating through the elements stored in anrbtree (in sort order)

 

In Linux, the RD Tree is used in many places. Anticipatory, deadline, and cfq I/O scheduling both use the RB tree for request tracking, as well as the CD/DVD drive package management. The high-resolutiontimer uses the RB tree to organize scheduled requests. The ext3 file system also uses the RB tree to manage directories. The Virtual Storage Management System also provides a Rb tree for VMAs (virtual memory areas) management. Of course, network data packets scheduled by file descriptors, password keys, and "Level Token buckets" are organized and managed using RB data. In addition, in C ++ STL, Set
And the underlying implementation of map is based on RB-tree.

Where rbtree is used in Android

1)/kernel/power/userwakelock. C // manage the user space's wakelock

This file is a simplified version of rbtree, which is implemented using only a few interfaces. This is also the key field as a string, which is actually the name of wake_lock.

Use rbtree to connect all the wakelock requests from the user space.

You can use this example to sort out the use of rbtree:

First, why rbtree?

When the user space applies for hundreds of wakelock, The rbtree data structure can quickly find the lock by name alone.

Secondly, how to use rbtree?

Construct struct user_wake_lock

By name --------> rbtree_node --------> user_wake_lock --------> wake_lock

We can imagine the layout of each structure in the memory: The Tree connected by rbtree_node, and each node is a member of another struct.

2) Binder

This is not yet viewed...

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.