Linux内核休眠流程

Kernel-5.10 内核休眠流程

用途: Linux的suspend机制是一种节能技术,用于将计算机的当前状态保存起来,然后进入休眠状态,以节省能源。在休眠状态下,计算机的硬件设备会停止工作,而保存的计算机状态被保存在内存或磁盘中。在用户空间向“/sys/power/state”文件分别写入“freeze”、“standby”和“mem”,即可触发它们。

1.内核休眠状态

1.1 电源管理休眠状态

电源管理休眠状态 说明
freeze 冻结I/O设备,将它们置于低功耗状态,使处理器进入空闲状态,唤醒最快,耗电比其它standby, mem, disk方式高
standby 除了冻结I/O设备外,还会暂停系统,唤醒较快,耗电比其它 mem, disk方式高
mem 将运行状态数据存到内存,并关闭外设,进入等待模式,唤醒较慢,耗电比disk方式高
disk 将运行状态数据存到硬盘,然后关机,唤醒最慢

内核源码路径:msm-kernel/kernel/power/
查看电源管理状态路径:cat /sys/power/state
手动执行休眠:echo standby > /sys/power/state

1.2 内核休眠状态

状态 ACPI等级 动作 进入方式
Suspend-to-idle S0 冻结用户空间程序
停止时间管理
IO设为低功耗状态
echo freeze > /sys/power/state

echo s2idle > /sys/power/mem_state
echo mem > /sys/power/state
Standby S1 包含Suspend-to-idle动作
非引导cpu下线
echo standby > /sys/power/state

echo shallow > /sys/power/mem_state
echo mem > /sys/power/state
Suspend-to-RAM S3 包含Standby所有动作
内存外所有设备进入低功耗状态
内存自动刷新
echo deep > /sys/power/mem_state
echo mem > /sys/power/state
Hibernation S4 创建内存快照保存至disk
内核停止所有系统活动
唤醒所有设备进入低功耗状态
echo disk > /sys/power/state

2 内核休眠流程

2.1 内核休眠流程图

内核路径:/msm-kernel/kernel/power/main.c
入口函数:state_store
在这里插入图片描述

2.2 电源管理休眠状态

路径:kernel/kernel5.4/include/linux/suspend.h
//表示系统处于完全开启状态,不进行任何挂起
#define PM_SUSPEND_ON ((__force suspend_state_t) 0)
//系统进入“空闲”模式,CPU 和设备可能处于低功耗状态,但系统仍然保持响应
#define PM_SUSPEND_TO_IDLE ((__force suspend_state_t) 1)
//系统处于待机状态,某些硬件组件可能已经进入低功耗模式,但系统仍然可以快速恢复
#define PM_SUSPEND_STANDBY ((__force suspend_state_t) 2)
//系统进入内存挂起状态(S3),系统状态保存在内存中允许快速恢复但消耗的电量较低
#define PM_SUSPEND_MEM ((__force suspend_state_t) 3)
#define PM_SUSPEND_MIN PM_SUSPEND_TO_IDLE
#define PM_SUSPEND_MAX ((__force suspend_state_t) 4)

2.3 休眠入口 - state_store函数

static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
			   const char *buf, size_t n)
{
   
	suspend_state_t state;
	int error;

	//获取电源自动休眠锁-保证state_store、mem_sleep_store、wakeup_count_store操作的完整性
	error = pm_autosleep_lock();
	if (error)
		return error;

	//如果已经是当前休眠状态的一种,就返回当前正忙
	if (pm_autosleep_state() > PM_SUSPEND_ON) {
   
		error = -EBUSY;
		goto out;
	}
	//根据输入的信息,解析要休眠的状态
	state = decode_state(buf, n);
	if (state < PM_SUSPEND_MAX) {
   
		if (state == PM_SUSPEND_MEM)
			state = mem_sleep_current;	//将当前休眠状态与内存休眠状态进行同步

		error = pm_suspend(state);	//执行休眠状态转换的操作
	} else if (state == PM_SUSPEND_MAX) {
   
		error = hibernate(); //执行系统休眠并保存镜像
	} else {
   
		error = -EINVAL;
	}
 out:
	pm_autosleep_unlock();
	return error ? error : n;
}

2.4 休眠执行函数 - pm_suspend

int pm_suspend(suspend_state_t state)
{
   
	int error;
	//判断休眠状态的类型
	if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)
		return -EINVAL;
	//显示当前内存的休眠状态
	pr_info("suspend entry (%s)\n", mem_sleep_labels[state]);
	error = enter_state(state);//设置当前状态
	if (error) {
   
		suspend_stats.fail++;		//休眠状态错误计数器增加计数
		dpm_save_failed_errno(error);
	} else {
   
		suspend_stats.success++;	//休眠状态成功计数器增加计数
	}
	pr_info("suspend exit\n");
	return error;
}
EXPORT_SYMBOL(pm_suspend);

2.5 休眠状态执行函数 - enter_state

执行进入系统睡眠状态所需的常见工作。

static int enter_state(suspend_state_t state)
{
   
	int error;

	//跟踪和记录系统的挂起(suspend)和恢复(resume)事件
	trace_suspend_resume(TPS("suspend_enter"), state, true);
	if (state == PM_SUSPEND_TO_IDLE) {
   
#ifdef CONFIG_PM_DEBUG
		//调试信息日志
		if (pm_test_level != TEST_NONE && pm_test_level <= TEST_CPUS) {
   
			pr_warn("Unsupported test mode for suspend to idle, please choose none/freezer/devices/platform.\n");
			return -EAGAIN;
		}
#endif
	//判断当前设置的状态是否是有效状态
	} else if (!valid_state(state)) {
   
		return -EINVAL;
	}
	//获取系统过度互斥锁
	if (!mutex_trylock(&system_transition_mutex))
		return -EBUSY;

	if (state == PM_SUSPEND_TO_IDLE)
		s2idle_begin();	//更新 s2idle_state状态为S2IDLE_STATE_NONE
	//同步开关:文件系统,同步更新数据到块设备 配置:sync_on_suspend文件节点
	if (sync_on_suspend_enabled) {
   
		trace_suspend_resume(TPS("sync_filesystems"), 0, true);
		ksys_sync_helper();
		trace_suspend_resume(TPS("sync_filesystems"), 0, false);
	}
	pm_pr_dbg("Preparing system for sleep (%s)\n", mem_sleep_labels[state]);
	//更新pm_suspend_global_flags标志位
	pm_suspend_clear_flags();
	error = suspend_prepare(state);//作用:做休眠前的准备工作
	if (error)
		goto Unlock;
	if (suspend_test(TEST_FREEZER))
		goto Finish;
	trace_suspend_resume(TPS("suspend_enter"), state, false);
	pm_pr_dbg("Suspending system (%s)\n", mem_sleep_labels[state]);
	//限制内存分配
	pm_restrict_gfp_mask();
	
	error = suspend_devices_and_enter(state);	//进入设备休眠执行函数
	//恢复内存分配
	pm_restore_gfp_mask();

 Finish:
	events_check_enabled = false;
	pm_pr_dbg("Finishing wakeup.\n");
	//休眠完成
	suspend_finish();
 Unlock:
	mutex_unlock(&system_transition_mutex);
	return error;
}

2.6 休眠前准备函数 - suspend_prepare

准备进入系统睡眠状态
目标:为所有可以进入的系统睡眠状态(除休眠外)运行通用代码。运行挂起通知程序,分配“挂起”控制台并冻结进程。

static int suspend_prepare(suspend_state_t state)
{
   
	int error;

	if (!sleep_state_supported(state))  //判断状态是否为 PM_SUSPEND_TO_IDLE
		return -EPERM;

    //挂起控制台 - pm_vt_switch虚拟终端切换判断;
	//vt_move_to_console(SUSPEND_CONSOLE, 1);将当前的前台控制台切换到指定的挂起控制台
	//vt_kmsg_redirect(SUSPEND_CONSOLE);将内核消息重定向到挂起控制台
	pm_prepare_console();

	//通知部分设备做睡眠前的准备工作
	error = pm_notifier_call_chain_robust(PM_SUSPEND_PREPARE, PM_POST_SUSPEND);
	if 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值