程序(最初粘贴这段程序时,还没找到语法显示插件,导致网页混入其他不可见的编码,不能直接用它来编译)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
| #include <linux/init.h>
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/sched.h>
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("fqh,http://cnkernel.org/blog");
MODULE_DESCRIPTION("for understanding the iteration macroes in list.h");
static int list_init(void)
{
int i = 0;
int j = 0;
int k = 0;
struct task_struct *p;
struct task_struct *m;
struct task_struct *n;
/****** test 1 *******/
printk(KERN_ALERT "testing for_each_process, current %d, %s\n",\
current->pid, current->comm);
for_each_process(p) {
printk(KERN_ALERT "1# PID: %d, name: %s\n",p->pid, p->comm);
i += 1;
}
printk(KERN_ALERT "1# total: %d\n\n\n", i);
/****** test 2 *******/
printk(KERN_ALERT "testing for list_for_each_entry\n\twith \
&(&init_task)->tasks as its paramter,current %d, %s\n",\
current->pid, current->comm);
list_for_each_entry(m, &(&init_task)->tasks,tasks) {
printk(KERN_ALERT "2# PID: %d, name: %s\n",m->pid, m->comm);
j += 1;
}
printk(KERN_ALERT "2# total: %d\n\n\n", j);
/****** test 3 *******/
printk(KERN_ALERT "testing for list_for_each_entry\n\twith \
¤t->tasks as its paramter,current %d, %s\n",\
current->pid, current->comm);
list_for_each_entry(n, ¤t->tasks,tasks) {
printk(KERN_ALERT "3# PID: %d, name: %s\n",n->pid, n->comm);
k += 1;
}
printk(KERN_ALERT "3# total: %d\n", k);
return 0;
}
static void list_exit(void)
{
printk(KERN_ALERT "bye bye\n");
}
module_init(list_init);
module_exit(list_exit); |
运行结果和分析
注意 insmod被列出,没有swapper
&init_task 作为结束循环的比较条件。因为p在第一次进行比较时被改变了值,swapper(0)没被列举出来
testing for_each_process, current 5414, insmod
1# PID: 1, name: init
1# PID: 2, name: migration/0
1# PID: 3, name: ksoftirqd/0
1# PID: 4, name: events/0
1# PID: 5, name: khelper
1# PID: 6, name: kthread
1# PID: 8, name: kblockd/0
1# PID: 9, name: kacpid
1# PID: 103, name: pdflush
1# PID: 104, name: pdflush
1# PID: 106, name: aio/0
1# PID: 105, name: kswapd0
1# PID: 312, name: cqueue/0
1# PID: 313, name: kseriod
1# PID: 353, name: kpsmoused
1# PID: 739, name: scsi_eh_0
1# PID: 835, name: reiserfs/0
1# PID: 928, name: udevd
1# PID: 1347, name: khubd
1# PID: 1409, name: kgameportd
1# PID: 2191, name: dbus-daemon
1# PID: 2193, name: acpid
1# PID: 2229, name: syslog-ng
1# PID: 2233, name: klogd
1# PID: 2358, name: resmgrd
1# PID: 2482, name: hald
1# PID: 2553, name: hald-addon-acpi
1# PID: 2559, name: dhcdbd
1# PID: 2566, name: NetworkManagerD
1# PID: 2571, name: NetworkManager
1# PID: 2601, name: mdnsd
1# PID: 2626, name: auditd
1# PID: 2637, name: kauditd
1# PID: 2650, name: portmap
1# PID: 2669, name: hald-addon-stor
1# PID: 2702, name: dhclient
1# PID: 2706, name: cupsd
1# PID: 2830, name: master
1# PID: 2845, name: pickup
1# PID: 2846, name: qmgr
1# PID: 2859, name: cron
1# PID: 3012, name: powersaved
1# PID: 3023, name: smpppd
1# PID: 3094, name: sshd
1# PID: 3106, name: gdm
1# PID: 3116, name: startpar
1# PID: 3125, name: gdm
1# PID: 3131, name: X
1# PID: 3282, name: mingetty
1# PID: 3283, name: mingetty
1# PID: 3284, name: mingetty
1# PID: 3285, name: mingetty
1# PID: 3286, name: mingetty
1# PID: 3294, name: mingetty
1# PID: 3480, name: racoon
1# PID: 3501, name: gnome-session
1# PID: 3531, name: scim-launcher
1# PID: 3535, name: scim-helper-man
1# PID: 3536, name: scim-panel-gtk
1# PID: 3538, name: scim-launcher
1# PID: 3552, name: gpg-agent
1# PID: 3553, name: ssh-agent
1# PID: 3559, name: dbus-launch
1# PID: 3560, name: dbus-daemon
1# PID: 3564, name: gconfd-2
1# PID: 3569, name: gnome-keyring-d
1# PID: 3571, name: bonobo-activati
1# PID: 3573, name: esd
1# PID: 3577, name: gnome-settings-
1# PID: 3579, name: metacity
1# PID: 3587, name: gnome-panel
1# PID: 3589, name: nautilus
1# PID: 3592, name: main-menu
1# PID: 3594, name: mono
1# PID: 3603, name: resapplet
1# PID: 3606, name: iprint-listener
1# PID: 3609, name: zen-updater
1# PID: 3611, name: gnome-vfs-daemo
1# PID: 3624, name: gnome-power-man
1# PID: 3626, name: application-bro
1# PID: 3627, name: gnome-volume-ma
1# PID: 3641, name: nm-applet
1# PID: 3667, name: gnome-screensav
1# PID: 3669, name: gnome-terminal
1# PID: 3670, name: gnome-pty-helpe
1# PID: 3671, name: bash
1# PID: 2883, name: zmd
1# PID: 5414, name: insmod
1# PID: 5415, name: udevd
1# total: 89
注意 insmod被列出,没有swapper
&(&init_task)->tasks 是表头,表头(或表头所在的大结构体)没列作关心对象,起结束循环的比较作用。也是就说0(swapper)没被列举出
结论。表头所在的大结构体不会被list_for_each_entry列举出来
testing for list_for_each_entry
with &(&init_task)->tasks as its paramter,current 5414, insmod
2# PID: 1, name: init
2# PID: 2, name: migration/0
2# PID: 3, name: ksoftirqd/0
2# PID: 4, name: events/0
2# PID: 5, name: khelper
2# PID: 6, name: kthread
2# PID: 8, name: kblockd/0
2# PID: 9, name: kacpid
2# PID: 103, name: pdflush
2# PID: 104, name: pdflush
2# PID: 106, name: aio/0
2# PID: 105, name: kswapd0
2# PID: 312, name: cqueue/0
2# PID: 313, name: kseriod
2# PID: 353, name: kpsmoused
2# PID: 739, name: scsi_eh_0
2# PID: 835, name: reiserfs/0
2# PID: 928, name: udevd
2# PID: 1347, name: khubd
2# PID: 1409, name: kgameportd
2# PID: 2191, name: dbus-daemon
2# PID: 2193, name: acpid
2# PID: 2229, name: syslog-ng
2# PID: 2233, name: klogd
2# PID: 2358, name: resmgrd
2# PID: 2482, name: hald
2# PID: 2553, name: hald-addon-acpi
2# PID: 2559, name: dhcdbd
2# PID: 2566, name: NetworkManagerD
2# PID: 2571, name: NetworkManager
2# PID: 2601, name: mdnsd
2# PID: 2626, name: auditd
2# PID: 2637, name: kauditd
2# PID: 2650, name: portmap
2# PID: 2669, name: hald-addon-stor
2# PID: 2702, name: dhclient
2# PID: 2706, name: cupsd
2# PID: 2830, name: master
2# PID: 2845, name: pickup
2# PID: 2846, name: qmgr
2# PID: 2859, name: cron
2# PID: 3012, name: powersaved
2# PID: 3023, name: smpppd
2# PID: 3094, name: sshd
2# PID: 3106, name: gdm
2# PID: 3116, name: startpar
2# PID: 3125, name: gdm
2# PID: 3131, name: X
2# PID: 3282, name: mingetty
2# PID: 3283, name: mingetty
2# PID: 3284, name: mingetty
2# PID: 3285, name: mingetty
2# PID: 3286, name: mingetty
2# PID: 3294, name: mingetty
2# PID: 3480, name: racoon
2# PID: 3501, name: gnome-session
2# PID: 3531, name: scim-launcher
2# PID: 3535, name: scim-helper-man
2# PID: 3536, name: scim-panel-gtk
2# PID: 3538, name: scim-launcher
2# PID: 3552, name: gpg-agent
2# PID: 3553, name: ssh-agent
2# PID: 3559, name: dbus-launch
2# PID: 3560, name: dbus-daemon
2# PID: 3564, name: gconfd-2
2# PID: 3569, name: gnome-keyring-d
2# PID: 3571, name: bonobo-activati
2# PID: 3573, name: esd
2# PID: 3577, name: gnome-settings-
2# PID: 3579, name: metacity
2# PID: 3587, name: gnome-panel
2# PID: 3589, name: nautilus
2# PID: 3592, name: main-menu
2# PID: 3594, name: mono
2# PID: 3603, name: resapplet
2# PID: 3606, name: iprint-listener
2# PID: 3609, name: zen-updater
2# PID: 3611, name: gnome-vfs-daemo
2# PID: 3624, name: gnome-power-man
2# PID: 3626, name: application-bro
2# PID: 3627, name: gnome-volume-ma
2# PID: 3641, name: nm-applet
2# PID: 3667, name: gnome-screensav
2# PID: 3669, name: gnome-terminal
2# PID: 3670, name: gnome-pty-helpe
2# PID: 3671, name: bash
2# PID: 2883, name: zmd
2# PID: 5414, name: insmod
2# PID: 5415, name: udevd
2# total: 89
注意 少了insmod,多了swapper
¤t->tasks (current指向的是insmod的task_struct)此时作为表头,原因和2#相同,表头所在大结构体不会被list_for_each_entry列出。所以insmod没被列举出来。但是2#中的”表头”(现在的角色成了节点中的list_head)所在的大结构体被列举了。也就是swapper被列举出来了。
我们可以这样想象出整个链表的样子,按照PID大小顺序 swapper<->init<->migration/0<-> … <->insmod<->udevd 注意链表两头我没把连起来。在这次中,因为insmod没列出,第一个列出的是insmod后面的udevd,因为是双向链表,所以下一个就列出swapper。接着….
我们看到,刚好2#中”表头”所在大结构体也是tast_struct,这个程序看起来正常。如果是其他结构体,它照样也会返回一个”虚拟的”tast_struct指针回来。如果对这个”虚拟的”tast_struct乱操作一通,实际作用的却是其他不明物体,结果可想而知.
testing for list_for_each_entry
with ¤t->tasks as its paramter,current 5414, insmod
3# PID: 5415, name: udevd
3# PID: 0, name: swapper
3# PID: 1, name: init
3# PID: 2, name: migration/0
3# PID: 3, name: ksoftirqd/0
3# PID: 4, name: events/0
3# PID: 5, name: khelper
3# PID: 6, name: kthread
3# PID: 8, name: kblockd/0
3# PID: 9, name: kacpid
3# PID: 103, name: pdflush
3# PID: 104, name: pdflush
3# PID: 106, name: aio/0
3# PID: 105, name: kswapd0
3# PID: 312, name: cqueue/0
3# PID: 313, name: kseriod
3# PID: 353, name: kpsmoused
3# PID: 739, name: scsi_eh_0
3# PID: 835, name: reiserfs/0
3# PID: 928, name: udevd
3# PID: 1347, name: khubd
3# PID: 1409, name: kgameportd
3# PID: 2191, name: dbus-daemon
3# PID: 2193, name: acpid
3# PID: 2229, name: syslog-ng
3# PID: 2233, name: klogd
3# PID: 2358, name: resmgrd
3# PID: 2482, name: hald
3# PID: 2553, name: hald-addon-acpi
3# PID: 2559, name: dhcdbd
3# PID: 2566, name: NetworkManagerD
3# PID: 2571, name: NetworkManager
3# PID: 2601, name: mdnsd
3# PID: 2626, name: auditd
3# PID: 2637, name: kauditd
3# PID: 2650, name: portmap
3# PID: 2669, name: hald-addon-stor
3# PID: 2702, name: dhclient
3# PID: 2706, name: cupsd
3# PID: 2830, name: master
3# PID: 2845, name: pickup
3# PID: 2846, name: qmgr
3# PID: 2859, name: cron
3# PID: 3012, name: powersaved
3# PID: 3023, name: smpppd
3# PID: 3094, name: sshd
3# PID: 3106, name: gdm
3# PID: 3116, name: startpar
3# PID: 3125, name: gdm
3# PID: 3131, name: X
3# PID: 3282, name: mingetty
3# PID: 3283, name: mingetty
3# PID: 3284, name: mingetty
3# PID: 3285, name: mingetty
3# PID: 3286, name: mingetty
3# PID: 3294, name: mingetty
3# PID: 3480, name: racoon
3# PID: 3501, name: gnome-session
3# PID: 3531, name: scim-launcher
3# PID: 3535, name: scim-helper-man
3# PID: 3536, name: scim-panel-gtk
3# PID: 3538, name: scim-launcher
3# PID: 3552, name: gpg-agent
3# PID: 3553, name: ssh-agent
3# PID: 3559, name: dbus-launch
3# PID: 3560, name: dbus-daemon
3# PID: 3564, name: gconfd-2
3# PID: 3569, name: gnome-keyring-d
3# PID: 3571, name: bonobo-activati
3# PID: 3573, name: esd
3# PID: 3577, name: gnome-settings-
3# PID: 3579, name: metacity
3# PID: 3587, name: gnome-panel
3# PID: 3589, name: nautilus
3# PID: 3592, name: main-menu
3# PID: 3594, name: mono
3# PID: 3603, name: resapplet
3# PID: 3606, name: iprint-listener
3# PID: 3609, name: zen-updater
3# PID: 3611, name: gnome-vfs-daemo
3# PID: 3624, name: gnome-power-man
3# PID: 3626, name: application-bro
3# PID: 3627, name: gnome-volume-ma
3# PID: 3641, name: nm-applet
3# PID: 3667, name: gnome-screensav
3# PID: 3669, name: gnome-terminal
3# PID: 3670, name: gnome-pty-helpe
3# PID: 3671, name: bash
3# PID: 2883, name: zmd
3# total: 89
总结:1. 在实际中,通常表头外面是有个大结构的。这点上ulk的插图有点误导作用。这个大结构体和节点的大结构体是否一样,两者没什么联系。
2. 表头所在大结构体不会被list_for_each_entry列出。
3. 类似地,list_for_each也不会返回表头指针
4. “表头”如何理解?
这涉及 从链接中间开始遍历行不行?如果从中间开始遍历,遍历到”所谓末尾”后会不会(当然会)倒过来遍历”前面”部分等等奇形怪状的问题。
其实源码注释得很明白
@head: the head for your list. head是你链表表头(的指针)
list_for_each(pos, head)
ist_for_each_entry(pos, head, member)
依据2.3.可见,凡是把你关心的研究对象(单个list_head,或它所在的大结构体)中的list_head指针作为了这两个宏的head参数,都是错误的。
(注意:其他宏的源码,暂时没看。对于遍历的宏,结论应该通用)
附Makefile
obj-m += list.o
CC = gcc
all:
make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) modules
clean:
@rm -rf *.o *.ko *.mod.c .*.cmd .*.d Modules.symvers
make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) clean
TOADD
task 链表的形成
clone()等C函数–>调用sys_clone()族系统调用–>do_fork()–>copy_process()–>SET_LINKS(p)
宏
#define SET_LINKS(p) do { \
if (thread_group_leader(p)) \
list_add_tail(&(p)->tasks,&init_task.tasks); \
add_parent(p, (p)->parent); \
} while (0)
补充
兄弟链表的形成,可见父进程的children域是各子进程sibling域所形成链表的表头
#define add_parent(p, parent) list_add_tail(&(p)->sibling,&(parent)->children)
hash表的形成
copy_process()–>
attach_pid(p, PIDTYPE_PID, p->pid);
attach_pid(p, PIDTYPE_TGID, p->tgid);
if (thread_group_leader(p)) {
attach_pid(p, PIDTYPE_PGID, process_group(p));
attach_pid(p, PIDTYPE_SID, p->signal->session);
if (p->pid)
__get_cpu_var(process_counts)++;
}
–>
int fastcall attach_pid(task_t *task, enum pid_type type, int nr)
{
struct pid *pid, *task_pid;
task_pid = &task->pids[type];
pid = find_pid(type, nr);
if (pid == NULL) {
hlist_add_head(&task_pid->pid_chain,
&pid_hash[type][pid_hashfn(nr)]);
INIT_LIST_HEAD(&task_pid->pid_list);
} else {
INIT_HLIST_NODE(&task_pid->pid_chain);
list_add_tail(&task_pid->pid_list, &pid->pid_list);
}
task_pid->nr = nr;
return 0;
}