咦,奇怪,这个cgroup_subsys[]数组里面居然是一个头文件。编译器在编译的时候会展开头文件<linux/cgroup_subsys.h>:
... SUBSYS(cpuset) SUBSYS(cpu) SUBSYS(cpuacct) SUBSYS(io) SUBSYS(memory) SUBSYS(devices) SUBSYS(freezer) SUBSYS(net_cls) SUBSYS(perf_event) SUBSYS(net_prio) SUBSYS(hugetlb) SUBSYS(pids) SUBSYS(debug) ..... 为了更好的理解这个头文件内容,我去掉了一些边边角角,就得到上面的代码。即cgroup_subsys[]看起来有点像这样: #define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys, static struct cgroup_subsys *cgroup_subsys[] = { SUBSYS(cpuset) SUBSYS(cpu) SUBSYS(cpuacct) SUBSYS(io) SUBSYS(memory) SUBSYS(devices) SUBSYS(freezer) SUBSYS(net_cls) SUBSYS(perf_event) SUBSYS(net_prio) SUBSYS(hugetlb) SUBSYS(pids) SUBSYS(debug) }; #undef SUBSYS 我们还注意到"SUBSYS()" 在这里宏定义成了这个东西: #define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys, 将这个“SUBSYS”宏展开代入到cgroup_subsys[]中,看起来就是这样: static struct cgroup_subsys *cgroup_subsys[] = { [cpuset_cgrp_id] = &cpuset_cgrp_subsys, [cpu_cgrp_id] = &cpu_cgrp_subsys, [cpuacct_cgrp_id] = &cpuacct_cgrp_subsys, [io_cgrp_id] = &_cgrp_subsys, [memory_cgrp_id] = &memory_cgrp_subsys, [devices_cgrp_id] = &devices_cgrp_subsys, [freezer_cgrp_id] = &freezer_cgrp_subsys, [net_cls_cgrp_id] = &net_cls_cgrp_subsys, [perf_event_cgrp_id] = &perf_event_cgrp_subsys, [net_prio_cgrp_id] = &net_prio_cgrp_subsys, [hugetlb_cgrp_id] = &_hugetlbcgrp_subsys, [pids_cgrp_id] = &pids_cgrp_subsys, [debug_cgrp_id] = &debug_cgrp_subsys, }; God,我们很接近真面目了,cgroup_subsys[]数组中的各个元素可以猜到就是&cpuset_cgrp_subsys,&cpuset_cgrp_subsys,&cpuacct_cgrp_subsys,&io_cgrp_subsys......这些就是cgroup中各个子系统cgroup_subsys的全局变量结构。这些xxx_cgrp_subsys全局变量在内核编译好后就已经初始化ok、分配好空间。我们拿cpu子系统struct cgroup_subsys cpu_cgrp_subsys这个结构来举例,它定义在kernel/sched/core.c文件中:
struct cgroup_subsys cpu_cgrp_subsys = { .css_alloc = cpu_cgroup_css_alloc, .css_released = cpu_cgroup_css_released, .css_free = cpu_cgroup_css_free, .fork = cpu_cgroup_fork, .can_attach = cpu_cgroup_can_attach, .attach = cpu_cgroup_attach, .legacy_cftypes = cpu_files, .early_init = 1, }; 好了,说完了各个元素,我们再来说说数组中元素的index:"_x## _cgrp_id"。各个元素的索引"_x## _cgrp_id"也是通过SUBSY宏的把戏在include/linux/cgroup-defs.h中定义的:
/* define the enumeration of all cgroup subsystems */ #define SUBSYS(_x) _x ## _cgrp_id, #define SUBSYS_TAG(_t) CGROUP_ ## _t, \ __unused_tag_ ## _t = CGROUP_ ## _t - 1, enum cgroup_subsys_id { #include <linux/cgroup_subsys.h> CGROUP_SUBSYS_COUNT, }; #undef SUBSYS_TAG #undef SUBSYS 有了前面对cgroup_subsys[]定义的分析,这里应该是轻车熟路了。即各个子系统的索引id "_x## _cgrp_id" 是通过枚举类型enum cgroup_subsys_id {} + <linux/cgroup_subsys.h> + SUBSYS(_x)宏来定义的。好了,这样以来,有了数组元素索引 和 数组元素,自然这个cgroup_subsys[]元素的定义也就终于真想大白了。
你,懂了么?
最后讲一点,为什么cgroup_subsys[]的定义要通过SUBSYS()宏 + "#include <linux/cgroup_subsys.h>" 的方式来定义呢?因为在内核中,有多个cgroup相关的结构都要用到子系统相关的名字的定义,如上面的xxx_cgrp_id以及xxx_cgrp_subsys等等。这样定义的好处就是提高了代码复用率,减少了重复代码。各种相关定义不用再写一长串,只需要短短几行就可以定义完成。
