Linux内部的时钟处理机制全面剖析(1)(2)
◆2、硬件时钟处理
这里所说的硬件时钟处理特指的是硬件计时器时钟中断的处理过程。
2.1 数据结构
和硬件计时器本文又称作硬件时钟,区别于软件时钟)相关的数据结构主要有两个:
- struct clocksource :对硬件设备的抽象,描述时钟源信息
- struct clock_event_device :时钟的事件信息,包括当硬件时钟中断发生时要执行那些操作实际上保存了相应函数的指针)。本文将该结构称作为“时钟事件设备”。
上述两个结构内核源代码中有较详细的注解,分别位于文件 clocksource.h 和 clockchips.h 中。需要特别注意的是结构 clock_event_device 的成员 event_handler ,它指定了当硬件时钟中断发生时,内核应该执行那些操作,也就是真正的时钟中断处理函数。 在2.3节“时钟初始化”部分会介绍它真正指向哪个函数。
Linux 内核维护了两个链表,分别存储了系统中所有时钟源的信息和时钟事件设备的信息。这两个链表的表头在内核中分别是 clocksource_list 和 clockevent_devices 。图2-1显示了这两个链表。
图2-1 时钟源链表和时钟事件链表
2.2 通知链技术 notification chain )
在时钟处理这部分中,内核用到了所谓的“通知链 notification chain )”技术。所以在介绍时钟处理过程之前先来了解下“通知链”技术。
在 Linux 内核中,各个子系统之间有很强的相互关系,一些被一个子系统生成或者被探测到的事件,很可能是另一个或者多个子系统感兴趣的,也就是说这个事件的获取者必须能够通知所有对该事件感兴趣的子系统,并且还需要这种通知机制具有一定的通用性。基于这些, Linux 内核引入了“通知链”技术。
2.2.1 数据结构:
通知链有四种类型,
- 原子通知链 Atomic notifier chains ):通知链元素的回调函数当事件发生时要执行的函数)只能在中断上下文中运行,不允许阻塞
- 可阻塞通知链 Blocking notifier chains ):通知链元素的回调函数在进程上下文中运行,允许阻塞
- 原始通知链 Raw notifier chains ):对通知链元素的回调函数没有任何限制,所有锁和保护机制都由调用者维护
- SRCU 通知链 SRCU notifier chains ):可阻塞通知链的一种变体
所以对应了四种通知链头结构:
- struct atomic_notifier_head :原子通知链的链头
- struct blocking_notifier_head :可阻塞通知链的链头
- struct raw_notifier_head :原始通知链的链头
- struct srcu_notifier_head : SRCU 通知链的链头
通知链元素的类型:
- struct notifier_block :通知链中的元素,记录了当发出通知时,应该执行的操作即回调函数)
链头中保存着指向元素链表的指针。通知链元素结构则保存着回调函数的类型以及优先级,参见 notifier.h 文件。
2.2.2 运作机制
通知链的运作机制包括两个角色:
- 被通知者:对某一事件感兴趣一方。定义了当事件发生时,相应的处理函数,即回调函数。但需要事先将其注册到通知链中被通知者注册的动作就是在通知链中增加一项)。
- 通知者:事件的通知者。当检测到某事件,或者本身产生事件时,通知所有对该事件感兴趣的一方事件发生。他定义了一个通知链,其中保存了每一个被通知者对事件的处理函数回调函数)。通知这个过程实际上就是遍历通知链中的每一项,然后调用相应的事件处理函数。
包括以下过程:
- 通知者定义通知链
- 被通知者向通知链中注册回调函数
- 当事件发生时,通知者发出通知执行通知链中所有元素的回调函数)
被通知者调用 notifier_chain_register 函数注册回调函数,该函数按照优先级将回调函数加入到通知链中 。注销回调函数则使用 notifier_chain_unregister 函数,即将回调函数从通知链中删除。2.2.1节讲述的4种通知链各有相应的注册和注销函数,但是他们最终都是调用上述两个函数完成注册和注销功能的。有兴趣的读者可以自行查阅内核代码。
通知者调用 notifier_call_chain 函数通知事件的到达,这个函数会遍历通知链中所有的元素,然后依次调用每一个的回调函数即完成通知动作)。2.2.1节讲述的4种通知链也都有其对应的通知函数,这些函数也都是最终调用 notifier_call_chain 函数完成事件的通知。
由以上的叙述,“通知链”技术可以概括为:事件的被通知者将事件发生时应该执行的操作通过函数指针方式保存在链表通知链)中,然后当事件发生时通知者依次执行链表中每一个元素的回调函数完成通知。
评论暂时关闭