内核双向循环链表

内核双向链表的数据结构

他只有两个指针域,没有数据域,但是这样他的通用性得到了优化,但是这样没有数据,有什么意义呢,我们先来看看内核提供的接口函数

struct list_head
{
	struct list_head *next,*head;
};

链表的创建函数,创建一个结点,并初始化

#define LIST_HEAD_INIT(name) { &(name), &(name) }                                             
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)

链表的插入的头插法

static inline void list_add(struct list_head *new, struct list_head *head)                    
  {
          __list_add(new, head, head->next);
 }

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

链表的尾插法

 74  static inline void list_add_tail(struct list_head *new, struct list_head *head)               
 75 {
 76         __list_add(new, head->prev, head);
 77 }
 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_del(struct list_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 != (head); pos = pos->next)

写一个测试程序测试一下


#include <linux/init.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/slab.h>
#define N 128

struct stu{
    char name[100];
    int id;
    int math;
    struct list_head list;
};

LIST_HEAD (head);
static int demo_init (void)
{
    int i,ret;
    struct stu *stu;
    struct list_head *pos;
    for (i=0;i<N;i++){
	stu =kmalloc(sizeof(*stu),GFP_KERNEL);
	if (NULL==stu) {
	    ret=-ENOMEM;
	    goto error0;
	}
	stu->id =9527+i;
	sprintf (stu->name,"chouchou%d",i);
	stu ->math = (60+i)%101;
	list_add_tail(&stu->list,&head);
    }
    list_for_each(pos,&head) {
	stu=container_of(pos,struct stu,list);
	printk ("-------id %d -------\n",stu->id);
	printk ("name %s , math: %d\n",stu->name,stu->math);
    }
    return ret;
error0:
    return ret;

}
module_init (demo_init);

static void demo_exit (void)
{
    struct list_head *pos,*n;
    struct stu*stu;
    list_for_each_safe(pos,n,&head)
    {
	stu =container_of(pos,struct stu,list);
	kfree (stu);
    }
}


module_exit (demo_exit);

container_of宏的理解

我们刚才在上面看双向循环链表结构的时候发现,他没有数据域,所以我们怎么知道他的数据,在上面的测试程序中我们使用了container_of这个宏来返回一个指针,其中就包含数据,所以我们来看一下container_of这个宏怎么得到数据

/**                                                                                           
677  * container_of - cast a member of a structure out to the containing structure
678  * @ptr:        the pointer to the member.
679  * @type:       the type of the container struct this is embedded in.
680  * @member:     the name of the member within the struct.
681  *
682  */
    #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
683 #define container_of(ptr, type, member) ({                      \
684         const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
685         (type *)( (char *)__mptr - offsetof(type,member) );})

来大概理解一下这个宏,他的核心思想就是通过知道你定义的类型指针,定义的类型,还有成员的名字来确定出包含这个链表的结构体的地址,从而获取数据域

 const typeof( ((type *)0)->member ) *__mptr = (ptr);   \ 
 //将ptr的类型指针赋值给通过tyoeof新类型的变量__mptr
 (type *)( (char *)__mptr - offsetof(type,member) );})
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 //将0地址转换为指针并指向成员再通过取地址操作得到偏移量
 //再用成员的地址减去偏移地址就得到结构体的首地址,再将他强转为目标结构体类型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值