Chinaunix首页 | 论坛 | 博客
  • 博客访问: 314167
  • 博文数量: 45
  • 博客积分: 2079
  • 博客等级: 上尉
  • 技术积分: 464
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-03 16:57
文章分类

全部博文(45)

文章存档

2015年(1)

2013年(1)

2012年(9)

2011年(2)

2010年(32)

分类: LINUX

2012-03-20 11:25:48

  使用linux内核链节时有时会有这样的使用场景:链表节点会被频繁的换入换出链表,这时操作链表节点时就需要判断节点是否归属于链表,比较容易想到的是判断指针是否为空来进行判断,实现如下:

static inline int node_in_list(const struct list_head *node)
{
ASSERT(node);
return (node->next != NULL && node->prev!= NULL && node->next != node);
}

然而,上面这段代码犯了一个致命错误:内核链表的删除操作list_del并不会将前驱和后继指针置空,而是将它们指向了特殊值:

static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
这两个值定义如下:
/*
 * These are non-NULL pointers that will result in page faults
 * under normal circumstances, used to verify that nobody uses
 * non-initialized list entries.
 */
#define LIST_POISON1  ((void *) 0x00100100)
#define LIST_POISON2  ((void *) 0x00200200)

如注释所述,内核链表这样设计正是为了防止我们使用那些未初始化的链表节点,当上面那段代码运行时,我们直到在堆栈中发现一个0x00200200或是0x00100100的数字,才恍然大悟,这样做判断是不行的。当然,你能将上面的那段代码改成:

static inline int node_in_list(const struct list_head *node)
{
ASSERT(node);
return (node->next != NULL && node->prev!= NULL && node->next != node
&&node->next !=   LIST_POISON1  && node->prev!=  LIST_POISON2   );
}

但是,这样修改复杂不说,你就能保证LIST_POISON1不会被什么宏包起来出现重复定义么?定义的值也未必相同吧……所以还是想想其他的办法吧。经高人指点,发现了这个函数:

/**
 * list_del_init - deletes entry from list and reinitialize it.
 * @entry: the element to delete from the list.
 */
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
聪明的朋友已经知道怎么做了吧,:)
1、申请节点时调用INIT_LIST_HEAD将其自环;
2、删除时调用list_del_init进行删除;
3、判断时根据节点是否自环判断是否在链表中。

实现如下:
static inline int node_in_list(const struct list_head *node)
{
 if(list_empty(node)) 
     return 0;
 else return 1;
}

另外,所谓自环就是节点前驱与后继都指向自己,即INIT_LIST_HEAD的实现:
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
阅读(2159) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

zboom2012-03-23 15:05:14

fanglq04: .....

fanglq042012-03-23 09:38:23