linux的list结构简单灵活,所以也常常被用在用户空间。但在使用的时候有个需要注意的小地方,试看下面这段代码:
list_head *pos;
list_for_each(pos, &queue->posted) {
request_head_t *post_req = list_entry(pos, request_head_t, list);
req_destroy((request_t*)post_req, 1);
list_del_init(pos);
}
其中posted定义为:list_head类型。
其中list_for_each, list_del_init, list_entry都是从内核中复制粘贴过来的,冷眼一看似乎没什么问题。执行的时候可以发现这段代码是死循环,why??内核代码有问题?!
其实如果这段代码不是通过宏的方式封装的话,一眼就能看出来bug,但被封装后可就不容易发现了。首先,让我们看一下list_for_each和list_del_init是如何定义的:
#define list_for_each(pos, head) /
for (pos = (head)->next; pos != (head); pos = pos->next)
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
把代码替换进去就能发现,list_for_each操作后续还要继续使用pos的内容呢,如果这个时候把pos销毁或修改,那么后面发生的事情就不确定了,可能死循环也可能内存非法访问。。。
所以上面那段代码应该修改为:
while (!list_empty(&queue->posted)) {
pos = queue->posted.next;
request_head_t *post_req = list_entry(pos, request_head_t, list);
req_destroy((request_t*)post_req, 1);
list_del_init(pos);
}
:-)