linux 内核list head,Linux Kernel: 強大又好用的list_head結構

Linux Kernel: 強大又好用的list_head結構

Linux Kernel: 強大又好用的list_head結構 程式設計者在設計一個doubly linked list時,通常會在所宣告的結構裡宣告兩個結構指標,如下所示:

struct student {

char name[16];

int id;

struct student *next, *prev;

};

只要經由prev與next兩個結構指標,便能取得該doubly linked list所有資訊。

然而,Linux kernel並非引用此種作法。因此,Linux kernel定義一通用結構 (struct list_head, include/linux/list.h),用以實作doubly linked list,此結構相當簡單,如下所示:

struct list_head {

struct list_head *next, *prev;

};

所以物件student宣告為如下:

struct student

{

char name[16];

int id;

struct list_head list;

};

藉由list變數便能取得doubly linked list所有資訊。

###list_head相關Marco與Function

這裡僅介紹較常用的macro與function,如欲進一步得知其它marco請參考include/linux/list.h

LIST_HEAD(name)

struct list_head name = { &(name), &(name) };

將next與prev指到自己,意味著此list為空的。

list_empty(const struct list_head *head)

retrun head->next == head;

檢查此list是否為空的。

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

head->next->prev = new;

new->next = head->next;

new->prev = head;

head->next = new;

將資料加入至doubly linked list最前端。建議自己動手畫個圖,便可瞭解這幾個指標指到何處。

list_del(struct list_head *entry)

entry->next->prev = entry->prev;

entry->prev->next = entry->next;

將某一資料從中刪除。

list_entry(ptr,type,member)

((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

透過此函式便能算出結構的起始位址,並做結構轉型便能取得結構的資料,此計算方式相當好用啊!!!

以struct student為例,如下所示:

(unsigned long)(&((struct student *)0)->member))) ==> 計算出list成員相對位址。通常看到這一個敘述,直覺地覺得應該會記憶體區段錯誤吧 (Segmentation Fault)!? 因為該敘述用NULL的pointer存取list成員,但在(struct student *)0)->member))前面加了&符號,就不會發生記憶體區段錯誤。因為&符號,只意味著存取list的位址,而不是資料, 經由此敘述便能取得list的位移植。如下圖所示,該敘述所得之位移植值為20。

75d83e0ce476197dc7543d37b17a3a74.png

((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) ==> 取得位移植之後,再將list的位址減去位移植,便能取得該結構的起始位址,如下圖所示 (假設結構起始位址為x),最後再做結構轉型變大功告成。

639fc1fff2e903a3cf30ffd02b0ffd49.png

list_for_each(pos, head)

for (pos = (head)->next; pos != (head); pos = pos->next)

取得該doubly linked list所有資料。

Makefile

obj-m += list_head_ex.o

KDIR=/lib/modules/$(shell uname -r)/build

all:

make -C $(KDIR) M=$(PWD) modules

clean:

make -C $(KDIR) M=$(PWD) clean

-list_head_ex.c

/*

* =============================================================================

*

* Filename: list_head_ex.c

*

* Description: Write a doubly linked list by using list_head structure

*

* Version: 1.0

* Created: Fri Oct 19 14:14:57 GMT 2007

* Revision: none

* Compiler: gcc

*

* Author: Adrian Huang

* Web Site: http://adrianhuang.blogspot.com/

*

* ============================================================================

*/

#include "list_head_ex.h"

int __init list_head_init(void)

{

struct list_headstd_head, *next;

struct studentsl[NR_STDS]; // student list

struct student*studentP; // student pointer

intidx;

/* init std_head */

INIT_LIST_HEAD(&std_head);

/* Check whether the std_head is empty */

if(list_empty(&std_head) == TRUE) {

printk(KERN_INFO "[Adrian] std_head is NULL\n");

}

/* Add each element to student head (std_head) */

for(idx=0;idx

sprintf(sl[idx].name, "Adrian Huang");

sl[idx].id = idx + 1;

list_add(&sl[idx].list, &std_head);

}

printk(KERN_INFO "======dump all elements of the list by invoking "

"'list_for_each'=========\n");

/* Traverse all elements of the list */

list_for_each(next, &std_head) {

studentP = (struct student *) list_entry(next, struct student, list);

printk(KERN_INFO "[Adrian] name: %s, id: %d\n",

studentP->name, studentP->id);

}

printk(KERN_INFO "\n======dump all elements of the list by invoking "

"'list_entry'=========\n");

/* Traverse all elements of the list and delete each of it */

for(idx=0;idx

studentP = (struct student *) list_entry(std_head.next,

struct student, list);

printk(KERN_INFO "[Adrian] name: %s, id: %d\n",

studentP->name, studentP->id);

list_del(std_head.next);

}

return 0;

}

void __exit list_head_exit(void)

{

;

}

module_init(list_head_init);

module_exit(list_head_exit);

list_head_ex.h

/*

* =============================================================================

*

* Filename: list_head_ex.h

*

* Description: Write a doubly linked list by using list_head structure

*

* Version: 1.0

* Created: Fri Oct 19 14:17:58 GMT 2007

* Revision: none

* Compiler: gcc

*

* Author: Adrian Huang

* Web Site: http://adrianhuang.blogspot.com/

*

* =============================================================================

*/

#ifndef LIST_HEAD_EX_INC

#define LIST_HEAD_EX_INC

#include /* Needed by all modules */

#include /* Needed for KERN_INFO */

#include

#include /* list_head structure*/

#defineNR_STDS5

struct student {

charname[16];

intid;

struct list_headlist;

};

typedef enum _Boolean { FALSE = 0, TRUE = 1 } LHBOOL; // list head boolean

#endif /* ----- #ifndef LIST_HEAD_EX_INC ----- */

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值