Linux kernel linked list implementation process _linux shell

Source: Internet
Author: User
Tags prefetch prev

On the realization of the double linked list, the general textbook defines a two-way linked list node in the following ways:

Copy Code code as follows:

struct list_node{
Stuct List_node *pre;
Stuct List_node *next;
Elemtype data;
}

That is, a list node contains: A pointer to a forward node, a pointer to a subsequent node, and a total of three data fields.
But when you look at the list implementation in the Linux kernel code, you'll find that it's a lot different from the textbook approach.
See how Linux realizes a double linked list.
Double linked table node definition
Copy Code code as follows:

struct List_head {
struct List_head *next, *prev;
};

What is the use of a linked list that discovers that there is no data field at all in a linked list node? What is the reason for defining such a list in the Linux kernel?
This is because Linux is through the definition of a linked list structure, and embedded in the structure of a linked list node to implement the list structure. This has the advantage of being able to achieve the goal of separating the linked list from the structure. In this way, after we build a linked list, the schematic diagram of the structure is as follows:

Definition of linked list and initialization macro definition:
Copy Code code as follows:

#define LIST_HEAD_INIT (name) {& (name),& (name)}
#define LIST_HEAD (name) \
struct List_head name = List_head_init (name)
#define Init_list_head (PTR) do {\
(PTR)->next = (PTR); (PTR)->prev = (ptr); \
} while (0)

The List_head (name) macro defines a linked header and points his two pointers to himself. We can define and initialize a list named name by calling the List_head (name) macro directly at the variable declaration of the program. You can also declare a list first, and then use Init_list_head to initialize the list.
Also namely:
Copy Code code as follows:

List_head (MyList);
And
struct List_head mylist;
Init_list_head (&mylist);

is equivalent.

Insert operation

Copy Code code as follows:

/* For internal calls only
* Insert A new entry between two known consecutive entries.
* This is a for internal list manipulation where we know
* The Prev/next entries already!
*/
static inline void __list_add (struct list_head *new,
struct List_head *prev,
struct List_head *next)
{
Next->prev = new;
New->next = Next;
New->prev = prev;
Prev->next = new;
}

Copy Code code as follows:

Insert a node after the head node
static inline void List_add (struct list_head *new, struct list_head)
{
__list_add (New, head, Head->next);
}
Insert a node after the tail node
static inline void List_add_tail (struct list_head *new, struct list_head)
{
__list_add (New, Head->prev, head);
}


Delete operation
Copy Code code as follows:

static inline void __list_del (struct list_head * prev, struct list_head * next)
{
Next->prev = prev;
Prev->next = Next;
}
static inline void List_del (struct list_head *entry)
{
__list_del (Entry->prev, Entry->next);
}

Deleting a linked list node is simple by linking the previous node of the node that you want to delete with the latter node.
Linked list node substitution operation
Copy Code code as follows:

static inline void List_replace (struct list_head *old,
struct List_head *new)
{
New->next = old->next;
New->next->prev = new;
New->prev = old->prev;
New->prev->next = new;
}


Linked list traversal operations (emphasis here)
First let's look at how to get the address of the structure of a linked list node.
Copy Code code as follows:

#define List_entry (PTR, type, member) container_of (PTR, type, member)
The CONTAINER_OF macro is defined as follows:
#define CONTAINER_OF (PTR, type, member) ({\
Const typeof ((type *) 0)->member) *__mptr = (ptr); \
(Type *) ((char *) __mptr-offsetof (Type,member));}
The macro definition for Offsetof is as follows:
#define OFFSETOF (Type, member) ((size_t) & ((type *) 0)->member)
Simplify this to become the following:
#define List_entry (PTR, type, member) \
((Type *) ((char *) (PTR)-(size_t) (& (Type *) 0)->member))

is a macro with 3 parameters that gets the starting address of the structure body where the linked list node (PTR) is located. With this macro, we can get a pointer to the structure of a linked list node by knowing the pointer to it, so that we can traverse the list, and we will be able to traverse our own defined structure. The first parameter is an address, which is the address of the node element of the structural body chain, the second parameter is the struct type, and the third parameter is the name of the linked list node element in the structure body.
To make a careful analysis of this macro:
The outermost bracket can be removed, which is to prevent the macro from being expanded, and removed as follows:
(Type *) ((char *) (PTR)-(size_t) (& (Type *) 0)->member))
It is now clear that first (type *) is a C-cast operation, or a pointer to a type structure that converts subsequent data. And the following operations can be decomposed
(char *) (PTR)-(size_t) (& ((type *) 0)->member)
This is a subtraction operation, preceded by a pointer, we pass over the structure of the link table node elements of the pointer, here is converted to point to the character. And the back is a plastic that can be decomposed
(size_t) (& ((type *) 0)->member)
Obviously this is a pointer transformation, and this pointer can be decomposed again,
& ((Type *) 0)->member
You can see that this pointer is a variable that gets the address, and what is this variable?
((type *) 0)->member
It looks a little strange, but this operation is the most subtle of the entire macro, he converts address 0 to type, and then to the member element of the structure, member is the parameter we pass in: the name of the element in the structure. In fact ((type *) 0)->member Take the variable is what the content is not important, important we want to take the address of this variable. Take this address and convert it to the size_t type, so this data is ((type *) 0)->member relative to address 0. Back to the above subtraction, the structure of the link table node elements of the address and the structure of the first address of the offset subtraction, do not get the address of the structure of the body. ) (& ((type *) 0)->member))
The outermost bracket can be removed, which is to prevent the macro from being expanded, and removed as follows:
(Type *) ((char *) (PTR)-(size_t) (& (Type *) 0)->member))
It is now clear that the first (type *) is a C-cast operation, or a pointer to a type structure that converts subsequent data. And the following operations can be decomposed
(char *) (PTR)-(size_t) (& ((type *) 0)->member)
This is a subtraction operation, preceded by a pointer, a pointer to the structure element of the past, which is converted to a character. And the back is a long plastic that can be decomposed
(size_t) (& ((type *) 0)->member)
Obviously this long shaping is a pointer transformation, and this pointer can be decomposed again,
& ((Type *) 0)->member
You can see that this pointer is a variable to get the address, what is this variable?
((type *) 0)->member
It's kind of weird, but it's the most subtle of the entire macro, he converts address 0 to type, and then the member element of the structure, which is the parameter we pass in: the name of the element in the structure. In fact ((type *) 0)->member Take the variable is what the content is not important, important we want to take the address of this variable. Take this address and convert it to the size_t type, so this data is ((type *) 0)->member relative to address 0. By returning to the above subtraction, the address of the element in the structure is subtracted from the offset of the first address of the structure body, and the address of the structure is obtained.
The traversal of a linked list is implemented through a macro:
Copy Code code as follows:

#define List_for_each (POS, head) \
for (pos = [head]->next, prefetch (pos->next);p os!= (head); \
pos = Pos->next,prefetch (Pos->next))

Where prefetch is used for performance optimization, it is not necessary to manage it for the time being.
From the list above, we can see that it is only once to get the link table node pointer, in the actual application, we need to get the data items of the structure of the linked table node, therefore, List_for_each and list_entry are usually used together. To do this, the Linux list implementation provides an additional interface as follows:
Copy Code code as follows:

#define LIST_FOR_EACH_ENTRY (POS, head, member) \
for (pos = list_entry (head)->next, typeof (*pos), member); \
Prefetch (Pos->member.next), &pos->member!= (head);
pos = List_entry (Pos->member.next, typeof (*pos), member))

With this interface, we can traverse our actual structure data field through the list structure.
For example, we have defined a struct as follows:
Copy Code code as follows:

struct mystruct{
ElemType1 data1;
ElemType2 data2;
Strcut List_head anchor;//Usually we call the chain table node in the structure body as the chain anchor, because it has the role of positioning.
}

So our code to traverse the list is as follows:
Copy Code code as follows:

struct MyStruct *pos;
List_for_each_entry (Pos,head,anchor) {
MyStruct *pstruct=pos;
Do something with pstruct .....
}

In addition, the Linux list also provides two "_safe" interfaces corresponding to basic traversal operations: List_for_each_safe (POS, N, head), List_for_each_entry_safe (POS, N, head, member), They require the caller to provide an additional pointer n of the same type as the POS, to hold the address of the next node of the POS in the For loop, and to avoid the broken chain caused by the release of the POS node.
Of course, Linux lists not only provide the above interface, but also
Copy Code code as follows:

List_for_each_prev (POS, head)
List_for_each_prev_safe (POS, N, head)
List_for_each_entry_reverse (POS, head, member)
List_prepare_entry (POS, head, member)
static inline int list_empty_careful (const struct List_head *head)
static inline void List_del_init (struct list_head *entry)
static inline void List_move (struct list_head *list, struct list_head)
static inline void List_move_tail (struct list_head *list,
struct List_head *head)
static inline int list_empty (const struct List_head *head)

Related Article

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.