内核版本:2.6.24
list_for_each_entry() 宏用来遍历内核链表,它定义在 include/linux/list.h 中:
[C++] 纯文本查看 复制代码 /**
* 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))
由注释知道,pos 参数是 1 个遍历用的指针,第 2 个参数就是链表头,第 3 个参数为链表中元素的一个成员。该宏被定义为一个 for 循环,可以用它从它从第 1 个元素开始(list_entry((head)->next)遍历整个链表。其中 prefetch() 函数用以加快对链表的遍历速度,它实际上是 gcc 内置函数 __builtin_prefetch 的封装,关于 __builtin_prefetch 函数的描述可参考:http://www.groad.net/bbs/read.php?tid-3542.html 。在 2.6.3x 这样的内核中,取消了 prefetch() 函数在此的使用,估计是和后来的 CPU 的缓存机制更为先进的缘故。
下面用这个函数遍历整个模块链表,并打印出各个模块的名字,就如同 lsmod 的精简版:
[C++] 纯文本查看 复制代码 #include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/list.h>
MODULE_LICENSE("Dual BSD/GPL");
struct module *m = &__this_module;
static void list_module_test(void)
{
struct module *mod;
list_for_each_entry(mod, m->list.prev, list)
printk ("%s\n", mod->name);
}
static int list_module_init (void)
{
list_module_test();
return 0;
}
static void list_module_exit (void)
{
printk ("unload listmodule.ko\n");
}
module_init(list_module_init);
module_exit(list_module_exit);
因为插入的当前模块会加在表头和原来的第一个模块之间,所以 m->list.prev 参数用以指名从表头开始遍历。
加载后输出:[root@SLinux listmodule]# dmesg -c
listmodule
fuse
ip6table_filter
ip6_tables
xt_CHECKSUM
iptable_mangle
ipt_MASQUERADE
iptable_nat
... ...
ata_generic
pata_acpi
ata_piix
dm_mod |