Document directory
When Sam looked at 2.4kernel, he often looked at list. But now he hasn't looked at kernel for a long time, didn't write programs, and he has forgotten a lot. Today, let's take a look and record it.
In linuxkernel, two-way linked list is often used. In ~ In/include/Linux/list. H, two-way linked list and common functions are defined.
The linked list header is as follows:
Struct list_head {
Struct list_head * Next, * Prev;
};
1. Create a two-way linked list ):
Init_list_head (Struct list_head * List)
The Code is as follows:
Static inline void init_list_head (struct list_head * List)
{
List-> next = List;
List-> Prev = List;
}
Point the header and tail of the List to itself.
2. Add the content to the two-way linked list:
2.1: normal addition:
2.1.1:Add a new project to the header of the list (the first position after the head ). Note that the head here refers to the two-way linked list header.
Void list_add (struct list_head * New, struct list_head * head)
Add parameter 1 (new) to the head. It calls
_ List_add (new, head, head-> next); that is, add new to the range between head and head-> next.
Static inline void _ list_add (structlist_head * New,
Struct list_head * Prev,
Struct list_head * Next) // It just adds new to the prev and next
{
Next-> Prev = new;
New-> next = next;
New-> Prev = Prev;
Prev-> next = new;
}
2.1.2: add the last position of the two-way linked list (that is, the priv of the head) to the new project ). Note that head indicates the list header.
Static inline void list_add_tail (structlist_head * New, struct list_head * head)
{
_ List_add (new, head-> Prev, head );
}
Add new to head-> Prev and head.
2.2: add the read copy Update (RCU) mode (smp_wmb () (see background)
2.2.1: add the new project to the prev and next of the knowledge:
Static inline void _ list_add_rcu (structlist_head * New,
Struct list_head * Prev, structlist_head * Next)
{
New-> next = next;
New-> Prev = Prev;
Smp_wmb ();
Next-> Prev = new;
Prev-> next = new;
}//Note: smp_wmb ();Smp_wmb () prevents the compiler and CPU from optimizing the code execution sequence. Here, smp_wmb ensures that the last two lines are executed after the previous two lines of code are executed.
2.2.2:Add a new project to the header of the list (the first position after the head ). Note that the head here refers to the two-way linked list header.
Static inline void list_add_rcu (structlist_head * New, struct list_head * head)
{
_ List_add_rcu (new, head, head-> next );
}
2.2.3:Add the last position of the two-way linked list to the new project (that is, the priv of the head ). Note that head indicates the list header.Staticinline void list_add_tail_rcu (struct list_head * New,
Structlist_head * head)
{
_ List_add_rcu (new, head-> Prev, head );
}
3. delete a project from a two-way linked list:
3.1: Basic deletion functions:
Static inline void _ list_del (structlist_head * Prev, struct list_head * Next)
{
Next-> Prev = Prev;
Prev-> next = next;
} // Only refer to the previous and next
3.2: delete a specified item:
Static inline void list_del (structlist_head * entry)
{
_ List_del (Entry-> Prev, entry-> next );
Entry-> next = list_python1;
Entry-> Prev = list_python2;
}
3.3: safely delete a specified item:
Static inline void list_del_rcu (structlist_head * entry)
{
_ List_del (Entry-> Prev, entry-> next );
Entry-> Prev = list_python2;
}
Sam doesn't know what's going on here.
3.4: delete and initialize an item:
Static inline void list_del_init (structlist_head * entry)
{
_ List_del (Entry-> Prev, entry-> next );
Init_list_head (entry );
}
4. Replace an item:
4.1 replace old with new:
Static inline void list_replace (structlist_head * old,
Structlist_head * New)
{
New-> next = old-> next;
New-> next-> Prev = new;
New-> Prev = old-> Prev;
New-> Prev-> next = new;
}
4.2 replace and initialize:
Static inline voidlist_replace_init (struct list_head * old,
Structlist_head * New)
{
List_replace (old, new );
Init_list_head (old );
}
4.3: Security replacement:
Static inline void list_replace_rcu (structlist_head * old,
Structlist_head * New)
{
New-> next = old-> next;
New-> Prev = old-> Prev;
Smp_wmb ();
New-> next-> Prev = new;
New-> Prev-> next = new;
Old-> Prev = list_python2;
}
5. Move item:
5.1 move to the header
Static inline void list_move (structlist_head * List, struct list_head * head)
{
_ List_del (list-> Prev, list-> next );
List_add (list, head );
}
5.2 move to the end
Static inline void list_move_tail (structlist_head * List,
Struct list_head * head)
{
_ List_del (list-> Prev, list-> next );
List_add_tail (list, head );
}
6. test whether the project is the last one:
Static inline int list_is_last (conststruct list_head * List,
Conststruct list_head * head)
{
Return list-> next = head;
}
7. test whether the list is empty:
Static inline int list_empty (const structlist_head * head)
{
Return head-> next = head;
}
8. connect two linked lists:
8.1: connect the list linked list to the head of the head linked list:
Static inline void _ list_splice (structlist_head * List,
Struct list_head * head)
{
Struct list_head * First = List-> next;
Struct list_head * Last = List-> Prev;
Struct list_head * at = head-> next;
First-> Prev = head;
Head-> next = first;
Last-> next =;
At-> Prev = last;
}
8.2: Connection
Static inline void list_splice (structlist_head * List, struct list_head * head)
{
If (! List_empty (list ))
_ List_splice (list, head );
}
8.3: Connection and initialization:
Connect the list to the head and initialize the list:
Static inline void list_splice_init (structlist_head * List,
Struct list_head * head)
{
If (! List_empty (list )){
_ List_splice (list, head );
Init_list_head (list );
}
}
9. Some useful macros:
9.1 get list_entry (PTR, type, member)
To put it simply, the role of this macro is:Get the pointer of the structure itself through the pointer (PTR) of a variable (member) in the structure (type.
That is to say,Type contains a member variable member. And the pointer of member in a struct object is PTR. Then list_entry () returns the pointer of this struct object.For how to do this, see background knowledge 3 --- container_of.
9.2: list_first_entry (PTR, type, member)
Returns the next struct object in the PTR linked list.
9.3: list_for_each (Pos, head)
# Define list_for_each (Pos, head )/
For (Pos = (head)-> next; prefetch (POS-> next), pos! = (Head );/
Pos = pos-> next)
It is actually a for loop, with a loop of two-way linked lists.
Prefetch () is a File Cache technology that does not require further research.
The following macros are similar:
_ List_for_each (Pos, head) // loop without the archive Cache Technology
List_for_each_prev (Pos, head) // forward Loop
9.4: list_for_each_entry (Pos, Head, member)
This macro is the most commonly used and useful two-way linked list. Indicates to extract the struct containing this list item (Pos type) one by one from the two-way loop list with head as the header and put it in POS.
# 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 ))
It is very simple because there is a foreshadowing of list_entry () above.
Parameter 1: POS is a struct pointer. This struct contains the member variable member.
Parameter 2: head is a two-way linked list header.
Parameter 3: name of the member variable in the POs struct.
Pos = list_entry (head)-> next, typeof (* POS), member): POS obtains the struct entity contained in the first linked list in a two-way linked list.
& Pos-> member! = (Head): The linked list in this struct is not the header.
Pos = list_entry (POS-> member. Next, typeof (* POS), member): POS obtains the next struct object in a two-way linked list.
Use of two-way circular linked list in Linux kernel:
In the Linux kernel linked list, data that needs to be organized by the linked list usually contains a structlist_head member. The structure is organized in a linked list through this list member.
For example, in a hid-core.c, you want to organize a report linked list.
Therefore, first use
1)
Init_list_head (& device-> report_enum [I]. report_list)
Struct hid_report {
Struct list_head list;
Unsignedid;
Unsignedtype;
Struct hid_field * field [hid_max_fields];
Unsignedmaxfield;
Unsignedsize;
Struct hid_device * device;
};
This means that the data that needs to be organized by a linked list usually contains a struct list_head member.
2 ).
List_add_tail (& Report-> list, & report_enum-> report_list );
Add the report type project to the initialized list.
3 ).
List_for_each_entry (report, & hid-> report_enum [hid_input_report]. report_list, list)
Traverse hid-> report_enum [hid_input_report]. report_list and get the report one by one.
Background:
Background Knowledge 1:Typeof:
Typeof is not a standard C Operator. It is an extension of GCC.
Similar to the sizeof () syntax, sizeof (exp) indicates the return exp length.The exp type returned by typeof (exp.
Example 1:
Int;
Typeof (& A) B;
Because a is of the int type. So & A is int *.
That is, B is of the int * type.
Example 2:
Typedef struct
{
Int size;
Char T;
} Ngate, * pngate;
Typeof (ngate *) 0)-> T) W;
This actually indicates that W type is ngate T type.
Here 0 is not a real variable. It can be understood as an alternative symbol. It can be understood as a variable assigned a value. The number can be either 0 or any number.
Background Knowledge 2: offsetof
The definition in kernel is as follows:
# Define offsetof (type, member) (size_t) & (type *) 0)-> Member)
Similar to the above, (type *) 0 indicates:0 is a pointer to type..
Then & (type *) 0-> Member indicates the address of the member variable 0 of the type object. Because it starts from 0, its address becomes offset. use size_t to force the conversion, that is, the offset from the struct header to the member variable member.
Background 3: container_of (PTR, type, member)
As defined in kernel:
# Define container_of (PTR, type, member )({/
Const typeof (type *) 0)-> member) * _ mptr = (PTR );/
(Type *) (char *) _ mptr-offsetof (type, member ));})
(Type *) 0: indicates that an object belongs to the type.
(Type *) 0)-> Member indicates a member variable of this entity.
Typeof (type *) 0)-> member) * _ mptr indicates thatMember variable typePointer.
Offsetof (type, member) indicates the offset from the member variable member to the Type header of the struct type.
(Type *) (char *) _ mptr-offsetof (type, member)
It indicates that a pointer to type is returned, which points to a type object. The PTR parameter is the position of a Member variable in this entity.
Background 4: RCU (read-copyupdate)
RCU is a new technology introduced in the 2.5/2.6 kernel. It improves synchronization performance through delayed write operations.
In the system, data read operations are much more than write operations, while the rwlock mechanism rapidly declines as the number of processors increases in the SMP environment. To address this background, Paul E. mckenney of the ibmlinux technical center proposed the "read copy Update" technology and applied it to the Linux kernel. The core of RCU technology is that write operations are divided into two steps: Write-update. Read operations are allowed at any time. When the system has write operations, the update operation is delayed until all the read operations on the data are completed.