转载的文章:输入子系统匹配过程之list_for_each_entry()函数分析
重点:
list_for_each_entry()宏函数分析:
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
时刻注意这是一个宏函数,第三个参数member也是替换字符串用的,是结构体成员的名称,它的作用是提供一个数据类型,宏展开成一个函数后,也并没有引用member传来的地址,pos->member不是第三个参数member。
第一行pos = list_entry((head)->next, typeof(*pos), member)的作用就是返回
head->next所指向的member 所在的pos类型结构体的首地址。
第二句prefetch(pos->member.next), &pos->member != (head)是循环条件, 先不管,不影响分析。
第三句pos = list_entry(pos->member.next, typeof(*pos), member))和第一句一样, pos指向的是下一个member所在的pos类型结构体的首地址,这样pos就历遍了一个由pos类型结构体组成的链表 一样。
{
自己的添加:
v4l2-async.c的272行函数:
int v4l2_async_register_subdev(struct v4l2_subdev *sd)
{
struct v4l2_async_notifier *notifier;
/*
* No reference taken. The reference is held by the device
* (struct v4l2_subdev.dev), and async sub-device does not
* exist independently of the device at any point of time.
*/
if (!sd->of_node && sd->dev)
sd->of_node = sd->dev->of_node;
mutex_lock(&list_lock);
INIT_LIST_HEAD(&sd->async_list);
list_for_each_entry(notifier, ¬ifier_list, list) {
struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
if (asd) {
int ret = v4l2_async_test_notify(notifier, sd, asd);
mutex_unlock(&list_lock);
return ret;
}
}
/* None matched, wait for hot-plugging */
list_add(&sd->async_list, &subdev_list);
mutex_unlock(&list_lock);
return 0;
}
list_for_each_entry(notifier, ¬ifier_list, list)函数里的for循环只运行了一次,想要获得notifier的地址,但是notifier_list刚被初始化,其指向的next其实是指向了自己,故不符合其初始条件判断: &pos->member != (head);
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
所以并不会进入该循环,但是下一行代码:list_add(&sd->async_list, &subdev_list);,相当于将其加入到注册链表里,可以查看v4l2_device_register_subdev函数,其主要功能就是添加该链表。
附:list_add和list_add_tail
调用list_add可以将一个新链表结点插入到一个已知结点的后面;
调用list_add_tail可以将一个新链表结点插入到一个已知结点的前面;
附上其网页的链接:(http://blog.sina.com.cn/s/blog_78d30f6b0102vug4.html)