staticintkprocprnt_init(void) { structtask_struct *task; printk(KERN_ALERT "Hello This function was make by Ryan.\n"); printk(KERN_ALERT "名称\t进程号\t状态\t优先级\t");
structtask_struct *real_parent;/* real parent process */ structtask_struct *parent;/* recipient of SIGCHLD, wait4() reports */ structlist_headchildren;/* list of my children */ structlist_headsibling;/* linkage in my parent's children list */ structtask_struct *group_leader;/* threadgroup leader */
staticvoidprocfaminfo_exit(void) { printk(KERN_ALERT "All family members done.Have a good day then.\n"); }
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ryan"); MODULE_DESCRIPTION("Process Family Info Print"); module_init(procfaminfo_init); module_exit(procfaminfo_exit);
需要注意的是,name是参数名,也是模块内接受参数的变量,在此模块内是进程的PID。type是参数的数据类型,可以是int,uint,short,ushort,long,ulong,bool,byte,charp,invboll之一。 (or XXX if you define param_get_XXX) perm字段是权限赋予(权限掩码),用来做一个辅助的sysfs入口。本例为755.即rwx-rx-rx。
-EFAULT
-EFAULT It happen if the memory address of some argument passed to sendto (or more generally to any system call) is invalid. \
#define list_for_each(pos, head) \ for (pos = (head)->next; prefetch(pos->next), pos != (head); \ pos = pos->next) * @pos: the &structlist_headtouseasaloopcursor. * @head: the head for your list.
list_for_each实际上是一个 for 循环,利用传入的pos 作为循环变量,从表头 head开始,逐项向后(next方向)移动 pos ,直至又回到 head (prefetch() 可以不考虑,用于预取以提高遍历速度)。 注意:此宏必要把list_head放在数据结构第一项成员,至此,它的地址也就是结构变量的地址。
p = list_entry(child, struct task_struct, sibling);//attention
在上方的list_for_each(child,&task->children)中已经将list_head更新为当前task的子进程链表头,从此处开始遍历打印即当前进程的子进程,主要注意的是,此处不需要判断pid的情况,因为task本身的pid不可能是子进程的pid。 此外:为什么在遍历时要传入sibling成员,是因为,sibling成员在源码的解释为linkage in the parents' children。这是指当当前节点为task->children的时候,要遍历其父节点的所有子节点就要给定一个子节点链表的链表头,而利用list_entry()找到子进程链表头,sibling承担着找到子节点链表项的功能。