Introduction to the linked list:
A linked list is a common data structure that connects a series of data nodes into a single data chain through pointers . Relative to the array, the linked list has better dynamic, the establishment of the linked list without knowing the total amount of data, you can randomly allocate space, you can effectively in the linked list anywhere in real-time insert or delete data. the cost of a linked list is primarily the order of access and the loss of space in the organization chain.
The good main embodiment of the core list is two points, 1 is scalability, and 2 is encapsulation. Scalability is definitely a must, the kernel has always been in development, so the code can not be written dead code, to facilitate the modification and append. the operations that are common to the list are encapsulated, and the user is focused on the interface without needing to focus on the implementation. Analyze the list of links in the kernel we What can be done? I think it can be reused in the user programming, in the future in the user-state programming will not need to write some of the linked list of code, directly to the kernel list.h code in the copy. You can also sort out the my_list.h and include it directly in the C file in future user-state programming.
1. Link list comparison
Traditional linked list and kernel linked list
Traditional linked list: Generally refers to a one-way linked list
struct List
{
struct list *next;//linked list node pointer field
};
Core list: two-way loop list design is designed to design a universal unified doubly linked list!
struct List_head
{
struct List_head *head, *prev;
};
The List_head structure contains two pointers to the list_head struct body
Prev and Next, this shows that the core list has a doubly linked list function, in fact, it is usually organized into a two-way circular linked list
2. Kernel Linked list use
1. Init_list_head: Creating a linked List
2. List_add: Inserting nodes in the linked list header
3. List_add_tail: Inserting nodes at the end of a chain
4. List_del: Deleting nodes
5. List_entry: Remove the node
6. List_for_each: Traversing a linked list
(If we do not know the parameters of these functions and the internal implementation of the function, learn to check the parameters of these functions or the best way to implement the code or directly to see the kernel source, the knot and the front of the Sourceinsight tool directly search for the names of these functions)
Here's an example: for example , check the Init_list_head function,
This is the first to import the kernel source code sourceinsight project inside! The source code can be downloaded on the official website, then unzipped under Linux (file name Linux is case-insensitive, Windows is case-insensitive), and then through Samba and mapped network drive features (mentioned in the previous Sourceinsight blog), Click on the icon to the left of the R icon (like an open book)
This can be quickly viewed in the Code Implementation section: in the kernel mkregtale.c file
/* * Doubly linked list implementation that matches the * * The Linux kernel doubly linked list Impleme Ntation works. */struct list_head {struct list_head *next;/* Next in Chain */struct list_head *prev;/* Previous in Chain */};
This linked list without data fields can be embedded in any data structure, for example, a linked list containing data fields can be defined as follows:
struct Score{int num;int english;int math;struct list_head list;//chain link Link field};struct list_head score_head;//Linked list header
Init_list_head (&score_head);Initialize the chain header to complete the creation of a two-way circular linked list
the red section above initializes an already existing List_head object,score_head as a pointer to a struct, which initializes the stack and the score_head object defined by the global zone. Call the Init_list_head () macro to initialize the list node and point the next and prev pointers to themselves, and we construct an empty double-loop list.
Initialize an empty list: In fact, it is the linked list head, to point to the first node! Define nodes and initialize! And then the two-way loop linked list was born.
Static is added to the function, indicating that the function is a static function, which is actually a scope limitation, meaning that the function scope is limited to this file only. Therefore, static has the function of information concealment. The function that adds the inline keyword before the function, called an inline function, means that the compiler expands the function immediately when it calls the function.
/* Initialise A list head to an empty list */static inline void init_list_head (struct list_head *list) { List->next = List;list->prev = list;}
List_add: Inserting nodes in the linked list header
/** * List_add-add A new entry * @new: new entry to being added * @head: List head to add it after * * Insert a new entry a fter the specified head. * This is good for implementing stacks. */static inline void List_add (struct list_head *new, struct list_head *head) { __list_add (new, head, Head->next);}
/* * Insert A new entry between, known consecutive entries. * * This was only for internal list manipulation where we know * the Prev/next entries already! */#ifndef config_debug_liststatic 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;} #elseextern void __list_add (struct list_head *new, struct list_head *prev, struct list_head *next); #endif
List_add_tail: Inserting nodes at the end of a list
/** * List_add_tail-add A new entry * @new: new entry to being added * @head: List head to add it before * * Insert a new E Ntry before the specified head. * This was useful for implementing queues. */static inline void List_add_tail (struct list_head *new, struct list_head *head) { __list_add (new, Head->prev, Head);}
Usage examples:
struct SCORE
{
int num;
int 中文版;
int math;
struct List_head list;//chain link Links field
};
The linked list header of the linked list created by the struct List_head score_head;//
Define three nodes and insert them into the list
struct score stu1, STU2, STU3;
List_add_tail (& (Stu1.list), &score_head); Using the tail interpolation method
every two-cycle linked list of Linux has a list header, which is also a node, except that it is not embedded in the host data structure, that is, the linked header cannot be used to locate the corresponding host structure, but it can get the virtual host structure pointer .
List_del: Deleting nodes
/* Take a element out of the It current list, with or without * reinitialising the links.of the entry*/static inline void Li St_del (struct list_head *entry) {struct List_head *list_next = entry->next;struct list_head *list_prev = entry-> Prev;list_next->prev = List_prev;list_prev->next = List_next;}
List_entry: Remove Node
/** * List_entry-get The struct for this entry * @ptr: the &struct list_head pointer. * @type: The type of the struct this is embedded in. * @member: The name of the list_struct within the struct. */#define LIST_ENTRY (PTR, type, member) container_of (PTR, type, member)
/** * Container_of-cast A member of a structure out to the containing structure * @ptr: The pointer to the member. * @type: The type of the container struct this is embedded in. * @member: The name of the member within the struct. * * /#define CONTAINER_OF (PTR, type, member) ({ const typeof (((type *) 0)->member) *__mptr = (PTR); (Type *) ((char *) __mptr-offsetof (type, member)); })
List_for_each: Traversing a linked list
#define List_for_each (POS, head) for (pos = (head)->next; prefetch (pos->next), pos! = (head); pos = pos->next) </span></span>
As you can see, using the auxiliary pointer Pos,pos is started from the first node and does not have access to the head node .end until POS reaches head node pointer head. And this traversal is only to find the current position of a node, how to get the address of the starting node through POS, so that the node can be referenced to the domain? List_entry macros defined in List.h: #define List_entry (PTR, type, member) \ ((Type *) ((char *) (PTR) -(unsigned Long) (& (Type *) 0))) Analysis: (unsigned Long) (& ((type *) 0), Memb ER) converts the 0 address into a pointer to the type structure and obtains a pointer to the member field in the structure, which is the offset of the member in the type structure. WHERE (char *) (PTR) is the absolute address of the PTR, the two are subtracted, so that the start address of the type struct, that is, the address of the starting node. The use of the method is very clever!For example, the following usage:
struct score stu1, STU2, STU3;
struct List_head *pos; Define a node pointer
struct score *tmp; Define a score struct variable
Traversing the entire list, each iteration prints out the data List_for_each (POS, &score_head)//The POS here will automatically be assigned a new value {tmp = List_entry (pos, struct score, list); PRINTK (kern_warning "num:%d, 中文版:%d, Math:%d\n", Tmp->num, Tmp->english, Tmp->math);}
List_for_each_safe: Release of linked list
/** * List_for_each_safe-iterate over a list safe against removal for list entry * @pos: The &struct list_head to use As a loop cursor. * @n:another &struct List_head to use as temporary storage * @head: </span>the head for your list. */#define LIST_FOR_EACH_SAFE (POS, N, head) for (pos = (head)->next, n = pos->next; pos! = (head); pos = N, n = pos->next)
3. Kernel Chain list Implementation analysis
4. Porting the kernel list (this is a small kernel module that uses the kernel list)
MYLIST.C file
#include <linux/module.h> #include <linux/init.h> #include <linux/list.h>//contains the kernel link header file struct score{ int num;int english;int math;struct list_head list;//chain link field};struct list_head score_head;//linked list of linked lists//define three nodes Then insert into the list of structs score stu1, STU2, stu3;struct list_head *pos;//Define a node pointer struct score *tmp;//define a score struct variable int mylist_init () {init_list_head (&score_head);//Initialize the chain header to complete the creation of a two-way circular linked list stu1.num = 1;stu1. 中文版 = 59;stu1.math = 99;//Then insert three nodes into the list List_add_tail (& (Stu1.list), &score_head);//Use the tail interpolation method stu2.num = 2;stu2. 中文版 = 69;stu2.math = 98;list_add_tail (& (Stu2.list), &score_head); stu3.num = 3;stu3. English = 89;stu3.math = 97;list_add_tail (& (Stu3.list), &score_head);//traverse the entire list, each time the data is printed List_for_each (POS, &score_head)//The POS here will automatically be assigned a new value {tmp = List_entry (pos, struct score, list);p RINTK (kern_warning "num:%d, English:%d, Math:%d\n ", Tmp->num, Tmp->english, Tmp->math);} return 0;} void Mylist_exit () {//Exit Delete node List_del (& (Stu1.list)) List_del (& (STU2.LIST));p rintk (kern_warning "MyList exit!\n");} Module_init (Mylist_init); Module_exit (Mylist_exit);
Makefile File
Obj-m: = Mylist.okdir: =/home/kernel/linux-ok6410all:make-c $ (kdir) m=$ (PWD) modules cross_compile=arm-linux-arch= Armclean:rm-f *.o *.ko *.order *.symvers
To load a running kernel module on a terminal:
There will be a mistake when rmmod here! But no big deal! Baidu has a lot of solutions!
Linux Kernel list Depth analysis