当前位置:首页>Linux>Linux休眠唤醒之主动休眠

Linux休眠唤醒之主动休眠

  • 2026-10-11 08:10:31
Linux休眠唤醒之主动休眠

更多内容可以加入Linux系统知识库套餐(教程+视频+答疑)

文章目录

  • 01、休眠唤醒(主动休眠)
  • 一、如何让linux进入睡眠
    • ① freeze
    • ② Standby
    • ③ mem
    • ④ disk
  • 二、suspend的入口函数
  • 三、电源管理操作的两个重要结构
  • 四、suspend的几个阶段
  • 五、suspend各阶段工作
  • 六、外设 suspend 案例

沉淀、分享、成长,让自己和他人都能有所收获!😄

01、休眠唤醒(主动休眠)

一、如何让linux进入睡眠


用户可以通过读写sys文件 “/sys/power/state” 控制系统进入休眠, 例如, echo mem > /sys/power/state可以让系统休眠(状态保存到内存), 可选的state如下:

  1. state : Freeze / Low-Power IdleACPI state: S0String: “freeze”

  2. State : Standby / Power-On Suspend ACPI State: S1 String: “standby”

  3. State : Suspend-to-RAM------<ACPI State: S3String: “mem”

  4. State : Suspend-to-disk ACPI State: S4 String: “disk”

具体可用的state在每个系统上有可能不一样, 使用cat /sys/power/state可以获取系统支持的sate。

/sys/power/state文件用于将系统置于指定的电源状态(freeze,standby, mem, disk),有些系统是不会全部有的,一般会有其中一种或者几种。 用户空间往该文件写入特定的电源状态字符串,将会把系统置为该模式,这几种状态的解释如下:

① freeze

冻结I/O设备,将它们置于低功耗状态,使处理器进入空闲状态,处于S2Idle状态下时,设备中断就可以将其唤醒。

② Standby

除了冻结I/O设备外,还会暂停系统。由于系统核心逻辑单元保持上电状态,操作的状态不会丢失,也会很容易恢复到之前的状态。 处于Standby状态时,可能需要依赖平台来设置唤醒源。

③ mem

运行状态数据存到内存,并关闭外设,进入等待模式,除了Memory需要进行自刷新来保持数据外,其他的所有设备都需要进入到低功耗状态,就是STR(Suspend to RAM)。除了实现Standby中的操作外,还有一些平台相关的操作要进行。 由于存在掉电行为,因此Resume的时候需要重新进行配置,唤醒过程较慢,处于STR状态时,需要依赖平台设置唤醒源。

④ disk

这个操作会将运行时的context保存在Disk这种非易失的存储器中,然后进行掉电操作,就是STD(Suspend-to-Disk)。比如当按下电源键进行唤醒时,然后恢复,唤醒过程最慢。

上面四种状态,功耗节省效果依次增强,同时唤醒回来的时间开销也相应加大。

二、suspend的入口函数


在”kernel/power/suspend.c”中定义了suspend的入口函数 pm_suspend()

int pm_suspend(suspend_state_t state)
{
                ......
                error = enter_state(state);
                ......
}
EXPORT_SYMBOL(pm_suspend);

调用enter_state进入suspend状态, 具体的状态根据state值而定, 如果执行成功的话, 一直到系统退出suspend的状态后此函数才退出。

三、电源管理操作的两个重要结构


struct dev_pm_ops {
        int (*prepare)(struct device *dev);
        void (*complete)(struct device *dev);
        int (*suspend)(struct device *dev);//休眠
        int (*resume)(struct device *dev);//唤醒
        int (*freeze)(struct device *dev);
        int (*thaw)(struct device *dev);
        int (*poweroff)(struct device *dev);
        int (*restore)(struct device *dev);
        int (*suspend_late)(struct device *dev);
        int (*resume_early)(struct device *dev);
        int (*freeze_late)(struct device *dev);
        int (*thaw_early)(struct device *dev);
        int (*poweroff_late)(struct device *dev);
        int (*restore_early)(struct device *dev);
        int (*suspend_noirq)(struct device *dev);
        int (*resume_noirq)(struct device *dev);
        int (*freeze_noirq)(struct device *dev);
        int (*thaw_noirq)(struct device *dev);
        int (*poweroff_noirq)(struct device *dev);
        int (*restore_noirq)(struct device *dev);
        int (*runtime_suspend)(struct device *dev);
        int (*runtime_resume)(struct device *dev);
        int (*runtime_idle)(struct device *dev);
};

struct platform_suspend_ops {
        int (*valid)(suspend_state_t state);
        int (*begin)(suspend_state_t state);
        int (*prepare)(void);
        int (*prepare_late)(void);
        int (*enter)(suspend_state_t state);
        void (*wake)(void);
        void (*finish)(void);
        bool (*suspend_again)(void);
        void (*end)(void);
        void (*recover)(void);
};

四、suspend的几个阶段


如果在编译内核时打开了”CONFIG_PM_DEBUG“, 则会在出现“/sys/power/pm_test”属性文件, 在pm_test中定义了一下几个阶段:

int pm_test_level = TEST_NONE;

static const char * const  pm_tests[__TEST_AFTER_LAST] = {
   [TEST_NONE] = "none",
   [TEST_CORE] = "core",
   [TEST_CPUS] = "processors",
   [TEST_PLATFORM] = "platform",
   [TEST_DEVICES] = "devices",
   [TEST_FREEZER] = "freezer",
};

向“/sys/power/pm_test”中写入0~5, 可以使得系统进入对应的(0对应”none”, 5对应”freezer”)suspend阶段,进入suspend状态时, 依次所经历的阶段为 ‘freezer’ -> ‘devices’ -> ‘processors’ -> ‘core’ 。 cat /sys/power/pm_test可以获取系统当前所处的阶段(使用‘[]’括起来的状态)。

五、suspend各阶段工作


suspend和resume时, 各个阶段的工作如下:

/*suspend-[freezer]*/

                pm_suspend() -->
                        enter_state() -->
[1]                                suspend_sync() -->
                        suspend_prepare() -->
[2]                                pm_prepare_console() -->
[3]                            pm_notifier_call_chain() -->
[4]                            suspend_freeze_processes() -->
                                suspend_prepare() <--
  1. _suspend_sync :_同步文件系统, 将高速缓存内容回写到磁盘

  2. _pm_prepare_console:_分配一个控制台, 用于输出消息

  3. 发送PM_SUSPEND_PREPARE消息,激活pm注册的内核通知链(内核通知链一般用于内核子系统之间的消息通知)

  4. _suspend_freeze_processes:_冻结任务, 包括用户进程, usermode helper进程(内核中启动的用户进程),以及可以冻结的内核线程

/*suspend-[device]*/

                                suspend_devices_and_enter() -->  
[5]                                        suspend_ops->begin() -->
[6]                                        suspend consle() -->
                                        dpm_suspend_start() -->
[7]                                        dpm_prepare() -->
[8]                                            dpm_suspend() -->
                                        dpm_suspend_start() <--

5.调用suspend_ops(板级电源管理操作)的begin回调 6.suspend consle子系统, 此后,不能输出内核消息 7.调用pm_ops(电源管理操作)的prepare回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->prepare) 8.调用pm_ops(电源管理操作)的suspend回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->suspend)

/*suspend-[platform]*/    

        suspend_enter() -->
[9]              suspend_ops->prepare() -->
        dpm_suspend_end() -->
[10]                            dpm_suspend_late() -->
[11]                        dpm_suspend_noirq() -->
                            dpm_suspend_end() <--
[12]                    suspend_ops->prepare_late() -->

9.调用suspend_ops(板级电源管理操作)的prepare回调 10.调用pm_ops(电源管理操作)的suspend_late回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->suspend_late回调) 11.调用pm_ops(电源管理操作)的suspend_noirq回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->suspend_noirq回调) 12.调用suspend_ops(板级电源管理操作)的prepare_late回调

/*suspend-[cpu]*/

[13]                                         disable_nonboot_cpus() -->

13.关闭多核cpu中的非启动cpu

/*suspend-[core]*/                                                
[14]                    arch_suspend_disable_irqs() -->
[15]                                        syscore_suspend() -->
[16]                    suspend_ops->enter() -->

14.禁止中断 15.调用所有system core(例如cpu频率, timer等)注册的supend回调 16.调用suspend_ops(板级电源管理操作)的enter回调, 真正进入suspend,当被唤醒时, 才返回

/*resume-[core]*/

[17]                                        syscore_resume() -->
[18]                    arch_suspend_enable_irqs() -->  

17.调用所有system core(例如cpu频率, timer等)注册的resume回调, 执行的时候,只有一个cpu核工作且中断关闭 18.打开中断

/*resume-[cpu]*/

[19]                                         enable_nonboot_cpus() -->

19.打开多核cpu中的非启动cpu

/*resume-[platform]*/

[20]                                        suspend_ops->wake() -->
                            dpm_resume_start() -->
[21]                                   dpm_resume_noirq() -->
[22]                            dpm_resume_early() -->
                            dpm_resume_start() <--
[23]                    suspend_ops->finish() -->
                                        suspend_enter() <--

20.调用suspend_ops(板级电源管理操作)的wake回调 21.调用pm_ops(电源管理操作)的resume_noirq回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->resume_noirq回调) 22.调用pm_ops(电源管理操作)的resume_early回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->resuem_early回调) 23.调用suspend_ops(板级电源管理操作)的finish回调

/*resume-[device] */

[24]                                suspend_ops->recover() -->
                        dpm_resume_end() -->
[25]                                        dpm_resume() -->  
[26]                                        dpm_complete() -->  
                        dpm_resume_end() <--
[27]                resume_console() -->
[28]                suspend_ops->end()-->
                    suspend_devices_and_enter() <--

24.调用suspend_ops(板级电源管理操作)的recover回调 25.调用pm_ops(电源管理操作)的resume回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->resume) 26.调用pm_ops(电源管理操作)的complete回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->complete) 27.恢复用于输出消息的控制台 28.调用suspend_ops(板级电源管理操作)的recover回调

/*resume-[freezer]*/

                                suspend_finish() -->
[29]                               suspend_thaw_processes() -->
[30]                                pm_notifier_call_chain() -->
[31]                                pm_restore_console() -->
                               suspend_finish() <--
                           enter_state() <--
                pm_suspend() <--

29.解冻冻结的任务 30.发送PM_POST_SUSPEND消息, 激活pm注册的内核通知链(内核通知链一般用于内核子系统之间的消息通知) 31.恢复用于输出消息的控制台

六、外设 suspend 案例

最新文章

随机文章