[Principle Analysis]linux The chain list principle in the kernel practice [3]

Source: Internet
Author: User

Summary:

The first [one, two] series of topics in this article are linked list operation, content or pointer operation, this paper illustrates the next pointer operation through a list of links. It involves not only data node pointers, but also function pointers, and finally the function body optimization based on pointers.

Body:

This article focuses on node deletion operations in a linked list, and uses callback functions during the removal process. The callback function itself is simple enough to determine whether the data node is deleted by judging the singularity or even the parity of the data in the current node.

#include "stdafx.h" #include <memory>typedef struct node{int value;node* next;} node;typedef BOOL (* condvalid) (node* stu), bool Pickeven (node* N) {if ((n->value)% 2 = = 0) return True;return false;} BOOL Pickodd (node* N) {if ((n->value)% 2 = = 1) return True;return false;} node* AddNode (node* head, int value) {if (head! = NULL) {node* n = new node (); n->value = Value;n->next = head->next; Head->next = n;} Else{head = new node (); head->next = Null;head->value = value;} return head;} node* Delnode (node* head, Condvalid validremove) {node* prev;node* cur;for (prev = NULL, cur = head; cur;) {node* Const NEXT = cur->next;if (Validremove (cur)) {if (prev) {prev->next = next;} Else{head = Next;} Free (cur);} Else{prev = cur;} cur = next;} return head;} void Showlist (node* head) {for (; head; head=head->next) printf ("%d", Head->value);p rintf ("\ n");} void Testadd () {node* head = Null;head = AddNode (Head, 2), head = AddNode (Head, 3), head = AddNode (Head, 5), head = AddNode (He AD, 6); Showlist (hEAD); It should show 2, 6, 5, 3;} void Testdel () {node* head = Null;head = AddNode (Head, 2), head = AddNode (Head, 3), head = AddNode (Head, 5), head = AddNode (He AD, 6); Showlist (head); It should show 2, 6, 5, 3;node* head1 = Delnode (head,pickeven);p rintf ("After Delnode using isevensel:\n"); Showlist (head1 ); It should show 5, 3;node* head2 = Delnode (Head1, pickodd);p rintf ("After Delnode using isoddsel:\n"); Showlist (head2); It shoud show nothing.} int _tmain (int argc, _tchar* argv[]) {//testadd (); Testdel (); GetChar (); return 0;} </span>

The above Delnode function should be noted in the For statement: 1.for (prev = NULL, cur= head; cur;) {There is no immediate follow-up to the common cur=cur->next;2. The cur->next is saved from the beginning of the loop, and the reason for 1 and 2 is that cur the current node may be deleted in the loop. The only disadvantage of the above delnode is that each time a head node needs to be returned, how do we not return the changed head value? Very straightforward we will think of pointers. So, we pass the head address as a parameter, the specific code is as follows:

void DelNode2 (node** head,  condvalid validremove) {node** cur;node* entry;for (cur=head;*cur;) {entry = *cur;if (Validremove (entry)) {*cur = Entry->next;free (entry);} Else{cur = &entry->next;}}} void TestDel2 () {node* head = Null;head = AddNode (Head, 2), head = AddNode (Head, 3), head = AddNode (Head, 5), head = AddNode (h EAD, 6); Showlist (head); It should show 2, 6, 5, 3;delnode2 (&head,pickodd);   Showlist (head); It should shoe 2, 6;}

The key to the above code is that *cur = Entry->next is covered, and Cur=&entry->next is mobile, and the specific process can refer to:


There are four data nodes: A1, A2, A3, A4; Let's say we're going to remove A1 and A3 in each step, resulting in the cur change process.

Now let's look at a pointer-based optimization, The code picked from the previous version of the network part of linux2.6, here do not need to understand the code behind the network principle, only need to code on the code to understand the principles contained in the optimization, then first look at the following example code (Linux Zhongyuan Code simplified implementation):

for (ptype = ptype_base; PType! = NULL; ptype = ptype->next)  {if (Ptype->type = = Type | | ptype->type = Hton S (eth_p_all)) && (!ptype->dev | | ptype->dev==skb->dev)) {        struct sk_buff *skb2;        Skb2=skb_clone (SKB, gfp_atomic);        if (skb2)            ptype->func (skb2, Skb->dev, ptype);}    } KFREE_SKB (SKB, free_write);

Light from the surface of the code can be understood, the main purpose is to traverse a linked list, to find out where the conditions of the node to make a deep copy (Skb_clone), the copied node for the corresponding processing, and finally the original node SKB released; The main problem with this code is skb_ Clone operation is very time-consuming, there is no way to reduce the number of clone operations? Can be used is SKB, assuming here to copy 10 times, then the last time can be considered unnecessary, you can directly use SKB, because there is no need to white, immediately SKB will be KFREE_SKB function destroyed; even if it is used, because SKB will no longer be used as a copy of the prototype (last time), So it is reasonable to use SKB directly for Ptype->func () operation. The question is how to dispense with the last SKB2 copy and use the SKB to implement the Ptype->func () operation directly? Refer to the solution for kernel hackers in the Linux community: Delay Type->func () processing by adding additional local variables.

Modification 1: Increase the local variable for staging ptype: Pt_prev = NULL;

Modification 2: Modify the If statement in the For loop accordingly:

if (pt_prev) {        struct sk_buff *skb2;        Skb2=skb_clone (SKB, gfp_atomic);        if (skb2)            Pt_prev->func (SKB2, Skb->dev,pt_prev);} Pt_prev = PType;
Modification 3: After exiting the For loop, dispose of the last PType:

<span style= "FONT-SIZE:14PX;" >if (Pt_prev) pt_prev->func (SKB, Skb->dev, Pt_prev); ELSEKFREE_SKB (SKB, Free_write);</span>
By incorporating the above code modifications, you can finally get:

Pt_prev = null;for (ptype = ptype_base; PType! = NULL; ptype = Ptype->next) {if (Ptype->type = = Type | | ptype->ty PE = = htons (eth_p_all)) && (!ptype->dev | | ptype->dev==skb->dev)) {      if (pt_prev) {<span style=] White-space:pre "></span>struct Sk_buff *skb2;       Skb2=skb_clone (SKB, gfp_atomic);        if (skb2)           Pt_prev->func (skb2, Skb->dev, Pt_prev);} Pt_prev = PType;}} End of Loop;if (Pt_prev) pt_prev->func (SKB, Skb->dev, Pt_prev); ELSEKFREE_SKB (SKB, free_write);

Inspired:

1. The code above shows a delay in the processing of code skills, although deduction performance, but the implementation of the program to improve the complexity of code is not easy to read;

2. Due to the needs of operating system optimization, the Linux implementation must contain many of the above-mentioned code optimization measures, as learners need to have a certain code simplification ability and thinking inquiry ability;


Resources:

Http://coolshell.cn/articles/8990.html

Http://coolshell.cn/articles/9859.html












[Principle Analysis]linux The list principle in the kernel practice [3]

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.