我正在阅读全文Linux 5.0.7源代码,我注意到一些奇怪的事情。我将linux
在这里称为父目录,如果社区在文献中使用其他命名约定,请纠正我。
在文件中,使用linux/include/asm-generic/param.h
该值。CONFIG_HZ
该值未在前面的行中定义,唯一包含的文件是uapi/asm-generic/param.h
.我相信这是指linux/include/uapi/asm-generic/param.h
,如果我错了,请再次纠正我。
在该文件中,没有CONFIG_HZ
定义过这样的值。现在,在普通的 C 程序中,这会导致错误。我们这里有 3 个选择:
- 我误解了一些东西,
linux/include/asm-generic/param.h
实际上包含了定义该值的另一个文件。 - 这是一个错误,我是发现它的天才(最不可能的选择)。
- 有一些“魔法”正在发生,比如 Linux 之前定义的一些宏,或者内核之前包含的一些文件,包括
linux/include/asm-generic/param.h
定义值的位置,这样当linux/include/asm-generic/param.h
调用时值就已经定义了。在这种情况下,请告诉我这个文件是什么。
如果这些都不成立,那么为什么这是一个正确的 C 程序?
答案1
与其他CONFIG_
值一样,CONFIG_HZ
是一个配置设置;你会发现它在kernel/Kconfig.hz
,以及其他Kconfig
文件中的各种特定于架构的覆盖。它的值在构建期间确定并存储在生成的配置文件include/generated/autoconf.h
.
后者包含在内核的构建命令中。要查看其实际效果,请选择一个包含 的文件asm/param.h
,并详细地构建其后处理后的等效项;例如
make drivers/atm/suni.i V=1
在构建的某个时刻你会看到
gcc -E -Wp,-MD,drivers/atm/.suni.i.d -nostdinc \
-isystem /usr/lib/gcc/x86_64-redhat-linux/8/include \
-I./arch/x86/include -I./arch/x86/include/generated \
-I./include -I./arch/x86/include/uapi \
-I./arch/x86/include/generated/uapi -I./include/uapi \
-I./include/generated/uapi \
-include ./include/linux/kconfig.h \
-include ./include/linux/compiler_types.h ...
-DMODULE -DKBUILD_BASENAME='"suni"' -DKBUILD_MODNAME='"suni"' \
-o drivers/atm/suni.i drivers/atm/suni.c
您可以在 中看到结果drivers/atm/suni.i
,并且展开HZ
和CONFIG_HZ
。
该-include ./include/linux/kconfig.h
指令确保始终包含内核配置。include/linux/kconfig.h
包括generated/autoconf.h
.
答案2
许多程序(例如 vim 或 firefox)都有许多编译选项。由于不同的原因你可以或必须在编译时选择一些选项。
对于 Linux,你有一个完整的系统:config
家族make
配置目标以逻辑分层方式配置 Kconfig“符号”,并提供良好的解释(在线帮助)。因为存在很多平台内和平台外的依赖关系。即使只是通过分页或 grep 这些“散布”各处的 Kconfig* 文件,您也可以获得基本信息(“如果不确定,请说是”,“如果您从未听说过 X,只需选择否”)
我很难从里面找到这个“HZ” make nconfig
。最后是F8
“SymSearch”,输入“HZ”(有或没有 CONFIG_ 它说 - 这非常用户友好!),你会得到如下搜索结果:
| Symbol: HZ_100 [=n]
| Prompt: 100 HZ
| Location:
| -> Processor type and features
| -> Timer frequency (<choice> [=y])
| Defined at kernel/Kconfig.hz:19
所以定时器频率是“处理器类型...”的子菜单。此 ncurses 弹出“窗口”包含“HZ 定义在哪里”的相关信息。 (“位置:”和“定义于”)
只需检查这 19 个 Kconfig 所在的位置(它们的目录名称),您就会得到一个好印象。Kconfig.hz
是./kernel/
其中之一。
]# find kernel mm block init ipc -name "Kconfig*" |wc
19 19 376
因此,在您从 kernel/Kconfig.hz (一个单独的文件!)中选择时间片(“jiffy”)值后,make
将以某种方式(Kbuild)为实际的编译器gcc
调用做好准备。 (详情请参阅其他答案)。
所以是的,某种魔法,一个用于 gcc 预处理器的自制预处理器(部分是 C 源代码!)。
CONFIG_xxx 主要用作布尔#ifdefs(条件编译——与 if...else 正交)。
...阅读整个 Linux 5.0.7 源代码的中间
]# find arch/x86/ include -name param.h
arch/x86/include/uapi/asm/param.h
include/uapi/linux/param.h
include/uapi/asm-generic/param.h
include/asm-generic/param.h
“创造魔法”和“头汤”之间有一条微妙的界限。感谢您的提示,我找到了一个不错的 find-prune-grep 序列。了解#preprocessor 和 CONFIG_ 是一回事。有时需要一些蛮力;对于完整搜索,修剪 drivers/ 通常是一个好主意。通过包含所有 arch/* 目录,这表明 alpha 是多么特殊。
以及 param.h 中的 asm 通用“#define HZ”的精确度:
]# find -name drivers -prune -o -name '*.[ch]' -exec grep "\<CONFIG_HZ\>" {} +
./arch/alpha/kernel/time.c: clockevents_config_and_register(ce, CONFIG_HZ, 0, 0);
./arch/alpha/kernel/time.c:#if CONFIG_HZ == 1024 || CONFIG_HZ == 1200
./arch/alpha/kernel/time.c:#elif CONFIG_HZ == 256 || CONFIG_HZ == 128 || CONFIG_HZ == 64 || CONFIG_HZ == 32
./arch/alpha/kernel/time.c: sel = RTC_REF_CLCK_32KHZ + __builtin_ffs(32768 / CONFIG_HZ);
./arch/alpha/kernel/time.c: CONFIG_HZ, sel);
./arch/alpha/kernel/setup.c:#if CONFIG_HZ == 1024 || CONFIG_HZ == 1200
./arch/alpha/kernel/setup.c: timer_freq = 100UL * CONFIG_HZ;
./arch/alpha/include/asm/param.h:# define HZ CONFIG_HZ
./arch/ia64/include/asm/param.h:# define HZ CONFIG_HZ
./include/asm-generic/param.h:# define HZ CONFIG_HZ /* Internal kernel timer frequency */
(我只触及了空白)
结果make config
(直接和间接 Kconfig 选择)最终在 /proc 中(如果此选项为 Y ;):
]# zcat /proc/config.gz |grep CONFIG_HZ
# CONFIG_HZ_PERIODIC is not set
# CONFIG_HZ_100 is not set
# CONFIG_HZ_250 is not set
CONFIG_HZ_300=y
# CONFIG_HZ_1000 is not set
CONFIG_HZ=300