autosleep框架设计与实现

news2024/11/28 15:38:09

在低功耗系统中,autosleep是一个较小的模块,是低功耗主流程的入口。在Linux内核中,autosleep是休眠流程的触发点和入口点,PM Core的休眠流程入口pm_suspend()就是被autosleep的睡眠工作队列调用而进入休眠的。
image

该功能的支持受宏CONFIG_PM_AUTOSLEEP控制。
1)通过写“mem, disk, standby, freeze” 到 /sys/power/autosleep 中可以开启autosleep功能。
2)通过写“off” 到 /sys/power/autosleep 中可以关闭autosleep功能。

1. 主要接口实现

1.1 pm_autosleep_init()接口

该接口在PM Core初始化过程中被调用,用于初始化autosleep,主要实现了:
1)注册autosleep wakeup_source autosleep_ws,用于投票系统是否进入休眠
2)创建autosleep休眠工作队列autosleep_wq

@kernel\power\autosleep.c
static struct wakeup_source *autosleep_ws;
static struct workqueue_struct *autosleep_wq;
int __init pm_autosleep_init(void)
{
	autosleep_ws = wakeup_source_register(NULL, "autosleep"); //注册ws

	autosleep_wq = alloc_ordered_workqueue("autosleep", 0); //创建工作队列
	if (autosleep_wq)
		return 0;
}

1.2 queue_up_suspend_work()接口

该函数的功能主要是启动autosleep_wq。函数被调用后,会触发工作队列运行,最终调用try_to_suspend()

#define PM_SUSPEND_ON		((__force suspend_state_t) 0)
#define PM_SUSPEND_TO_IDLE	((__force suspend_state_t) 1)
#define PM_SUSPEND_STANDBY	((__force suspend_state_t) 2)
#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)

static DECLARE_WORK(suspend_work, try_to_suspend);

void queue_up_suspend_work(void)
{
	if (autosleep_state > PM_SUSPEND_ON)
		queue_work(autosleep_wq, &suspend_work);
}

1.3 pm_autosleep_set_state()接口

该函数是供文件节点autosleep使用的,在init.rc中向此节点写入suspend状态,触发autosleep运行。

int pm_autosleep_set_state(suspend_state_t state)
{

#ifndef CONFIG_HIBERNATION
	if (state >= PM_SUSPEND_MAX)
		return -EINVAL;
#endif

	__pm_stay_awake(autosleep_ws);

	mutex_lock(&autosleep_lock);

	autosleep_state = state;  //更新autosleep状态

	__pm_relax(autosleep_ws);

	if (state > PM_SUSPEND_ON) { //state大于PM_SUSPEND_ON,表示开启低功耗相关特性
		pm_wakep_autosleep_enabled(true); //更新所有的ws的autosleep的标记为使能,便于维护记录
		queue_up_suspend_work(); //进入休眠流程
	} else {
		pm_wakep_autosleep_enabled(false);
	}

	mutex_unlock(&autosleep_lock);
	return 0;
}

void pm_wakep_autosleep_enabled(bool set)
{
	struct wakeup_source *ws;
	ktime_t now = ktime_get();
	int srcuidx;

	srcuidx = srcu_read_lock(&wakeup_srcu);
	list_for_each_entry_rcu_locked(ws, &wakeup_sources, entry) {
		spin_lock_irq(&ws->lock);
		if (ws->autosleep_enabled != set) { //更新所有的ws的autosleep的标记为使能/失能
			ws->autosleep_enabled = set;
			if (ws->active) {
				if (set)
					ws->start_prevent_time = now;
				else
					update_prevent_sleep_time(ws, now);
			}
		}
		spin_unlock_irq(&ws->lock);
	}
	srcu_read_unlock(&wakeup_srcu, srcuidx);
}

1.4 try_to_suspend()模块私有接口

该函数主要根据当前系统中的持锁状态和autosleep_state的状态来判断是否进入PM CORE休眠流程。

static void try_to_suspend(struct work_struct *work)
{
	unsigned int initial_count, final_count;

	if (!pm_get_wakeup_count(&initial_count, true)) //阻塞等待直到唤醒事件数为0(也可能是其它因素导致阻塞退出)
		goto out;

	mutex_lock(&autosleep_lock);

	if (!pm_save_wakeup_count(initial_count) ||
		system_state != SYSTEM_RUNNING) {
		mutex_unlock(&autosleep_lock);
		goto out;
	}

	if (autosleep_state == PM_SUSPEND_ON) {
		mutex_unlock(&autosleep_lock);
		return;
	}
	if (autosleep_state >= PM_SUSPEND_MAX)
		hibernate(); //挂到磁盘中,嵌入式设备一般不使用。
	else
		pm_suspend(autosleep_state);  //进入PM Core的休眠主流程

	mutex_unlock(&autosleep_lock);

	if (!pm_get_wakeup_count(&final_count, false)) //退出休眠流程后再次获取唤醒事件数,此处不阻塞
		goto out;

	/*
	 * If the wakeup occured for an unknown reason, wait to prevent the
	 * system from trying to suspend and waking up in a tight loop.
	 */
	if (final_count == initial_count) //如果被未知原因(未持锁状态)唤醒,则在此处终止睡眠流程
		schedule_timeout_uninterruptible(HZ / 2);

 out:
	queue_up_suspend_work(); //再次尝试检测并进入休眠流程
}

2. 工作时序

Autosleep 工作步骤如下:

  1. 在init.rc中,向autosleep节点写入功耗控制的状态,通常写入mem状态(write /sys/power/autosleep mem);或在控制台中输入echo mem > /sys/power/autosleep来触发autosleep机制
  2. 写文件节点会触发调用pm_autosleep_set_state(),该函数进行参数的判断、系统状态的更新并调用queue_up_suspend_work()来触发autosleep的工作队列
  3. queue_up_suspend_work()被调用后触发工作队列suspend_work运行
  4. 工作队列suspend_work运行后进入函数try_to_suspend()执行,该函数会根据持锁条件决策是否进入PM Core休眠主流程
  5. try_to_suspend()通过调用pm_suspend()来进入PM Core流程
  6. pm_suspend()退出后回到try_to_suspend()try_to_suspend()会再次触发任务或者工作队列调度,期待进入下次的休眠流程
  7. try_to_suspend()通过调用queue_up_suspend_work()来再次调度autosleep的工作队列suspend_work
    image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1815920.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

反向代购系统建站技术详解

一、引言 随着全球化趋势的深入和电商行业的快速发展,反向代购(Reverse Daigou)作为一种新兴的商业模式逐渐受到关注。反向代购,即海外消费者通过国内电商平台购买国内商品并委托平台或第三方进行国际配送,满足了海外…

[Java基本语法] 从0到1带你精通Java基本语法

🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏:🍕 Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 🧀线程与…

类和对象(二)(C++)

初始化列表 class Date{public:Date(int year, int month, int day){_year year;_month month;_day day;}private:int _year;int _month;int _day;}; 虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化…

第十五篇——条件熵和信息增益:你提供的信息到底值多少钱?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么? 四、总结五、升华 一、背景介绍 通过这篇文章,我知道了条件熵和信息增益;如果你试…

创建应用程序

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 使用wxPython之前,先来了解两个基础对象:应用程序对象和顶级窗口。 应用程序对象管理主事件循环,主事件循环是wx…

JavaScript的运算符(算术、比较、赋值、逻辑、条件)

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…

直播预告|就在明天,解锁半导体测试全攻略

随着5G、物联网、人工智能和新能源汽车等新兴产业的快速发展,半导体测试设备与服务的市场需求将更加多样化。IC测试作为产品良率和成本管理的重要环节,行业测试工程师面临着降低测试成本和提高产品良率的强劲压力。如何提升测试的质量与效率,…

Spring Boot + Mybatis Plus实现登录注册

Spring Boot 实现登录注册 1. 注册 业务逻辑 客户端输入注册时需要的用户参数,比如:账户名、密码、确认密码、其他服务端接收到客户端的请求参数进行校验,然后判断是否有误,有误的地方就将错误信息抛出将密码进行加密之后存储到…

光伏项目管理——数字化改革

随着全球对可再生能源的迫切需求以及环保意识的日益增强,光伏产业作为清洁能源的重要组成部分,正迎来快速发展的黄金时期。然而,传统的光伏项目管理方式已逐渐无法满足现代化、高效化的需求,数字化改革成为了行业发展的必然趋势。…

什么是无头浏览器以及其工作原理?

如果您对这个概念还不熟悉,那么使用无头网络浏览器的想法可能会让您感到不知所措。无头浏览器本质上与您熟悉的网络浏览器相同,但有一个关键区别:它们没有图形用户界面 (GUI)。这意味着没有按钮、选项卡、地址栏或视觉显示。 相反&#xff0c…

Tuxera NTFS for Mac 2023软件:超级详细安装步骤(最新版软件下载)

软件简介: 在 Mac 上打开、编辑、复制、移动或删除存储在 Windows NTFS 格式 USB 驱动器上的文件。当您获得一台新 Mac 时,它只能读取 Windows NTFS 格式的 USB 驱动器。要将文件添加、保存或写入您的 Mac,您需要一个附加的 NTFS 驱动程序。…

checkbox表单校验 至少选中一个Checkbox , 否则会报错

项目背景 : react ant 需求 : 需实现至少选中一个Checkbox , 否则会报错 需求如下 : 注意 : Input, Select, DatePicker可以直接处理Form.Item的验证规则 , 但Checkbox不行 , 需自定义验证规则 实现 : // 自定义的checkbox校验规则--星期const validateAtLeastOneCheckbo…

CP AUTOSAR标准中文文档链接索引

AUTOSAR标准的核心组件包括通信、诊断、安全等,这些组件通过模块化结构进行组织。系统被划分为多个模块,每个模块负责特定的功能。模块之间通过接口进行通信,接口定义了模块之间的交互规则。AUTOSAR标准支持模块的配置,可以根据不…

加密经济时代:Web3如何改变我们的生活方式

随着区块链技术的蓬勃发展和加密经济的兴起,Web3正逐渐成为数字化时代的主流趋势之一。作为下一代互联网的代表,Web3以其去中心化、安全可信的特性,正在改变着我们的生活方式。本文将深入探讨加密经济时代下,Web3如何改变了我们的…

形如SyntaxError: EOL while scanning string literal,以红色波浪线形式在Pycharm下出现

背景: 新手在学习Python时可能会出现如下图所示的报错 下面分情况教大家如何解决 视频教程【推荐】: 形如SyntaxError: EOL while scanning string literal,以红色波浪线形式在Pycharm下出现 过程: 问题概述: 简单…

鸿蒙开发文件管理:【@ohos.securityLabel (数据标签)】

数据标签 该模块提供文件数据安全等级的相关功能:向应用程序提供查询、设置文件数据安全等级的JS接口。 说明: 本模块首批接口从API version 9开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。 导入模块 import security…

C# WinForm —— 34 ToolStrip 工具栏 介绍

1. 简介 工具栏 ToolStrip,一般紧贴在菜单栏下面 2. 属性 属性解释(Name)控件ID,在代码里引用的时候会用到Enabled控件是否启用Dock定义要绑定到容器的控件边框,默认是topAnchor定义某个控件绑定到的容器的边缘。当控件锚定到某个边缘时&a…

C++基础编程100题-009 OpenJudge-1.3-07 计算多项式的值

更多资源请关注纽扣编程微信公众号 http://noi.openjudge.cn/ch0103/07/ 描述 对于多项式 f ( x ) a x 3 b x 2 c x d f(x) ax^3 bx^2 cx d f(x)ax3bx2cxd 和给定的a, b, c, d, x,计算f(x)的值。 输入 输入仅一行,包含5个实数,分…

LeetCode | 66.加一

这道题有多个思路,可以依次取数组的每一位,乘10后加下一位,直到最后一位,就得到我们数组所表示的数字,然后加一,然后把新得到的数字再转化为对应的数组,我的做法是直接取数组的最后一位&#xf…

redis 07 订阅

订阅频道 订阅模式: 解释: