內核雙鏈表-2

內核雙鏈表:

  3.1這裏的雙鏈表程序是很簡單,也是使用了許多宏和內聯函數,我們現在主要來看下程序。內核中雙鏈表的結構體定義如下:

structlist_head {

         struct list_head *next, *prev;

}; 這裏的頭部只有兩個指針域,相當奇怪,我們平時定義的鏈表主要都是節點域與指針域。這裏這麼用,自然有好處,將指針直接與數據剝離,對於內核中擁有不同數據域的鏈表即可公用一套指針域。現在這是我能想到的。不然前面的container_of宏也沒有多大意義了。

 

3.2程序接下來進行數據的初始化

#defineLIST_HEAD_INIT(name) { &(name), &(name) }

 

#defineLIST_HEAD(name) \

         struct list_head name =LIST_HEAD_INIT(name)

 

#defineINIT_LIST_HEAD(ptr) do { \

         (ptr)->next = (ptr); (ptr)->prev= (ptr); \

} while(0)

這裏主要是初始化頭結點,假如有一個使用中的結構體,這裏的代碼即可進行宏替換。

第二個宏就類似於,structlist_head _head; _head={&(_head),&(head)}; 第三個即是將next和prev指針都指向本身。接下來看看頭插法和尾插法的實現。

static  inline  void  __list_add(structlist_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, structlist_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.3 接下來看看從鏈表中刪除一個節點。

staticinline void __list_del(struct list_head * prev, struct list_head * next)

{

         next->prev = prev;

         prev->next = next;

}

staticinline void list_del(struct list_head *entry)

{

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

         entry->next = LIST_POISON1;

         entry->prev = LIST_POISON2;

}

由於這裏是沒有進行內存釋放的,所以用戶在自己使用時,一定要進行手動釋放內存[自己定義的結構體],否則會出現野指針和內存泄露。

 

3.4 進行移動

/*移動到某節點頭部*/

static  inline  void  list_move(struct  list_head *list, struct  list_head *head)

{

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

        list_add(list, head);

}

/*移動到某節點尾部*/

static  inline  void  list_move_tail(struct list_head *list,

                                       struct list_head *head)

{

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

        list_add_tail(list, head);

}

這兩個思想都是一樣,先刪除,在插入。

 

3.5 進行鏈表的遍歷

#definelist_for_each(pos, head) \

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

                 pos= pos->next, prefetch(pos->next))

其實也就是一個for循環,使用宏進行了重定義。

pos作爲中間變量,依次遞加,其中prefetch主要保證了地址的有效,還有這裏面涉及到流的欲抓取,據說能夠使用這個函數通常可以減少緩存缺失和停頓,沒試驗過,^_^||,前面的功能有點像assert

這裏還實現了雙向鏈表的前置掃描,這裏不再贅述。

我們這裏還有一個安全的鏈表遍歷。這裏何爲安全,看下面代碼。

#define list_for_each_safe(pos, n, head) \

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

                   pos= n, n = pos->next)

舉個例子就行,在list_for_each遍歷的時候,你敢刪除一個節點嗎?

 

3.6接下來這個宏比較吊

#define list_for_each_entry(pos, head,member)                              \

         for(pos = list_entry((head)->next, typeof(*pos), member),   \

                        prefetch(pos->member.next);                          \

              &pos->member != (head);                                         \

              pos = list_entry(pos->member.next,typeof(*pos), member),      \

                        prefetch(pos->member.next))

仍然是遍歷的過程。

pos = list_entry((head)->next,typeof(*pos), member), \

                        prefetch(pos->member.next);

首先是獲取member成員所在節點pos的首地址。就是container_of宏的作用,然後prefetch告訴cpu接下來會獲取下一個節點,達到預取的目的。

&pos->member != (head);      這個是用於循環條件判斷。

pos = list_entry(pos->member.next,typeof(*pos), member),        \

                        prefetch(pos->member.next))

這個類似於第一個。

 

 

接下來我們使用這些個函數,實現簡答的一些程序設計。[不可直接套用list.h]文件,這裏很多函數都是內核態的,非用戶態。  我們來刪繁就簡下。

double_list.h

#ifndef _double_list_

#define _double_list_

 

#include <stdio.h>

#include <stddef.h>

#include <stdlib.h>

 

#define LIST_POISON1  ((void *) 0x00100100)

#define LIST_POISON2  ((void *) 0x00200200)

 

/*用戶結構體*/

typedef struct _TApple

{

  intweight;

  charcolor[10];

  charname[20];

}TApple;

 

 

struct list_head {

         TApple*pApple;

         structlist_head *next, *prev;

};

 

//#define LIST_HEAD_INIT(name) { &(name),&(name) }

 

//#define LIST_HEAD(name) \

         structlist_head name = LIST_HEAD_INIT(name)

 

#define INIT_LIST_HEAD(ptr) do { \

         (ptr)->next= (ptr); (ptr)->prev = (ptr); \

} while (0)

 

 

 

#define container(ptr, type, member) ({ \

       const typeof(((type*)0)->member)* __mptr =(ptr);  \

       (type*)((char*)__mptr - offsetof(type, member)); })

                  

 

static inline void __list_add(structlist_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(structlist_head *new, struct list_head *head)

{

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

}

 

static inline void __list_del(structlist_head * prev, struct list_head * next)

{

         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;

}

 

#define list_for_each(pos, head) \

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

                 pos= pos->next)

                           

#define list_for_each_safe(pos, n, head) \

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

                   pos= n, n = pos->next)

                  

#define list_for_each_entry_safe(pos, n,head, member)                        \

         for(pos = container((head)->next, typeof(*pos), member),   \

                   n= container(pos->member.next, typeof(*pos), member);   \

              &pos->member != (head);                                         \

              pos = n, n = container(n->member.next,typeof(*n), member))

 

#endif

 

 

double_list.c

#include "double_list.h"

 

int main()

{

         TApple*pApple = (TApple*)malloc(sizeof(TApple));

         memset(pApple,0x00, sizeof(TApple));

         pApple->weight= 10;

         strcpy(pApple->color,"紅色");

         strcpy(pApple->name,"紅色富士山");

        

         structlist_head* head_node = (struct list_head*)malloc(sizeof(struct list_head));

         INIT_LIST_HEAD(head_node);

         head_node->pApple= pApple;

         printf("pApple=%p,head_node=%p \n", pApple,head_node);

         /*untilnow, you can see a head node*/

         /************************************************************************/

         TApple*pApple1 = (TApple*)malloc(sizeof(TApple));

         memset(pApple1,0x00, sizeof(TApple));

         pApple1->weight= 10;

         strcpy(pApple1->color,"綠色");

         strcpy(pApple1->name,"綠色富士山");

        

         structlist_head* head_node1 = (struct list_head*)malloc(sizeof(struct list_head));

         head_node1->pApple= pApple1;

         list_add(head_node1,head_node);

         printf("pApple1=%p,head_node1=%p \n", pApple1,head_node1);

         /************************************************************************/

         TApple*pApple2 = (TApple*)malloc(sizeof(TApple));

         memset(pApple2,0x00, sizeof(TApple));

         pApple2->weight= 10;

         strcpy(pApple2->color,"黃色");

         strcpy(pApple2->name,"黃色富士山");

        

         structlist_head* head_node2 = (struct list_head*)malloc(sizeof(struct list_head));

         head_node2->pApple= pApple2;

         list_add(head_node2,head_node);

         printf("pApple2=%p,head_node2=%p \n", pApple2,head_node2);

         /***********************************************************************/

        

         structlist_head* step_pointer = NULL;

         structlist_head* temp_pointer = NULL;

         intidx = 0;

         list_for_each_safe(step_pointer,temp_pointer,head_node)

         {

                   printf("weight=[%d],color=[%s],  name=[%s]\n",step_pointer->pApple->weight,step_pointer->pApple->color,step_pointer->pApple->name);

                   printf("index=%d,step_pointer->pApple=%p, step_pointer=%p \n", idx,step_pointer->pApple,step_pointer);

                   free(step_pointer->pApple);

                   step_pointer->pApple=NULL;

                   free(step_pointer);

                   step_pointer= NULL;

                   idx++;

         }

         /*******************delhead**********************/

         printf("weight=[%d],color=[%s],  name=[%s]\n",head_node->pApple->weight,head_node->pApple->color,head_node->pApple->name);

         printf("index=%d,head_node->pApple=%p, head_node=%p \n", idx,head_node->pApple,head_node);

         free(head_node->pApple);

         head_node->pApple=NULL;

         free(head_node);

         head_node= NULL;

        

         return0;

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章