Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1615735
  • 博文数量: 197
  • 博客积分: 10046
  • 博客等级: 上将
  • 技术积分: 1983
  • 用 户 组: 普通用户
  • 注册时间: 2006-08-07 12:36
个人简介

在外企做服务器开发, 目前是项目经理, 管理两个server开发的项目。不做嵌入式好久了。

文章分类
文章存档

2011年(2)

2010年(6)

2009年(18)

2008年(30)

2007年(100)

2006年(41)

分类: LINUX

2007-09-28 12:46:32

【kernel进阶练习1】kernel 中的双链表的使用

参考例子如下:

你们可以把下面的代码粘贴到 自己的 代码里面去试验 , 我给的只是个代码片段而已 。 自己调试。

关于链表操作的具体实现, 可以看kernel代码里面的 include/linux/list.h
也可以在kernel代码中搜索 list_add/list_del/list_empty 等例子。



//声明一个链表

LIST_HEAD(bob_list);

struct bob_jobs {
    unsigned long id;

    struct list_head list;
};


#define this_job(p) list_entry(p, struct bob_jobs, list)

static __init int chardev_init(void)
{
   
    struct list_head *p = NULL;
   
    //begin

    struct bob_jobs job1 = {
        .id = 10UL,
        //.list = LIST_HEAD_INIT(list), 因为我们的结构体刚定义,list指针本身就是未知的,需要在list_add()才能对其进行操作,不用没法赋值。

    };
    struct bob_jobs job2 = {
        .id = 20UL,
        //.list = LIST_HEAD_INIT(list), 因为我们的结构体刚定义,list指针本身就是未知的,需要在list_add()才能对其进行操作,不用没法赋值。

    };
   
        
    Major = register_chrdev(0, DEVICE_NAME, &fops);

    if (Major < 0) {
        dbg("Registering the character device failed with %d\n", Major);
        return Major;
    }

   
    dbg("only debug the functions in list.h\n");
   
    INIT_LIST_HEAD(&bob_list);    //初始化链表

    list_add(&(job1.list),&bob_list);
    list_add(&(job2.list),&bob_list);
   
    //print ,遍历一下 ,

    list_for_each(p,&bob_list)
    {
        struct bob_jobs *job = NULL;
        
        job = this_job(p);
        dbg("id=%lu\n",job->id);
    }

    //试验完毕要删除链表, 但是这里面没有删除header ,因为header不是指针, 所以也就不用回收了。

    dbg("will delete the bob_list double list\n");
    while(bob_list.next != &bob_list)
    {
        struct bob_jobs *job = NULL;
        
        p = bob_list.next;
        job = this_job(p);
        
        //delete a entry after header

//        dbg("delete a entry after header , id = %lu\n",(this_job(p))->id);

        dbg("delete a entry after header , id = %lu\n",job->id);
        list_del(bob_list.next);
    }
    dbg("delete over \n");
   
    return 0;
}

 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
下面是edwin的反馈的练习记录:
 
回复 #1 bobzhang 的帖子

做这个练习的时候,了解到 list_for_each(pos, head)可以用来遍历整个双向链表,所以想在遍历链表的同时,用这个宏作删除的操作,结果不可以。
删除链表源码:

QUOTE:
list_for_each(p, &bob_list)  //can not be used to delete elements of the list for list_del() function
                                     //turns the pointer of the element to a fixed value.
//        list_for_each_safe(p, n, &bob_list)  // the list_for_each_safe(p, n, head) function protect the pos pointer before list_del()
        {
                struct bob_jobs *job_tobe_delete = NULL;
                job_tobe_delete = this_job(p);
                list_del(p);
                dbg("delete element id: %lu\n", job_tobe_delete->id);
        }

分析list_for_each(pos, head)源码

QUOTE:
      #define list_for_each(pos, head) \
        for (pos = (head)->next; prefetch(pos->next), pos != (head); \
                pos = pos->next)

可见此宏是用pos指针不断向后移动来遍历整个链表的。

再看list_del()的实现源码:

QUOTE:
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
        next->prev = prev;
        prev->next = next;
}

/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
static inline void list_del(struct list_head *entry)
{
        __list_del(entry->prev, entry->next);
        entry->next = LIST_POISON1;
        entry->prev = LIST_POISON2;
}

可以看到当执行删除操作的时候, 被删除的节点的连个指针被指向一个固定的位置(entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;)。而list_for_each(pos, head)中的pos指针在遍历过程中向后移动,即pos = pos->next,
如果执行了list_del()操作,pos将指向这个固定位置所指向next, prev,没有任何意义。出错。

而list_for_each_safe(p, n, head) 宏解决了上面的问题。它采用了一个同p同样类型的指针n 来暂存将要被删除的节点指针p
从而使得删除操作不影响pos指针。

QUOTE:
      list_for_each(p, &bob_list)  //can not be used to delete elements of the list for list_del() function
                                     //turns the pointer of the element to a fixed value.
//        list_for_each_safe(p, n, &bob_list)  // the list_for_each_safe(p, n, head) function protect the pos pointer before list_del()
        {
                struct bob_jobs *job_tobe_delete = NULL;
                job_tobe_delete = this_job(p);
                list_del(p);
                dbg("delete element id: %lu\n", job_tobe_delete->id);
        }

试验证明, 可以完成删除操作。

但是问题是,在module_init()中加入删除操作没有问题,而同样的删除代码放在module_exit()中,就会出现
kernel当机的现象。  不知道什么原因, 会是module实现机制上的原因吗??


阅读(3086) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~