Linked List in Linux Kernel

Source: Internet
Author: User

A linked list is a commonly used data structure in C programming. For example, to create an integer linked list, it is generally defined as follows:

?

1

2

3

4

struct int_node {

int val;

struct int_node *next;

};

To implement functions such as inserting, deleting, and traversing a linked list, a series of functions must be implemented, such:

?

1

2

3

4

5

6

7

8

9

void insert_node(struct int_node *head, struct int_node *current);

void delete_node(struct int_node *head, struct int_node *current);

void access_node(struct int_node *head)

{

struct int_node *node;

for (node = head; node != NULL; node = node->next) {

// do something here

}

}

If we only have such a data structure in our code, this is certainly not a problem, but when the code size is large enough, we need to manage many types of linked lists, do you need to implement a set of insert, delete, traverse, and other functions for each type of linked list? If you are familiar with C ++, you may say that we can use a standard template library. But here we are talking about C. Is there any better method in C?

Mr. Dave introduced his implementation in his blog. This implementation is a good solution. You may wish to refer to it. In this article, we will focus on the Linux kernel, the largest C Project in the open-source world today, to see how the Linux kernel solves this problem.

A two-way linked list is usually used in Linux kernel and declared as struct list_head. This struct is in include/Linux/types. as defined in H, linked list access is in the form of macros or inline functions in include/Linux/list. h.

?

1

2

3

struct list_head {

struct list_head *next, *prev;

};

The Linux Kernel provides consistent access interfaces for linked lists.

?

1

2

3

4

5

void INIT_LIST_HEAD(struct list_head *list);

void list_add(struct list_head *new, struct list_head *head);

void list_add_tail(struct list_head *new, struct list_head *head);

void list_del(struct list_head *entry);

int list_empty(const struct list_head *head);

The above are just a few common interfaces selected from the Linux kernel. For more definitions, see Linux kernel source code. We will first establish a perceptual knowledge of how the Linux kernel processes linked lists through a simple implementation.

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

#include <stdio.h>

#include "list.h"

struct int_node {

int val;

struct list_head list;

};

int main()

{

struct list_head head, *plist;

struct int_node a, b;

a.val = 2;

b.val = 3;

INIT_LIST_HEAD(&head);

list_add(&a.list, &head);

list_add(&b.list, &head);

list_for_each(plist, &head) {

struct int_node *node = list_entry(plist, struct int_node, list);

printf("val = %d\n", node->val);

}

return 0;

}

After reading this implementation, do you think it is easy to manage a linked list in the C code? List of header files contained in the Code. H is the linked list processing code that I extracted from the Linux kernel and made some modifications. It is now attached here for your reference. You only need to include this header file in your project.

 

# Ifndef _ c_list_h
# DEFINE _ c_list_h
Typedef unsigned char u8;
Typedef unsigned short 2010;
Typedef unsigned int u32;
Typedef unsigned long size_t;
# Define offsetof (type, member) (size_t) & (type *) 0)-> 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) (type *) (char *) PTR-offsetof (type, member ))
/*
* These are non-null pointers that will result in page faults
* Under normal circumstances, used to verify that nobody uses
* Non-initialized list entries.
*/
# Define list_poison1 (void *) 0x00100100)
# Define list_poison2 (void *) 0x00200200)
Struct list_head {
Struct list_head * Next, * Prev;
};
/**
* 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)
# 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;
}
/**
* List_for_each-iterate over a list
* @ Pos: The & struct list_head to use as a loop counter.
* @ Head: The head for your list.
*/
# Define list_for_each (Pos, head )\
For (Pos = (head)-> next; pos! = (Head); Pos = pos-> next)
/**
* List_for_each_r-iterate over a list Reversely
* @ Pos: The & struct list_head to use as a loop counter.
* @ Head: The head for your list.
*/
# Define list_for_each_r (Pos, head )\
For (Pos = (head)-> Prev; pos! = (Head); Pos = pos-> PREV)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only 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;
}
/**
* List_add-Add a new entry
* @ New: New entry to be added
* @ Head: List head to add it after
*
* Insert a new entry after 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 );
}
/**
* List_add_tail-Add a new entry
* @ New: New entry to be added
* @ Head: List head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
Static inline void list_add_tail (struct list_head * New, struct list_head * head)
{
_ List_add (new, head-> Prev, head );
}
/*
* Delete A List entry by making the prev/next entries
* Point to each other.
*
* This is only for internal list manipulation where we know
* The Prev/next entries already!
*/
Static inline void _ list_del (struct list_head * Prev, struct list_head * Next)
{
Next-> Prev = Prev;
Prev-> next = next;
}
/**
* List_del-deletes entry from list.
* @ Entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is
* In an undefined state.
*/
Static inline void list_del (struct list_head * entry)
{
_ List_del (Entry-> Prev, entry-> next );
Entry-> next = list_python1;
Entry-> Prev = list_python2;
}
/**
* List_empty-Tests whether a list is empty
* @ Head: the list to test.
*/
Static inline int list_empty (const struct list_head * head)
{
Return head-> next = head;
}
Static inline void _ list_splice (struct list_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;
}
/**
* List_splice-join two lists
* @ List: the new list to add.
* @ Head: the place to add it in the first list.
*/
Static inline void list_splice (struct list_head * List, struct list_head * head)
{
If (! List_empty (list ))
_ List_splice (list, head );
}
# Endif/_ c_list_h

Generally, list_head is embedded in the data structure. In the above implementation, we take the integer linked list as an example. The definition of int_node is as follows:

?

1

2

3

4

struct int_node {

int val;

struct list_head list;

};

Shows the structure of the linked list organized by list_head:

The list_for_each macro is used to complete a traversal table.

?

1

2

3

#define list_for_each(pos, head) \

for (pos = (head)->next; prefetch(pos->next), pos != (head); \

pos = pos->next)

Here, both POs and head are struct list_head. If you need to access the Node during traversal, you can use list_entry to obtain the base address of the node.

?

1

2

#define list_entry(ptr, type, member) \

container_of(ptr, type, member)

Let's take a look at how container_of is implemented. As shown in, we already know the address of the member in the type structure. To get the address of this struct, you only need to know the offset of the member in the struct. How can I get this offset address? Here we use the C language tips. We may as well project the struct to a place where the address is 0, so the absolute address of the member is the offset. After obtaining the offset, you can easily calculate the structure address based on the address pointed by the PTR pointer.

List_entry is the type struct we need from the PTR pointer through the above method.

The Linux kernel code is profound and profound. Teacher Chen Lijun once described it as "over three hundred years of pressure, isolated Days" (from "A house Palace Fu"), showing its rich content and complex structure. There are many important data structures in the kernel, and many of the correlated data structures are organized together using the linked list described in this article. It seems that the list_head structure is small and has a great effect.

The Linux kernel is a great project, and there are many subtleties in its source code. It is worth reading carefully by C/C ++ programmers, even if we do not do kernel-related work, reading the wonderful code is also of great benefit to the improvement of the programmer's self-cultivation.

List definition in kernel: http://lxr.oss.org.cn/source//include/linux/list.h? V = 2.6.30

Original article: http://www.cnblogs.com/wwang/archive/2010/11/28/1889281.html

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.