本文将使用前文中所分析的list_head结构来遍历内核中的进程链表。task_struct结构中使用多个字段来详细的描述一个进程。本文中所属的遍历函数只打印一些常用的信息,即进程名称,进程的pid。
我们利用list.h中的下述遍历宏对整个进程链表进行遍历:
1 | 420#define list_for_each_entry(pos, head, member) \ |
2 | 421 for (pos = list_entry((head)->next, typeof(*pos), member); \ |
3 | 422 prefetch(pos->member.next), &pos->member != (head); \ |
4 | 423 pos = list_entry(pos->member.next, typeof(*pos), member)) |
先简单了解一下这个宏的使用方法。由于list_head结构中没有数据字段,所以它经常被嵌套在其他的结构体当中。pos指向包含list_struct结构的结构体;head为list_head类型的指针,我们可以使用链表中任意一个结点的指针;member即为list_head类型的变量名。
对应到我们下面的程序,pos为指向task_struct类型的指针,我们通过遍历宏即得到每个进程对应的task_struct类型的指针;我们将current_head赋予遍历宏中的第二个参数,current是一个宏,即为系统内正在运行的进程;由于list_struct结构在task_struct结构中的变量明为tasks,因此我们将tasks传递给便利宏的第三个参数。
01 | #include< linux/init.h > |
02 | #include< linux/module.h > |
03 | #include< linux/sched.h > |
04 | #include< linux/sem.h > |
05 | #include< linux/list.h > |
07 | static int __init traverse_init( void ) |
09 | struct task_struct *pos; |
10 | struct list_head *current_head; |
13 | printk( "Traversal module is working..\n" ); |
14 | current_head=&(current->tasks); |
15 | list_for_each_entry(pos,current_head,tasks) |
18 | printk( "[process %d]: %s\'s pid is %d\n" ,count,pos->comm,pos->pid); |
20 | printk(KERN_ALERT "The number of process is:%d\n" ,count); |
了解了便利宏的使用方法,那么理解上述代码就简单的多了。关于便利宏的代码详解可参考这里的文章。
加载函数要做的工作就是这些,那么卸载函数的功能就相对于简单多了。
1 | static void __exit traverse_exit( void ) |
3 | printk( "hello world exit\n" ); |
OK,编译,插入内核,再查看内核日志文件吧!