1. Preface
Recently written code needs to be linked to the list structure, just the public library has about the linked list. At first glance, I felt a bit fresh, unlike the list structure I saw before, with only precursors and successors, and no data fields. Later read the code comment found that the code from the Linux kernel, under the Linux source code under INCLUDE/LISH.H. This list is versatile and easy to use. It is only necessary to define a list structure in the structure to be used.
2. Introduction of Chain List
Linked list is a very basic data structure, according to the number of links into a single linked list, double linked list, according to whether the loop is divided into unidirectional linked lists and circular linked lists. Usually the definition defines the list structure as follows:
typedef struct node{ elemtype data; Data domain struct node *next; Pointer field}node, *list;
The linked list contains data fields and pointer fields. A linked list usually contains a head node that does not hold data and facilitates the operation of the list. The unidirectional circular linked list structure is as shown:
The two-way circular linked list structure looks like this:
Such a linked list with data field reduces the generality of the list and is not easy to expand. The list structure defined by the Linux kernel does not have a data field and requires only two pointers to complete the operation of the linked list. The link list node joins the data structure, has the very high expansibility, the universality. The list structure definition is as follows:
struct List_head { struct list_head *next, *prev;};
The list structure is as follows:
When you need to use a linked list structure, you only have to define a list type of data in the struct. For example, define a app_info linked list,
1 typedef struct APPLICATION_INFO2 {3 uint32_t app_id;4 uint32_t up_flow;5 uint32_t down_ flow;6 struct list_head app_info_head; Linked list node 7}app_info;
Define a App_info linked list, App_info app_info_list, and chain list operations through App_info_head. According to the C language pointer operation, through CONTAINER_OF and offsetof, you can find the starting address of app_info according to the address of App_info_head, that is, the starting address of a complete ap_info structure. can refer to: http://www.cnblogs.com/Anker/p/3472271.html.
3, Linux kernel chain list implementation
The kernel implements a two-way loop linked list, which provides the basic functions of the list operation.
(1) Initializing the node of the linked list head
#define LIST_HEAD_INIT (name) {& (name), & (name)} #define LIST_HEAD (name) struct List_head name = List_head_ INIT (name) static inline void Init_list_head (struct list_head *list) { list->next = LIST; List->prev = list;}
The List_head macro creates a chain header node and assigns it to the list_head_init, making the head and the successor point to themselves.
The Init_list_head function initializes the linked list so that the precursor and the subsequent pointer pointers point to the head node.
(2) Inserting a node
1 static inline void __list_add (struct list_head *new, 2 struct List_head *prev, 3 struct List_head *next) 4 {5
next->prev = new; 6 new->next = Next; 7 new->prev = prev; 8 prev->next = new; 9}10 one static inline void List_add (Stru CT list_head *new, struct list_head *head) {__list_add (new, head, Head->next),}15-static inline void lis T_add_tail (struct list_head *new, struct list_head *head) : {__list_add (new, Head->prev, head); 19}
The insertion node is divided into List_add from the head of the list and inserted into the tail of the list list_add_tail, by calling the __list_add function to implement, Head->next points to a node, Head->prev points to the tail node.
(3) Deleting a node
1 static inline void __list_del (struct list_head * prev, struct list_head * Next) 2 {3 next->prev = prev; 4 PR Ev->next = Next; 5} 6 7 static inline void List_del (struct list_head *entry) 8 {9 __list_del (Entry->prev, entry->next); 10
entry->next = list_poison1;11 Entry->prev = list_poison2;12}
Deleting a node from a linked list requires changing the predecessor node of the predecessor node of the node and subsequent nodes. Finally, the node's precursor and subsequent nodes are set to point to List_position1 and list_position2 two special values, which are set to ensure that node entries not in the list are inaccessible to List_position1 and List_ POSITION2 Access will cause page failure
/* * These is non-null pointers that would result in page faults * Under normal circumstances, used to verify that nobody Uses * non-initialized list entries. */#define List_poison1 ((void *) 0x00100100 + poison_pointer_delta) #define List_poison2 ((void *) 0x00200200 + Poison_pointer_delta)
(4) Mobile node
1/** 2 * List_move-delete from a list and add as another ' s head 3 * @list: The entry to move 4 * @head: T He head that would precede our entry 5 */6 static inline void List_move (struct list_head *list, struct list_head *head ) 7 {8 __list_del (List->prev, List->next), 9 list_add (list, head),}11,/**13 * list_move_tail-de Lete from a list and add as another ' s tail14 * @list: The entry to MOVE15 * @head: The head that would follow our ENTRY16 */17 static inline void List_move_tail (struct list_head *list,18 struct list_head *head) List_del (List->prev, list->next); list_add_tail (list, head); 22}
Move moves a node to the head or tail.
(5) Judging the chain list
1/** 2 * list_is_last-tests Whether @list is the last entry on List @head 3 * @list: The entry to test 4 * @head: The head of the list 5 */6 static inline int list_is_last (const struct List_head *list, 7 const struct LIS T_head *head) 8 {9 return list->next = = Head;10}11 [/**13] list_empty-tests Whether a list is Empty14
* @head: The list to test.15 */16 static inline int list_empty (const struct List_head *head) ~ { return head-& Gt;next = = head;19}
The List_is_last function determines whether the node is the end node, List_empty determines whether the linked list is empty.
(6) Traversing linked list
1/** 2 * list_entry-get the struct for this entry 3 * @ptr: The &struct list_head pointer. 4 * @type: The type of the struct this is embedded in. 5 * @member: The name of the list_struct within the struct. 6 */7 #define LIST_ENTRY (PTR, type, member) 8 container_of (PTR, type, member) 9/**11 * List_first_entry-get The first element from a list12 * @ptr: The list head to take the element from.13 * @type: The type of the struct This is embedded in.14 * @member: The name of the list_struct within the struct.15 *16 * Note, which list is expecte D to is not empty.17 */18 #define List_first_entry (PTR, type, member) List_entry ((PTR)->next, type, member) 20 2 1/**22 * List_for_each-iterate over a list23 * @pos: The &struct list_head to use as a loop cursor.24 * @head: The head for your list.25 */26 #define List_for_each (POS, head) (pos = (head)->next; prefetch (PO S->next), pos! = (head); 28 pos = pos->next)
Macro List_entity Gets the structure of the linked list, including the data fields. List_first_entry gets the first node of a list, including the data source. List_for_each a macro to traverse a linked list node.
4. Test examples
Write a simple program that uses a linked list to master the use of linked lists.
Customizing a similar list structure is as follows: Mylist.h
1 # define POISON_POINTER_DELTA 0 2 3 #define LIST_POISON1 ((void *) 0x00100100 + Poison_pointer_delta) 4 #define List_ POISON2 (void *) 0x00200200 + Poison_pointer_delta) 5 6//calculates the position of member in Type 7 #define OFFSETOF (type, member) (size_t) ( & ((type*) 0)->member) 8//Based on member address get the start address of type 9 #define CONTAINER_OF (PTR, type, member) ({Ten Co NST typeof (((type *) 0)->member) *__mptr = (PTR); One (Type *) ((char *) __mptr-offsetof (type, member)); }) 12 13//list structure of the struct LIST_HEAD15 {list_head-struct-*prev;17 struct list_head *next;18};19-Static inline void Init_list_head (struct list_head *list) {List->prev = list;23 List->next = list;24}25-Static in line void __list_add (struct list_head *new,27 struct list_head *prev, struct list_head *next) (prev->next = new;30 New->prev = prev;31 New->next = next;32 Next->prev = new;33}34 35//Add the static inline V from the head OID List_add (struct list_head *new , struct List_head *head) Notoginseng {__list_add (new, head, Head->next); 39}40//Add from tail to static inline void List_add_tai L (struct list_head *new, struct list_head *head), __list_add (New, Head->prev, head),}45, static inline V OID __list_del (struct list_head *prev, struct list_head *next), {prev->next = next;49 Next->prev = prev; }51 List_del (struct list_head *entry) (__list_del, Entry->prev): 55 Entry->next = list_poison1;56 Entry->prev = list_poison2;57}58, static inline void List_move (struct List_hea D *list, struct List_head *head) {__list_del (List->prev, List->next); List_add (list, head); 63 }64 of static inline void List_move_tail (struct list_head *list,66 struct List_head *head) 67 {68 __list_del (List->prev, List->next); List_add_tail (list, head),}71 #define List_entry (PTR, type, M Ember) Container_Of (PTR, type, member) #define LIST_FIRST_ENTRY (PTR, type, member) List_entry ((PTR)->next, type, member) 76 7 7 #define List_for_each (POS, head) for (pos = (head)->next; pos! = (head); pos = pos->next)
The mylist.c is as follows:
1/** @brief Practice using the Linux kernel list, features include: 2 * Define linked list structure, create linked list, insert node, delete node, move node, traverse node 3 * 4 * @auther Anker @date 2013-12-15 5 **/6 #in Clude <stdio.h> 7 #include <inttypes.h> 8 #include <stdlib.h> 9 #include <errno.h>10 #include "myl Ist.h "11//Definition APP_INFO list structure typedef struct APPLICATION_INFO13 {uint32_t app_id;15 uint32_t up_flow;16 UIn t32_t down_flow;17 struct list_head app_info_node;//linked list node}app_info;19 app_info* get_app_info (uint32_t app_ ID, uint32_t up_flow, uint32_t down_flow), {app_info *app = (app_info*) malloc (sizeof (app_info)), if (app = = NULL) fprintf (stderr, "Failed to malloc memory, errno:%u, reason:%s\n", errno, Strerror (errno)); 28 return null;29}30 app->app_id = app_id;31 App->up_flow = up_flow;32 App->down_flow = Down_f low;33 return app;34}35 static void For_each_app (const struct list_head *head) [PNS] List_head *pos;38 App_info *app;39//Traverse the list of List_for_each (POS, head) for the "List_entry" (POS, App_info, App_info_node), and printf ("AP_ID:%u\ Tup_flow:%u\tdown_flow:%u\n ", app->app_id, App->up_flow, App->down_flow);}47}48 $ void de Stroy_app_list (struct List_head *head) {Wuyi List_head *pos = head->next;52 struct List_head *tmp = NULL , pos->next;56 (pos! = head), {in. tmp = List_del (POS); + pos = tmp;58}59}60 T Main () 63 {64//Create a app_info65 app_info * app_info_list = (app_info*) malloc (sizeof (App_info)); App_info *ap p;67 if (app_info_list = = NULL) fprintf (stderr, "Failed to malloc memory, errno:%u, reason:%s\n", 70 errno, Strerror (errno)); return-1;72}73//Initialize the list head: List_head *head = &APP_INFO_LIST-&G T;app_info_node;75 Init_list_head (head); 76//Insert three app_info77 app = Get_app_info (1001, +); _tail (&app->app_iNfo_node, head), app = Get_app_info (1002, N), List_add_tail (&app->app_info_node, head), Bayi app = Get_app_info (1003, N, +), List_add_tail (&app->app_info_node, head), ("After insert three AP P_info: \ n "); For_each_app (head); 85//Move the first node to the end of printf (" Move primary node to tail:\n "); List_move_tai L (Head->next, head); For_each_app (head); 89//delete the last node ("delete", "node:\n"); List_del (Head->prev); For_each_app (head), Destroy_app_list (head), 94 free (app_info_list), and 0;96}
The test results are as follows:
Linked list of Linux kernel data structures