Linux内核状态 system_state

基于msm-5.4

一、定义

/* 用于 system_state 的值,状态的顺序不得更改,代码检查时会用 <、<=、>、>= STATE */
extern enum system_states { //include/linux/kernel.h
    SYSTEM_BOOTING, //0, 最初没有赋值的时候的默认值
    SYSTEM_SCHEDULING,
    SYSTEM_RUNNING,
    SYSTEM_HALT,
    SYSTEM_POWER_OFF,
    SYSTEM_RESTART,
    SYSTEM_SUSPEND,
} system_state;

enum system_states system_state __read_mostly; //init/main.c


二、赋值路径

1. 内核启动

rest_init //init/main.c
    kernel_thread(kernel_init, NULL, CLONE_FS);
    kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
    system_state = SYSTEM_SCHEDULING;
    complete(&kthreadd_done); //唤醒init进程

kernel_init //init/main.c
    system_state = SYSTEM_RUNNING;

在唤醒init进程时,将系统状态 system_state 设置为 SYSTEM_SCHEDULING.

这里做这个设置原文有个注释:启用 might_sleep() 和 smp_processor_id() 检查。它们不能提前启用,因为使用 CONFIG_PREEMPTION=y kernel_thread() 会触发 might_sleep()。

init线程创建后将 system_state 设置为 SYSTEM_RUNNING。


2. reboot系统重启

reboot(cmd) //reboot.c 系统调用 cmd=CMD_RESTART 等
deferred_cad //reboot.c 传参NULL
__orderly_reboot //reboot.c 传参NULL
power_down //若hibernation_mode=HIBERNATION_REBOOT,则调用,传参NULL, 默认没使能CONFIG_HIBERNATION不执行
    kernel_restart(cmd) //reboot.c cmd=edl/recovery/bootloader/soc等
    kernel_kexec //kexec_core.c
        kernel_restart_prepare //reboot.c
            blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
            system_state = SYSTEM_RESTART;

reboot() //reboot.c 系统调用 cmd=CMD_HALT 时调用
    kernel_halt //reboot.c 传参 SYSTEM_HALT
reboot() //reboot.c 系统调用 cmd=POWER_OFF 时调用
    kernel_power_off //reboot.c 传参 SYSTEM_POWER_OFF
        kernel_shutdown_prepare(enum system_states state) //reboot.c
            blocking_notifier_call_chain(&reboot_notifier_list, state, NULL);
                system_state = state;

在系统重启,发出通知后,将 system_state 赋值为 SYSTEM_RESTART。在系统shutdown,发出通知后,将 system_state 赋值为设置的 state 值。


3. tick的freeze/unfreeze

tick_freeze //tick-common.c
    system_state = SYSTEM_SUSPEND;

tick_unfreeze
    system_state = SYSTEM_RUNNING;


4. 系统休眠唤醒

suspend_enter
    system_state = SYSTEM_SUSPEND;
    syscore_suspend
    system_state = SYSTEM_RUNNING;


三、使用案例

1. 内存初始化时判断是内核启动路径还是hotplug路径

void __ref build_all_zonelists(pg_data_t *pgdat) //page_alloc.c
{
    if (system_state == SYSTEM_BOOTING) {
        build_all_zonelists_init();
    } else {
        __build_all_zonelists(pgdat); //memory_hotplug.c 中应该会走这个路径
    }
}

 

posted on 2024-08-17 14:52  Hello-World3  阅读(37)  评论(0编辑  收藏  举报

导航