Interesting data structure--linux the chain list in the kernel __adobe

Source: Internet
Author: User
Tags data structures prev

Turn from: http://blog.csdn.net/yanook/article/details/7199513


There are many kinds of lists in the Linux kernel, if each kind of linked list uses the separate data structure to represent, then needs to implement a set of primitive operations to each list, including initialization, inserts, deletes and so on. The Linux kernel then defines a very interesting data structure: List_head struct List_head {
struct List_head * Next, * prev;
}; Copy Code

At first glance this definition seems very common, but it's wonderful in general. Often our approach is to embed data into the nodes of a linked list, similar to the following definition: struct List_node {
Data_type data;
List_node * Next, * prev;
Copy Code

The schematic diagram is as follows:


But, instead, embed the linked list node in the data structure: struct Data_type {
Data
List_head;
Copy Code

The schematic diagram below (which adds a dummy):

In this list, all the basic operation of the linked list is for the List_head data structure, rather than for the data structure containing list_head, so no matter what data, linked list operations are unified. So, now there is a problem, because all linked list operations refer to pointers to list_head data structures, rather than the contained structure, then how to get the address of the data structure containing it from list_head addresses. Let's look at the List_entry (P,T,M) macro in the Linux kernel: #define List_entry (PTR, type, member) \
Container_of (PTR, type, member) copy code

Tracking to CONTAINER_OF macros: #define CONTAINER_OF (PTR, type, member) ({\
Const typeof ((type *) 0)-> member) * __mptr = (PTR); \
(Type *) ((char *) __mptr-offsetof (Type,member));} Copy Code

This offsetof does not need to track, we can understand the meaning of the macro. First of all, a simple description of the three parameters of the macro. PTR is a pointer to the List_head data structure, type is the container data structure, and member is the name of the List_head in type. Look directly at the following sample code: struct data{
xxx
List_head List1;
List_head List2;
xxx
};
struct Data Vardat = {initialize};
List_head * p = & vardat.list1;
List_head * q = & vardat.list2;

List_entry (p, struct data, list1) = = & Vardat;
List_entry (q, struct data, list2) = = & Vardat; Copy Code

As you can see from the example above, Vardat can be hung on two (or more) lists at the same time, where List1 is a node on the first list, List2 is the node on the second list, and &list2 can be obtained from &list1 and Vardat, The problems raised above are solved.
Before skipping the OFFSETOF this macro, I believe that a lot of readers will be interested in this macro, then we now see how the macro is implemented. Tracking this macro will find that there are two definitions, one is __compiler_offsetof (a,b), continue to trace the __builtin_offsetof (a,b), which is not seen; we see another definition: #define OFFSETOF (TYPE, Member) ((size_t) & ((TYPE *) 0)->member)

After looking at it, it turned out to be so simple, put a type of pointer to 0, its member nature is offset, Miao.
Summarize the advantages of this list:(1) All the basic operation of the linked list is based on the List_head pointer, so when adding type, do not need to repeat the basic operation function of the linked list (2) a container data structure can contain multiple List_head members so that it can be linked to several different lists at the same time. , for example, the Linux kernel will have the process data structure (TASK_STRUCT) at the same time linked to the task list, priority list, and many other linked lists, there will be more instructions below.
Look at the basic operation of the list of linked lists provided in the Linux kernel (list_head *): List_add (new, head); Inserts new behind the head element
List_add_tail (new, head); Well, there's no need to explain the difference, but the head here is the real list.
List_del (entry); Delete Entry node
List_empty (head); Check for empty linked lists
List_entry (PTR, type, member); I explained it earlier.
List_for_each (POS, head); Iterate through the list, each loop is returned through the POS node List_head pointer
Here's the most useful.
List_for_each_entry (POS, head, member); Ditto, but returned through POS is the address of the container data structure. Copy Code

Slow. Found a problem, list_entry need type, why list_for_each_entry do not need it. Simple, POS is you give a container data structure of the pointer, in the implementation of the macro, with typeof (*pos) to get type.
Let's look at the task_struct in Linux, which holds the process information and only looks at the linked list: struct Task_struct {
xxxxxxx
struct Hlist_head preempt_notifiers;
struct List_head rcu_node_entry;
struct List_head tasks;
struct List_head children; /* List of my children * *
struct List_head sibling; /* Linkage in my parent ' s children list */
struct List_head ptraced;
struct List_head ptrace_entry;
struct List_head thread_group;
There are a lot of list, do not copy ...
Copy Code

Where tasks are linked lists of all processes, you can use this macro to traverse all processes: #define FOR_EACH_PROCESS (P) \
for (p = & init_task; (p = next_task (P))!= & Init_task; )
#define NEXT_TASK (P) \
List_entry ((p)-> tasks.next, struct task_struct, tasks) copying code is not cool.
------------------------Digress------------------------The author encountered such a list implementation while doing MIT's operating system experiment Jos, the following is an example of the use given in its code: struct FROB
{
int Frobozz;
List_entry (Frob) Frob_link; /* This contains the list element pointers * *
};

List_head (Frob_list, Frob)/* defines struct frob_list as a list of Frob * *

struct Frob_list flist; /* Declare a Frob list * *

List_init (& Flist); /* Clear Flist (Globals are cleared anyway) * *
Flist = List_head_initializer (& flist); /* Alternate way to clear flist * *

if (List_empty (& flist))/* Check whether LIST is EMPTY * *
printf ("list is empty\n");

struct Frob * f = list_first (& flist); /* f is-a-in-list * *
f = List_next (f, frob_link); /* now F. Next (second) element in list */
f = List_next (f, frob_link); /* now F. Next (third) element in list */

for (f = list_first (& flist); f!= 0; /* Iterate over elements in Flist * *
f = List_next (f, Frob_link))
printf ("F%d\n", F-> frobozz);

List_foreach (f, & Flist, Frob_link)/* Alternate way to say that * * *
printf ("F%d\n", F-> frobozz);

f = List_next (List_first (& Flist)); /* F is second element in list * * *
List_insert_after (f, G, frob_link); /* Add G right after F in list * *
List_remove (g, frob_link);  /* Remove G from list (can ' t insert twice!) */
List_insert_before (f, G, frob_link); /* Add G right before f * *
List_remove (g, frob_link); /* Remove g again * *
List_insert_head (& Flist, G, frob_link); /* Add g as the in list * *
Copy Code

It can be seen that the usage here is similar to the Linux kernel, with a set of macros can be used to operate a variety of linked lists, but carefully read the relevant macro code found that it and the Linux kernel of the list_head has a big difference, it is more like C + + template, in the compile time, Generates the appropriate code for each list.

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.