Linux时间子系统8:clock_event_device

1、前言

        上一篇我们谈到了timer,在详细分析hrtimer的实现之前,我们先追根溯源来谈一下clockevent。先抛开clockevent这个概念,如果硬件要支持定时功能,那么硬件必然要能够支持产生定时时间,通过异步中断的方式通知CPU,你当然不可能让CPU一直去轮询时钟,看时间是不是快到了对吧,linux对能够产生异步事件的clock进行了软件抽象clock event。那么实际上clock event和clock source是硬件时钟的一体两面,clock source提供了读取cycle,计算时间相关的功能,而clock event则提供了产生时间事件相关的功能。

2、clock_event_device数据结构

        我们看一下Linux内核是如何用clock_event_device来抽象产生系统时间事件(中断)的设备的,如下:

struct clock_event_device {void			(*event_handler)(struct clock_event_device *);int			(*set_next_event)(unsigned long evt, struct clock_event_device *);int			(*set_next_ktime)(ktime_t expires, struct clock_event_device *);ktime_t			next_event;u64			max_delta_ns;u64			min_delta_ns;u32			mult;u32			shift;enum clock_event_state	state_use_accessors;unsigned int		features;unsigned long		retries;int			(*set_state_periodic)(struct clock_event_device *);int			(*set_state_oneshot)(struct clock_event_device *);int			(*set_state_oneshot_stopped)(struct clock_event_device *);int			(*set_state_shutdown)(struct clock_event_device *);int			(*tick_resume)(struct clock_event_device *);void			(*broadcast)(const struct cpumask *mask);void			(*suspend)(struct clock_event_device *);void			(*resume)(struct clock_event_device *);unsigned long		min_delta_ticks;unsigned long		max_delta_ticks;const char		*name;int			rating;int			irq;int			bound_on;const struct cpumask	*cpumask;struct list_head	list;struct module		*owner;
} ____cacheline_aligned;

clock_event_device肯定要基于中断,我们先看中断相关的成员

irq:使用的中断号

features:中断模式,硬件支持的中断能力,包括:

# define CLOCK_EVT_FEAT_PERIODIC	0x000001
# define CLOCK_EVT_FEAT_ONESHOT		0x000002
# define CLOCK_EVT_FEAT_KTIME		0x000004
# define CLOCK_EVT_FEAT_C3STOP		0x000008
# define CLOCK_EVT_FEAT_DUMMY		0x000010
# define CLOCK_EVT_FEAT_DYNIRQ		0x000020
# define CLOCK_EVT_FEAT_PERCPU		0x000040
# define CLOCK_EVT_FEAT_HRTIMER		0x000080

CLOCK_EVT_FEAT_PERIODIC:能够产生周期性event,比如每隔1s产生1个event

CLOCK_EVT_FEAT_ONESHOT        :具备产生oneshot类型的event能力,即单次event

CLOCK_EVT_FEAT_KTIME        :可以直接使用ktime产生event,即到达某个ktime产生event,有些硬件时钟确实有这样的能力,就比如在clocksource中说的,read函数返回的是time,而不是counter

CLOCK_EVT_FEAT_C3STOP :CPU的sleep state叫做C-states,有C1/C2等,即CPU进入某个深度睡眠状态的时候,停止了local timer的运作

CLOCK_EVT_FEAT_PERCPU        :是不是percpu的clock event

CLOCK_EVT_FEAT_DYNIRQ:表示该定时事件设备可以设定CPU亲缘性,也就是可以指定到期后触发某个特定CPU的中断

CLOCK_EVT_FEAT_HRTIMER:表示该定时事件设备实际上是有高分辨率定时器模拟出来的

与feature强相关的还有state_use_accessors,clock event支持上述feature,但是具体工作在哪一个状态,用state_use_accessors描述,

enum clock_event_state {

    CLOCK_EVT_STATE_DETACHED,

    CLOCK_EVT_STATE_SHUTDOWN,

    CLOCK_EVT_STATE_PERIODIC,

    CLOCK_EVT_STATE_ONESHOT,

    CLOCK_EVT_STATE_ONESHOT_STOPPED,

};

都比较好理解,就不解释了。同时,也可以看到工作状态,通过set_state_xxx这样的接口实现。

event_handler:这里的event_handler并不是中断处理函数,而是在中断处理函数中调用的callback

相应的就有next_event,set_next_event,set_next_ktime相关成员,和设置下一次触发时间相关

除了这些与中断相关的成员,还有

cpumask:指定了这个定时事件设备所服务的CPU号,系统中高精度定时事件设备一般都是每个CPU核私有的。

list:系统中所有的定时事件设备实例都会保存在全局链表clockevent_devices中

mult、shift,rating与clock source相同,其他略过。

3、clock_event_device的注册

注册函数:clockevents_config_and_register

在使用clockevents_config_and_register注册设备之前,先要 准备好clock_event_device结构体数据。

void clockevents_config_and_register(struct clock_event_device *dev,u32 freq, unsigned long min_delta,unsigned long max_delta)
{dev->min_delta_ticks = min_delta;dev->max_delta_ticks = max_delta;clockevents_config(dev, freq);clockevents_register_device(dev);
}

实际调用了clockevents_config和clockevents_register_device,完成设备配置和注册

clockevents_config主要用来设置对应的mult和shift,clockevents_register_device如下:

void clockevents_register_device(struct clock_event_device *dev)
{unsigned long flags;/* Initialize state to DETACHED */clockevent_set_state(dev, CLOCK_EVT_STATE_DETACHED);if (!dev->cpumask) {WARN_ON(num_possible_cpus() > 1);dev->cpumask = cpumask_of(smp_processor_id());}if (dev->cpumask == cpu_all_mask) {WARN(1, "%s cpumask == cpu_all_mask, using cpu_possible_mask instead\n",dev->name);dev->cpumask = cpu_possible_mask;}raw_spin_lock_irqsave(&clockevents_lock, flags);list_add(&dev->list, &clockevent_devices);tick_check_new_device(dev);clockevents_notify_released();raw_spin_unlock_irqrestore(&clockevents_lock, flags);
}

首先修改了注册设备的状态为:CLOCK_EVT_STATE_DETACHED 

再次检查了设备绑定的cpumask,随后list_add将设备加入全局设备链表clockevent_devices,与时钟源注册类似clocksource_list

tick_check_new_device用来检查当前的定时设备是否可以成为新的tick设备,回想一下,之前clocksource注册的时候是不是也有类似的操作,判断新注册的时钟源是否可以替代现有时钟源,这里的逻辑也是类似的。如果新设备更适合作为tick设备(想一想,系统时间是和clocksource绑定的,而系统tick是和clock_event_device绑定的),那么就会调用clockevents_exchange_device。

clockevents_exchange_device的实现看下一节

4、更换系统clock_event_device

当有新的定时事件设备加入内核后,有可能会切换当前tick设备使用的定时事件设备,

这是在函数clockevents_exchange_device中实现的

void clockevents_exchange_device(struct clock_event_device *old,struct clock_event_device *new)
{/** Caller releases a clock event device. We queue it into the* released list and do a notify add later.*/if (old) {module_put(old->owner);clockevents_switch_state(old, CLOCK_EVT_STATE_DETACHED);list_del(&old->list);list_add(&old->list, &clockevents_released);}if (new) {BUG_ON(!clockevent_state_detached(new));clockevents_shutdown(new);}
}

clockevents_switch_state将设备状态切换为CLOCK_EVT_STATE_DETACHED

list_del将事件设备从clockevent_devices全局链表删除,加入clockevents_released链表

这个函数是在本地中断关闭并且获得自旋锁的情况下调用的。功能其实很简单,主要就是把被替换的老设备从原有的clockevent_devices全局链表中删除,并加入clockevents_released全局链表中,于此同时,把新替换的设备加入clockevent_devices全局链表中,当然还要更新设备的状态。新加入的设备的初始状态必须是CLOCK_EVT_STATE_DETACHED。

5、配置clock event device触发参数

int clockevents_program_event(struct clock_event_device *dev, ktime_t expires,bool force)
{unsigned long long clc;int64_t delta;int rc;if (WARN_ON_ONCE(expires < 0))return -ETIME;dev->next_event = expires;if (clockevent_state_shutdown(dev))return 0;/* We must be in ONESHOT state here */WARN_ONCE(!clockevent_state_oneshot(dev), "Current state: %d\n",clockevent_get_state(dev));/* Shortcut for clockevent devices that can deal with ktime. */if (dev->features & CLOCK_EVT_FEAT_KTIME)return dev->set_next_ktime(expires, dev);delta = ktime_to_ns(ktime_sub(expires, ktime_get()));if (delta <= 0)return force ? clockevents_program_min_delta(dev) : -ETIME;delta = min(delta, (int64_t) dev->max_delta_ns);delta = max(delta, (int64_t) dev->min_delta_ns);clc = ((unsigned long long) delta * dev->mult) >> dev->shift;rc = dev->set_next_event((unsigned long) clc, dev);return (rc && force) ? clockevents_program_min_delta(dev) : rc;
}

dev指向具体的clock event device,expires参数是设定下一次产生event的时间点,force参数控制在expires设定异常的时候(例如设定在一个过去的时间点上产生event)该函数 的行为,一种是出错返回,另外一种还是进行event的产生,只是设定一个最小的delta。

(1)如果chip driver支持使用ktime的设定(这需要硬件支持,设定了CLOCK_EVT_FEAT_KTIME flag的那些clock event device才支持哦),事情会比较简单,直接调用set_next_ktime就搞定了。

(2)对于一个“正常”的clock event device,需要转换成cycle这样的单位。不过在转换成cycle之前,需要先将ktime格式的时间(传入的expires参数就是这样的格式)转换成纳秒这样的时间单位。

(3)delta小于0意味着用户设定的时间点已经是过去的一个时间点,如果强制产生event的话,那么事不宜迟,要立刻产生event,这需要调用clockevents_program_min_delta函数,代码如下:

6、总结

了解了上面的内容就可以知道内核中timer相关的底层机制了,关于tick和timer的内容,见后面的文章,本篇主要内容参考Linux时间子系统之(十六):clockevent

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

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

相关文章

计算机科学中的接口(Interface)介绍

计算机科学中的接口&#xff08;Interface&#xff09;介绍 计算机科学中&#xff0c;接口是一个广泛的概念&#xff0c;在不同上下文中有不同含义&#xff1a; 1.任何两电路或设备间的连接电路&#xff0c;用于连接CPU与内存、CPU与外设之间。这是一个重要的硬件层面的接口概…

你必须要知道的自闭症知识,推荐收藏

自闭症&#xff0c;一种日益受到关注的神经发育障碍&#xff0c;对于许多人来说&#xff0c;仍充满了神秘和误解。以下是 12 个你必须知道的关于自闭症的重要知识点&#xff1a; 1、自闭症并非心理问题 自闭症是一种生理上的神经发育障碍&#xff0c;不是由于孩…

Linux: security: openssh: ssh 登陆变慢又一例;strace的使用

文章目录 问题分析解决问题 今天遇到一个问题,ssh登陆服务器比平时慢了20秒。 分析 这种问题的分析,首先要靠strace,trace sshd的服务进程,看看有没有卡在某个系统调用上。 确实抓到了慢的原因;这里sshd向169.254.195.0:1812 发送了一个消息,然后接下来使用select,等…

亚马逊TM商标跟卖,同行截流采集,人工手动跟卖选品更方便!

区分TM标&#xff0c;软件自动查询&#xff0c;人工手动查询方便。 大家好&#xff0c;跟大家说下如何区分TM标。 选择相对于的站点&#xff0c;选择TM。 软件采集出来的已备案、未备案TMR标&#xff0c;现在点击TM标就会跳到美国商标局。 可以清晰的看到这个地方只有一个序…

张颂文百花提名,男配界笑出“颂”彩

在这个星光熠熠的百花奖舞台上&#xff0c; 张颂文老师犹如一坛陈年老酒&#xff0c;越品越有味&#xff0c; 竟不声不响地提名了最佳男配角&#xff01;这下可好&#xff0c; 男配界仿佛一夜之间被“颂”风吹得花枝乱颤&#xff0c;笑料百出。你说张颂文老师这演技&#xf…

DreamTech联合南大和牛津发布最强3D内容生成大模型——Direct3D

文章链接&#xff1a;https://arxiv.org/pdf/2405.14832 github链接&#xff1a;https://nju-3dv.github.io/projects/Direct3D/ 从文本和图像生成高质量的3D资产一直是一项挑战&#xff0c;主要是由于缺乏能够捕捉复杂几何分布的可扩展3D表示。在这项工作中&#xff0c;介绍…

详解反向传播(BP)算法

文章目录 what&#xff08;是什么&#xff09;where&#xff08;用在哪&#xff09;How&#xff08;原理&&怎么用&#xff09;原理以及推导过程pytorch中的反向传播 what&#xff08;是什么&#xff09; 反向传播算法&#xff08;Backpropagation&#xff09;是一种用于…

自动驾驶水泥搅拌车在梁场的应用(下)

自动驾驶水泥搅拌车在梁场的应用&#xff08;下&#xff09; 北京渡众机器人科技有限公司的自动驾驶水泥搅拌车在梁场&#xff08;也称为预制梁场&#xff09;的应用可以带来多方面的优势和效益&#xff1a; 1. 自动化搅拌和运输 在梁场中&#xff0c;通常需要大量的混凝土搅…

自动化一些操作

下拉选择框 from selenium import webdriver from time import sleep # 导包 from selenium.webdriver.support.select import Select driver webdriver.Edge() driver.get(r"D:\WORK\ww\web自动化_day01_课件笔记资料代码\web自动化_day01_课件笔记资料代码\02_其他资料…

调试支付分回调下载平台证书

之前的原生代码放到webman里面&#xff0c;死活跑不通 没办法&#xff0c;只能用esayWeChat6.7 &#xff08;自行下载&#xff09; 它里面配置要用到平台证书 平台证书又要用到 composer require wechatpay/wechatpay 但是请求接口之前&#xff0c;你先要用到一个临时的平台…

配置atuin记录

https://atuin.sh/ 运行 curl --proto https --tlsv1.2 -LsSf https://setup.atuin.sh | sh报错 $ curl --proto https --tlsv1.2 -LsSf https://setup.atuin.sh | sh curl: (77) error setting certificate verify locations:CAfile: /etc/ssl/certs/ca-certificates.crtCAp…

同时安装JDK8和JDK17+环境变量默认无法修改

一、问题描述 当在windows系统中&#xff0c;同时安装JDK8和JDK17&#xff0c;环境变量默认就为jdk17&#xff0c;且从jdk17切换为jdk8后不生效&#xff0c;使用"java -version"命令查看后还是17版本。 解决方法 首先&#xff0c;产生的原因是&#xff0c;在安装…

2024最新源代码加密软件丨五款企业级软件评测

程序源代码作为企业的核心成果&#xff0c;一旦泄密将产生重大的损失&#xff0c;加密源代码至关重要。 可以防止他人未经授权使用、复制或修改源代码&#xff0c;保护开发者的劳动成果。 可以防止源代码被黑客或竞争对手获取和分析&#xff0c;减少漏洞被发现和利用的风险。…

通过MATLAB控制TI毫米波雷达的工作状态之实时数据采集

前言 前一章博主介绍了如何基于MATLAB的各种前面板组件结合MATLAB代码来发送CFG指令控制毫米波雷达的工作状态,这一章节博主将介绍如何基于这些组件结合MATLAB代码来实现TI毫米波雷达数据的实时采集。目前大部分TI毫米波雷达的数据采集均是仅可以采集一段数据又或者利用DAC10…

JAVA极简图书管理系统,初识springboot后端项目

前提条件&#xff1a; 具备基础的springboot 知识 Java基础 废话不多说&#xff01; 创建项目 配置所需环境 将application.properties>application.yml 配置以下环境 数据库连接MySQL 自己创建的数据库名称为book_test server:port: 8080 spring:datasource:url:…

ShareSDK HarmonyOS NEXT集成指南

集成前准备 注册账号 使用MobSDK之前&#xff0c;需要先在MobTech官网注册开发者账号&#xff0c;并获取MobTech提供的AppKey和AppSecret&#xff0c;详情可以点击查看注册流程 ShareSDK流程图 集成配置 添加依赖 在Terminal窗口中&#xff0c;执行如下命令进行安装 ohpm …

【Python】MacBook M系列芯片Anaconda下载Pytorch,并开发一个简单的数字识别代码(附带踩坑记录)

文章目录 配置镜像源下载Pytorch验证使用Pytorch进行数字识别 配置镜像源 Anaconda下载完毕之后&#xff0c;有两种方式下载pytorch&#xff0c;一种是用页面可视化的方式去下载&#xff0c;另一种方式就是直接用命令行工具去下载。 但是由于默认的Anaconda走的是外网&#x…

杂学可以查看各个网络学习

WZMIAOMIAO (WuZhe) GitHub这个是一个各个深度学习的合集&#xff0c;有代码

主干网络篇 | YOLOv8改进之引入YOLOv10的主干网络 | 全网最新改进

前言:Hello大家好,我是小哥谈。YOLOv10是由清华大学研究人员利用Ultralytics Python软件包开发的,它通过改进模型架构并消除非极大值抑制(NMS)提供了一种新颖的实时目标检测方法。这些优化使得模型在保持先进性能的同时,降低了计算需求。与以往的YOLO版本不同,YOLOv10的…

突发!Runway的Gen-3向所有人开放,媲美Sora!

7月2日凌晨&#xff0c;著名生成式AI平台Runway在官网宣布&#xff0c;其文生视频模型Gen-3 Alpha向所有用户开放使用。 上周日Runway只向部分用户提供了Gen-3的使用权限&#xff0c;「AIGC开放社区」也为大家解读了10个非常有代表性的视频案例。&#xff08;点击查看&#xf…