本文部分内容参考Linux Thermal 学习笔记 - 爱码网。特此致谢!
接前一篇文章Linux内核Thermal框架详解三、Thermal Core(2)
原本thermal_register_governors属于下一级函数,在前篇文章已经介绍过了。但是由于其重要性,因此将它提升一级,并且在本篇文章中进行更详细解析。再次列出函数源码,位于drivers/thermal/thermal_core.c中,如下所示:
static void __init thermal_unregister_governors(void)
{struct thermal_governor **governor;for_each_governor_table(governor)thermal_unregister_governor(*governor);
}static int __init thermal_register_governors(void)
{int ret = 0;struct thermal_governor **governor;for_each_governor_table(governor) {ret = thermal_register_governor(*governor);if (ret) {pr_err("Failed to register governor: '%s'",(*governor)->name);break;}pr_info("Registered thermal governor '%s'",(*governor)->name);}if (ret) {struct thermal_governor **gov;for_each_governor_table(gov) {if (gov == governor)break;thermal_unregister_governor(*gov);}}return ret;
}
thermal_register_governor函数的总体功能是将所有的governor策略(step_wise、power_alloctor、user_space、fair_share等)默认都注册给kernel。
下边对于关键代码进行分析。
(1)for_each_governor_table
for_each_governor_table是一个宏定义,在drivers/thermal/thermal_core.h中,代码如下:
#define for_each_governor_table(__governor) \for (__governor = __governor_thermal_table; \__governor < __governor_thermal_table_end; \__governor++)
__governor_thermal_table的定义直接搜索是找不到的,只是在同文件中有一个extern的引用。如下所示:
extern struct thermal_governor *__governor_thermal_table[];
extern struct thermal_governor *__governor_thermal_table_end[];
那么__governor_thermal_table的定义到底在什么地方?这得从THERMAL_TABLE宏说起。
THERMAL_TABLE宏在include/asm-generic/vmlinux.lds.h中,代码如下:
#ifdef CONFIG_THERMAL
#define THERMAL_TABLE(name) \. = ALIGN(8); \__##name##_thermal_table = .; \KEEP(*(__##name##_thermal_table)) \__##name##_thermal_table_end = .;
#else
#define THERMAL_TABLE(name)
#endif
在配置了THERMAL选项的时候,才会有内容。假设有这样的定义THERMAL_TABLE(governor),那么实际展开来,代码为:
. = ALIGN(8); \
__governor_thermal_table = .; \
KEEP(*(__governor_thermal_table)) \
__governor_thermal_table_end = .;
看到我们要找的__governor_thermal_table了吧,就是在这里最终出现了。
到此,还有一个问题没有弄清楚:我们上边是假设有THERMAL_TABLE(governor)的代码,那么真正调用THERMAL_TABLE宏的代码在哪里?
其实是在同文件(include/asm-generic/vmlinux.lds.h)中,代码如下:
/* init and exit section handling */
#define INIT_DATA \KEEP(*(SORT(___kentry+*))) \*(.init.data init.data.*) \MEM_DISCARD(init.data*) \KERNEL_CTORS() \MCOUNT_REC() \*(.init.rodata .init.rodata.*) \FTRACE_EVENTS() \TRACE_SYSCALLS() \KPROBE_BLACKLIST() \ERROR_INJECT_WHITELIST() \MEM_DISCARD(init.rodata) \CLK_OF_TABLES() \RESERVEDMEM_OF_TABLES() \TIMER_OF_TABLES() \CPU_METHOD_OF_TABLES() \CPUIDLE_METHOD_OF_TABLES() \KERNEL_DTB() \IRQCHIP_OF_MATCH_TABLE() \ACPI_PROBE_TABLE(irqchip) \ACPI_PROBE_TABLE(timer) \THERMAL_TABLE(governor) \EARLYCON_TABLE() \LSM_TABLE() \EARLY_LSM_TABLE() \KUNIT_TABLE()
看到代码中的THERMAL_TABLE(governer)了吧,就是在这里。至于在哪里调用的INIT_DATA宏,在此就不再刨根问底了,毕竟不是本文的重点。
回到for_each_governor_table代码中,在弄清楚了全部细节之后,接着往下看整个代码段:
for_each_governor_table(governor) {ret = thermal_register_governor(*governor);if (ret) {pr_err("Failed to register governor: '%s'",(*governor)->name);break;}pr_info("Registered thermal governor '%s'",(*governor)->name);
}
展开:
for (__governor = __governor_thermal_table; \__governor < __governor_thermal_table_end; \__governor++) {ret = thermal_register_governor(*governor);if (ret) {pr_err("Failed to register governor: '%s'",(*governor)->name);break;}pr_info("Registered thermal governor '%s'",(*governor)->name);
}
这段代码的意思就比较明显了,遍历__governor_thermal_table中的每一项,进行注册。那么__governor_thermal_table中都包括了哪些项?又是什么时候加入进去的?且听我慢慢道来……
实际上,各个governor是通过 __section() 属性配合链接器脚本链接到一起的。以step_wise为例进行说明。
在drivers/thermal/gov_step_wise.c中有这样一行代码:
static struct thermal_governor thermal_gov_step_wise = {.name = "step_wise",.throttle = step_wise_throttle,
};
THERMAL_GOVERNOR_DECLARE(thermal_gov_step_wise);
THERMAL_GOVERNOR_DECLARE同样是宏,也是在drivers/thermal/thermal_core.h中,如下所示:
#define THERMAL_TABLE_ENTRY(table, name) \static typeof(name) *__thermal_table_entry_##name \__used __section("__" #table "_thermal_table") = &name#define THERMAL_GOVERNOR_DECLARE(name) THERMAL_TABLE_ENTRY(governor, name)
上边代码连同进一步的宏定义一起写出了。因此,完全展开来就是:
static typeof(thermal_gov_step_wise) *__thermal_table_entry_thermal_gov_step_wise __used __section("__governor_thermal_table") = &thermal_gov_step_wise
由于thermal_gov_step_wise的类型为struct thermal_governor,因此,最终展开为:
static struct thermal_governor *__thermal_table_entry_thermal_gov_step_wise \__used __section("__governor_thermal_table") = &thermal_gov_step_wise
这样,就完成了在__governor_thermal_table中添加一项thermal_gov_step_wise。
对于其它几种governor来说,都是同样的方法。在此,为了能够解析得更清晰、更彻底,列出全部的governor。
power_allocator在drivers/thermal/gov_power_allocator.c中:
static struct thermal_governor thermal_gov_power_allocator = {.name = "power_allocator",.bind_to_tz = power_allocator_bind,.unbind_from_tz = power_allocator_unbind,.throttle = power_allocator_throttle,
};
THERMAL_GOVERNOR_DECLARE(thermal_gov_power_allocator);
展开为:
static struct thermal_governor *__thermal_table_entry_thermal_gov_power_allocator \__used __section("__governor_thermal_table") = &thermal_gov_power_allocator
fair_share在drivers/thermal/gov_fair_share.c中:
static struct thermal_governor thermal_gov_fair_share = {.name = "fair_share",.throttle = fair_share_throttle,
};
THERMAL_GOVERNOR_DECLARE(thermal_gov_fair_share);
展开为:
static struct thermal_governor *__thermal_table_entry_thermal_gov_fair_share \__used __section("__governor_thermal_table") = &thermal_gov_fair_share
user_space在drivers/thermal/gov_user_space.c中:
static struct thermal_governor thermal_gov_user_space = {.name = "user_space",.throttle = notify_user_space,.bind_to_tz = user_space_bind,
};
THERMAL_GOVERNOR_DECLARE(thermal_gov_user_space);
展开为:
static struct thermal_governor *__thermal_table_entry_thermal_gov_user_space \__used __section("__governor_thermal_table") = &thermal_gov_user_space
bang_bang在drivers/thermal/gov_bang_bang.c中:
static struct thermal_governor thermal_gov_bang_bang = {.name = "bang_bang",.throttle = bang_bang_control,
};
THERMAL_GOVERNOR_DECLARE(thermal_gov_bang_bang);
展开为:
static struct thermal_governor *__thermal_table_entry_thermal_gov_bang_bang \__used __section("__governor_thermal_table") = &thermal_gov_bang_bang
欲知后事如何,且听下回分解。
上一篇:[算法]计数排序和基数排序