cgroup_subsys.h というヘッダがあって、cpuset の部分だけ抜き出すと
#if IS_ENABLED(CONFIG_CPUSETS) SUBSYS(cpuset) #endif
という風に SUBSYS
マクロの中に cpuset
のようなサブシステム名を与えているだけのヘッダファイルがあります。
この SUBSYS
マクロは cgroup.h と cgroup.c で計 4 回ほど定義されています。
まず最初に、cgroup.h で
#define SUBSYS(_x) _x ## _cgrp_id,
と定義されています。サブシステム名と _cgrp_id
という文字列を連結します。
直後に enum の定義があり、
enum cgroup_subsys_id { #include <linux/cgroup_subsys.h> CGROUP_SUBSYS_COUNT, };
上記のように、そこで cgroup_subsys.h が include されているので、さきほどの SUBSYS(cpuset)
が cpuset_cgrp_id
という風に展開されます。
つまり、
enum cgroup_subsys_id {
cpuset_cgrp_id,
となります。cgroup_subsys.h には、他に存在するサブシステムが (kernel の config で有効になっている場合に) SUBSYS(サブシステム名)
という風に定義されているので、(サブシステム名)_cgrp_id
という値をサブシステム分持つ enum が定義されます。そして、最後が CGROUP_SUBSYS_COUNT
となるわけですね。つまり、
enum cgroup_subsys_id {
cpuset_cgrp_id,
cpu_cgrp_id,
cpuacct_cgrp_id,
blkio_cgrp_id,
memory_cgrp_id,
devices_cgrp_id,
freezer_cgrp_id,
net_cls_cgrp_id,
perf_event_cgrp_id,
net_prio_cgrp_id,
hugetlb_cgrp_id,
debug_cgrp_id,
CGROUP_SUBSYS_COUNT,
};
という enum が完成します。直後に
#undef SUBSYS
と SUBSYS は undef されているので、ここで上記の enum を作って役割は終わりです。この CGROUP_SUBSYS_COUNT
はサブシステム分ループする場合に使えますね。例えばこんなふうに
#define for_each_subsys(ss, ssid) \ for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT && \ (((ss) = cgroup_subsys[ssid]) || true); (ssid)++)
そして、サブシステムの配列などで、それぞれのサブシステムの ID を表す (サブシステム名)_cgrp_id
という値が利用できます。あとは配列の領域確保のときに使われています。
もう 1 か所、cgroup.h に SUBSYS
の定義があります。
#define SUBSYS(_x) extern struct cgroup_subsys _x ## _cgrp_subsys; #include <linux/cgroup_subsys.h> #undef SUBSYS
サブシステム名を _cgrp_subsys
と連結して、extern struct cgroup_subsys
の後に書くので、例えば cpuset なら
extern struct cgroup_subsys cpuset_cgrp_subsys;
となります。cpuset_cgrp_subsys
変数は kernel/cpuset.c に定義がありますので、それの extern 宣言になりますね。同様に、有効になっている各サブシステムの cgroup_subsys
構造体ごとに宣言されます。
kernel/cgroup.c にも 2 ヶ所ほどあります。
/* generate an array of cgroup subsystem pointers */ #define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys, static struct cgroup_subsys *cgroup_subsys[] = { #include <linux/cgroup_subsys.h> }; #undef SUBSYS
最初に紹介した、サブシステム名と _cgrp_id
を連結した enum の id が使われていますね。これも同様に
[cpuset_cgrp_id] = &cpuset_cgrp_subsys,
という行が生成されますね。つまり cgroup_subsys
という配列の (サブシステム名)_cgrp_id
番目は (サブシステム名)_cgrp_subsys
へのポインタということです。
これは先に紹介した for_each_subsys
マクロで使われていましたね。
さいごに kernel/cgroup.c にあるのが、サブシステム名を命名するマクロです。
/* array of cgroup subsystem names */ #define SUBSYS(_x) [_x ## _cgrp_id] = #_x, static const char *cgroup_subsys_name[] = { #include <linux/cgroup_subsys.h> }; #undef SUBSYS
これもさきほどと同様の処理でサブシステム名の配列を作っています。配列の (サブシステム名)_cgrp_id
番目は (サブシステム名)
、つまり SUBSYS
マクロに指定した文字列となります。
[cpuset_cgrp_id] = cpuset,
つまり、カーネルが使うサブシステムに関わる構造体の配列とか ID とか名前の配列なんかは、カーネルの config 時 (make config
とか make menuconfig
とか) の時点で定義され、コンパイル時点で作成されるってことですね。
いやー、さすがカーネル開発するような人は賢いなあ (←言ってる人アホっぽい)