linux内核链表函数学习

1.INIT_LIST_HEAD: 创建链表

点击(此处)折叠或打开

  1. /*
  2.  * Simple doubly linked list implementation.
  3.  *
  4.  * Some of the internal functions ("__xxx") are useful when
  5.  * manipulating whole lists rather than single entries, as
  6.  * sometimes we already know the next/prev entries and we can
  7.  * generate better code by using them directly rather than
  8.  * using the generic single-entry routines.
  9.  */

  10. #define LIST_HEAD_INIT(name) { &(name), &(name) }

  11. #define LIST_HEAD(name) \
  12.     struct list_head name = LIST_HEAD_INIT(name)

  13. static inline void INIT_LIST_HEAD(struct list_head *list)
  14. {
  15.     list->next = list;
  16.     list->prev = list;
  17. }
创建链表的时候需要一个头链表所以要先
struct list_head list;
然后调用
INIT_LIST_HEAD(& list);   初始化链表头

2.list_add: 在链表头插入节点

点击(此处)折叠或打开

  1. /**
  2.  * list_add - add a new entry
  3.  * @new: new entry to be added
  4.  * @head: list head to add it after
  5.  *
  6.  * Insert a new entry after the specified head.
  7.  * This is good for implementing stacks.
  8.  */
  9. static inline void list_add(struct list_head *new, struct list_head *head)
  10. {
  11.     __list_add(new, head, head->next);
  12. }

  13. /*
  14.  * Insert a new entry between two known consecutive entries.
  15.  *
  16.  * This is only for internal list manipulation where we know
  17.  * the prev/next entries
  18.  */
  19. #ifndef CONFIG_DEBUG_LIST
  20. static inline void __list_add(struct list_head *new,
  21.              struct list_head *prev,
  22.              struct list_head *next)
  23. {
  24.     next->prev = new;
  25.     new->next = next;
  26.     new->prev = prev;
  27.     prev->next = new;
  28. }
  29. #else
  30. extern void __list_add(struct list_head *new,
  31.              struct list_head *prev,
  32.              struct list_head *next);
  33. #endif
首先是list_add(struct list_head *new, struct list_head *head);
传入要插入的指针域,和头部,然后又进入了__list_add(struct list_head *new, struct list_head *prev, struct list_head *next)
就是把头部next指向,新的指针域. 把原来next->prev指向新的指针域. 然后把新的指针域指向各自的头部和原来的next;
于是就可以在head后不断插入新的指针域(个人理解,不知对错)
3.list_add_tail:在链表尾插入节点

点击(此处)折叠或打开

  1. /**
  2.  * list_add_tail - add a new entry
  3.  * @new: new entry to be added
  4.  * @head: list head to add it before
  5.  *
  6.  * Insert a new entry before the specified head.
  7.  * This is useful for implementing queues.
  8.  */
  9. static inline void list_add_tail(struct list_head *new, struct list_head *head)
  10. {
  11.     __list_add(new, head->prev, head);
  12. }

  13. /*
  14.  * Insert a new entry between two known consecutive entries.
  15.  *
  16.  * This is only for internal list manipulation where we know
  17.  * the prev/next entries
  18.  */
  19. #ifndef CONFIG_DEBUG_LIST
  20. static inline void __list_add(struct list_head *new,
  21.              struct list_head *prev,
  22.              struct list_head *next)
  23. {
  24.     next->prev = new;
  25.     new->next = next;
  26.     new->prev = prev;
  27.     prev->next = new;
  28. }
  29. #else
  30. extern void __list_add(struct list_head *new,
  31.              struct list_head *prev,
  32.              struct list_head *next);
  33. #endif
这个原理和上面的有点类似;调用了__list_add, 但是传入的值有所不同.
感觉就是在head->prev上 一个一个的插入,head不是头吗.看着像是尾巴
4.list_del: 删除节点

点击(此处)折叠或打开

  1. /**
  2.  * list_del - deletes entry from list.
  3.  * @entry: the element to delete from the list.
  4.  * Note: list_empty() on entry does not return true after this, the entry is
  5.  * in an undefined state.
  6.  */
  7. #ifndef CONFIG_DEBUG_LIST
  8. static inline void __list_del_entry(struct list_head *entry)
  9. {
  10.     __list_del(entry->prev, entry->next);
  11. }

  12. static inline void list_del(struct list_head *entry)
  13. {
  14.     __list_del(entry->prev, entry->next);
  15.     entry->next = LIST_POISON1;
  16.     entry->prev = LIST_POISON2;
  17. }
  18. #else
  19. extern void __list_del_entry(struct list_head *entry);
  20. extern void list_del(struct list_head *entry);
  21. #endif

  22. /*
  23.  * Delete a list entry by making the prev/next entries
  24.  * point to each other.
  25.  *
  26.  * This is only for internal list manipulation where we know
  27.  * the prev/next entries
  28.  */
  29. static inline void __list_del(struct list_head * prev, struct list_head * next)
  30. {
  31.     next->prev = prev;
  32.     prev->next = next;
  33. }

  34. /*
  35.  * These are non-NULL pointers that will result in page faults
  36.  * under normal circumstances, used to verify that nobody uses
  37.  * non-initialized list entries.
  38.  */
  39. #define LIST_POISON1  ((void *) 0x00100100 + POISON_POINTER_DELTA)
  40. #define LIST_POISON2  ((void *) 0x00200200 + POISON_POINTER_DELTA)
这里调用了__list_del(entry->prev, entry->next); 把指针指向了自己.
后面的就看不懂了,这里传进去的都是指针吧,那么后面是什么意思呢,求大神啊POISON_POINTER_DELTA是0
entry - > next   =  LIST_POISON1 ;
entry - > prev  =  LIST_POISON2 ;

        这段来自http://hi.baidu.com/fan_ying_fei/item/5010e140cbe837efbdf4515b
        此操作删除一个链表中的指定元素。调用该函数后,指定元素从链表中消失,它的前仆后继成为彼此新的前仆后继。
        其中LIST_POISON1、LIST_POISON2是因为删除的元素其next和prev变量仍然是指向它以前的前仆后继,也就是说将会导致从一个
        非链表中的对象可以访问链表对象,会引起严重的安全问题
        LIST_POISON1和LIST_POISON定义在include/linux/poison.h中:
        #define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)
        #define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)
        将该被抛弃的元素的内部指针指向两个内核空间不会用到的内存位置,当试图访问该指针时会出现错误

所以被删除的节点的两个指针被指向一个固定的位置( LIST_POISON1 和 LIST_POISON2  是内核空间的两个地址) -----《linux操作系统与应用》

5.list_entry: 去除节点

点击(此处)折叠或打开

  1. /**
  2.  * list_entry - get the struct for this entry
  3.  * @ptr:    the &struct list_head pointer.
  4.  * @type:    the type of the struct this is embedded in.
  5.  * @member:    the name of the list_struct within the struct.
  6.  */
  7. #define list_entry(ptr, type, member) \
  8.     container_of(ptr, type, member)

  9. #ifndef container_of
  10. /**
  11.  * container_of - cast a member of a structure out to the containing structure
  12.  * @ptr:    the pointer to the member.
  13.  * @type:    the type of the container struct this is embedded in.
  14.  * @member:    the name of the member within the struct.
  15.  *
  16.  */
  17. #define container_of(ptr, type, member) ({            \
  18.     const typeof(((type *)0)->member) * __mptr = (ptr);    \
  19.     (type *)((char *)__mptr - offsetof(type, member)); })
  20. #endif

  21. #ifndef offsetof
  22. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
  23. #endif
调用了container_of(ptr, type, member);用来获得指针域上面的结构体开头地址
ptr:list_head头指针位置 type:结构体类型吧 member:这个结构体里的list_head名字
ptr把list_head的位置放在mptr;然后又offsetof,把TYPE强制转换成0地址开始到MEMBER就是从struct开始到list_head的距离
mptr的地址减去这个距离就是struct的位置,从而能使用struct的变量

6.list_for_each: 遍历链表

点击(此处)折叠或打开

  1. /**
  2.  * list_for_each    -    iterate over a list
  3.  * @pos:    the &struct list_head to use as a loop cursor.
  4.  * @head:    the head for your list.
  5.  */
  6. #define list_for_each(pos, head) \
  7.     for (pos = (head)->next; prefetch(pos->next), pos != (head); \
  8.             pos = pos->next)

  9. #ifndef PERF_LINUX_PREFETCH_H
  10. #define PERF_LINUX_PREFETCH_H

  11. static inline void prefetch(void *a __attribute__((unused))) { }

  12. #endif

  13. static inline __attribute__((pure)) int phys_to_nid(unsigned long addr)
  14. {
  15.     unsigned nid;
  16.     VIRTUAL_BUG_ON(!memnodemap);
  17.     nid = memnodemap[addr >> memnode_shift];
  18.     VIRTUAL_BUG_ON(nid >= MAX_NUMNODES || !node_data[nid]);
  19.     return nid;
  20. }
list_for_each是个循环遍历链表头,更看不懂了..先睡了

这段来自http://hi.baidu.com/fan_ying_fei/item/5010e140cbe837efbdf4515b
它实际上是一个for循环,利用传入的pos作为循环变量,从表头head开始,逐项向后(next方向)移动pos,直至又回到head,停止循环,该宏使用两个list_head类型的参数,第一个参数用来指向当前项,第二个参数指向需要检索的链表
当然使用该遍历链表只能得指向list_head结构体的指针,但是无法访问其成员变量,为此linux提供了
#define list_entry(ptr, type, member) \
    container_of(ptr, type, member)
假设设有一个list_head的链表,且每个链表包含在另外一个结构体的对象里,这些外部结构体的对象通过list_head联系起来。如果ptr指向链表中一个已知的list_head对象,那么list_entry宏会返回包含这个对象的外部结构体对象的指针,从而实现访问其成员变量的遍历

自己写的:

  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/list.h>


  4. struct score
  5. {
  6.     int num;
  7.     int english;
  8.     int math;
  9.     struct list_head list;
  10. };


  11. struct list_head score_head;
  12. struct score stu1,stu2,stu3;
  13. struct list_head *pos;
  14. struct score *tmp;




  15. int mylist_init()
  16. {
  17.     INIT_LIST_HEAD(&score_head);
  18.     
  19.     stu1.num = 1;
  20.     stu1.english = 90;
  21.     stu1.math =98;
  22.     list_add_tail(&(stu1.list),&score_head);
  23.     
  24.     stu2.num = 2;
  25.     stu2.english = 91;
  26.     stu2.math =96;
  27.     list_add_tail(&(stu2.list),&score_head);


  28.     stu3.num = 3;
  29.     stu3.english = 92;
  30.     stu3.math = 99;
  31.     list_add_tail(&(stu3.list),&score_head);
  32.     
  33.     list_for_each(pos,&score_head)
  34.     {
  35.         tmp = list_entry(pos,struct score,list);
  36.         printk("No. %d, english is %d, math is %d\n",tmp->num,tmp->english,tmp->math);
  37.     }
  38.     
  39.     return 0;
  40. }


  41. void mylist_exit()
  42. {
  43.     list_del(&(stu1.list));
  44.     list_del(&(stu2.list));
  45. }


  46. module_init(mylist_init);


  47. module_exit(mylist_exit);


<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(267) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

ch1226332014-05-28 13:26:24

CU博客助理:嘉宾点评:
要做一名优秀的程序员,一个是英语技能,最起码可以流畅的阅读英文资料。内核链表实现代码有着非常清楚的注释,从注释中完全可以理解代码的意图;另一个是理解代码的能力,即使直接看,看不懂源码,那么完全可以通过实践测试,调试等方法理解源码。所以楼主要想提高技能,完全可以从这两方面入手,也就不会有文中对代码的疑问了。(感谢您参与“原创博文评选”获奖结果即将公布)

哦,太感谢了

回复 | 举报

CU博客助理2014-05-22 13:07:30

嘉宾点评:
要做一名优秀的程序员,一个是英语技能,最起码可以流畅的阅读英文资料。内核链表实现代码有着非常清楚的注释,从注释中完全可以理解代码的意图;另一个是理解代码的能力,即使直接看,看不懂源码,那么完全可以通过实践测试,调试等方法理解源码。所以楼主要想提高技能,完全可以从这两方面入手,也就不会有文中对代码的疑问了。(感谢您参与“原创博文评选”获奖结果即将公布)

评论热议
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

习惯就好zz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值