Linux Linked list Operation __linux

Source: Internet
Author: User

In the study of the Linux kernel with the dmatest.c driver process found that some of the link operation, very confusing, so the record down some of the information after the experience. 0 The characteristics of the core linked list

Common linked list operations, usually containing data fields and pointer fields 2 contents are shown below.

typedef struct Node

{

Elemtype data; Data fields

struct Node *next; Pointer field

node, *list;

The Linux kernel defines a linked list with no data fields, and requires only two pointers to complete the operation of the linked list. It has very high expansibility and universality. The list structure is defined as shown below.

struct List_head {

struct List_head *next, *prev;

};

There are usually definitions of the following format, and it is generally recommended to combine containner_of and offset_of to gain greater flexibility and maneuverability. For example, you can find the starting address of the app_info from the address of App_info_head, that is, the starting address of a complete app_info structure.

typedef struct APPLICATION_INFO

{

uint32_t app_id;

uint32_t Up_flow;

uint32_t Down_flow;

struct List_head app_info_head; Linked list node

}app_info;

1 Linked list operation and realization principle

(1) Initialization of the Chain header node

The effect of initialization is to make both the predecessor and the successor pointer point to the header node.

Here you need to be very careful about the interface of INIT (at first you didn't notice the code that led to the error understanding) List_head_init, List_head, and Init_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;

}

So there are two different uses. One is a macro extension and the other is a function call.

Way One

static struct info_t{

struct List_head channels;

}Info = {

. Channels = list_head_init(info. Channels);

}

Mode two

Init_list_head(&info. Channels);

(2) Insert operation

List_add and List_add_tail are inserted in the table head and the end of the table, but are implemented through the __list_add, because the core implementation of the linked list is a two-way list, so Head->prev is the end of the table, and after the Head->next is the head of the table. The kernel is implemented as shown in the following table.

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;

}

static inline void List_add(struct list_head *new, struct list_head *head)

{

__list_add(new, head, head->next);

}

static inline void List_add_tail(struct list_head *new, struct list_head * Head)

{

__list_add(new, head->prev, head);

}

(3) Delete operation

List_del, the predecessor and successor node of the node are deleted. Note that the deletion also requires that the predecessor and successor of the node to be deleted be pointed to POSITION1 and POSITION2 respectively. Operations on both POSITION1 and POSITION2 will cause page failures.

static inline void __list_del(struct list_head * prev, struct list_head * next) /c4>

{

Next->prev = prev;

Prev->Next = next;

}

static inline void List_del(struct list_head *entry)

{

__list_del(entry->prev, entry->next);

Entry->next = list_poison1;

Entry->prev = list_poison2;

}

/*

* These are 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) Judgment list

Whether null (LIST_EMPTY) is the last node (list_is_last).

/**

* List_is_last-tests Whether @list is the last entry in list @head

* @list: the entry to test

* @head: The head of the list

*/

static inline int list_is_last(const struct List_head *list,

const struct List_head *head)

{

return list->Next = head;

}

/**

* 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;

}

(5) Traverse list

Note that List_for_each is just a macro substitution.

/**

* List_entry-get the struct for this entry

* @ptr: The &struct list_head pointer.

* @type: The type of the struct this are embedded in.

* @member: The name of the list_struct within the struct.

*/

#define List_entry (PTR, type, member) \

Container_of (PTR, type, member)

/**

* List_first_entry-get the "a" list

* @ptr: The "list head" to take the element from.

* @type: The type of the struct this are embedded in.

* @member: The name of the list_struct within the struct.

*

* Note, the list is expected to being not empty.

*/

#define List_first_entry (PTR, type, member) \

List_entry ((PTR)->next, type, member)

/**

* List_for_each-iterate over a list

* @pos: The &struct list_head to use as a loop cursor.

* @head: The head for your list.

*/

#define List_for_each (POS, head) \

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

pos = pos->next)

You often need to use container_of and offset when traversing, such as List_for_each_entry (POS, head, member), which is to traverse the head list, and the head list pointer type is member (string), Member is one of the members of the POS type structure, and then the structure body pointer is obtained based on container_of. [This technique is often found in kernel source code] 2 Examples of the use of linked lists

The following is an example of dmatest.c. Requirements: The DMA test program needs to implement multiple channels, and the channel supports multiple threads and requires support to access each other.

First, because the requirements are accessed each other, the struct member variable is immediately thought of as shown in the following code.

struct channel_t{

struct thread_t used[m];

}

struct info_t{

struct channel_t used[m];

};

static struct info_t info;

However, the disadvantage is also obvious, the application of fixed size space, either waste resources, or insufficient resources. Write to this, you can immediately launch the use of linked lists, but the core provided by the list does not have data fields are pointer fields, how to design a key.

Here, DMATEST.C gives the reference answer by adding a node node to each member as the mediation node. as shown below.

struct thread_t {

    struct List_head node ;

}

 

struct channel_t {

    struct List_head node ;

    struct List_head threads ;

}

 

struct info_t {

    struct LIST_ Head channels ;

};

 

Static info_t Info =

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.