init_timers();

2024-02-18 14:08
文章标签 init timers

本文主要是介绍init_timers();,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

void __init init_timers(void)
{
//初始化本 CPU 上的软件时钟相关的数据结构int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,(void *)(long)smp_processor_id()); //因为是初始化阶段,所以得到的CPU为启动CPUinit_timer_stats();BUG_ON(err != NOTIFY_OK);
//向 cpu_chain 通知链注册元素 timers_nb ,该元素的回调函数用于初始化指定 CPU 上的软件时钟相关的数据结构register_cpu_notifier(&timers_nb);
//初始化时钟的软中断处理函数open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
}

这个函数完成的主要作用包括:

(1)初始化本 CPU 上的软件时钟相关的数据结构;

(2)向 cpu_chain 通知链注册元素 timers_nb ,该元素的回调函数用于初始化指定 CPU 上的软件时钟相关的数据结构;

(3)初始化时钟的软中断处理函数。

对于操作(1):

static int __cpuinit timer_cpu_notify(struct notifier_block *self,unsigned long action, void *hcpu)
{long cpu = (long)hcpu;int err;switch(action) {case CPU_UP_PREPARE:case CPU_UP_PREPARE_FROZEN:err = init_timers_cpu(cpu);  //调用该函数,参数CPU即为启动CPU(或者主CPU)if (err < 0)return notifier_from_errno(err);break;
#ifdef CONFIG_HOTPLUG_CPUcase CPU_DEAD:case CPU_DEAD_FROZEN:migrate_timers(cpu);break;
#endifdefault:break;}return NOTIFY_OK;
}

调用init_timers_cpu:


static int __cpuinit init_timers_cpu(int cpu)
{int j;struct tvec_base *base;static char __cpuinitdata tvec_base_done[NR_CPUS];if (!tvec_base_done[cpu]) {                                        //启动CPU尚未进行tvec的设置static char boot_done;if (boot_done) {/** The APs use this path later in boot*/base = kmalloc_node(sizeof(*base),GFP_KERNEL | __GFP_ZERO,cpu_to_node(cpu));if (!base)return -ENOMEM;/* Make sure that tvec_base is 2 byte aligned */if (tbase_get_deferrable(base)) {WARN_ON(1);kfree(base);return -ENOMEM;}per_cpu(tvec_bases, cpu) = base;} else {                                                         //第一次进行设置/** This is for the boot CPU - we use compile-time* static initialisation because per-cpu memory isn't* ready yet and because the memory allocators are not* initialised either.*/boot_done = 1;base = &boot_tvec_bases;}tvec_base_done[cpu] = 1;} else {base = per_cpu(tvec_bases, cpu);}spin_lock_init(&base->lock);//开始初始化5个定时器表for (j = 0; j < TVN_SIZE; j++) {INIT_LIST_HEAD(base->tv5.vec + j);INIT_LIST_HEAD(base->tv4.vec + j);INIT_LIST_HEAD(base->tv3.vec + j);INIT_LIST_HEAD(base->tv2.vec + j);}for (j = 0; j < TVR_SIZE; j++)INIT_LIST_HEAD(base->tv1.vec + j);//默认值为初始化时的jiffesbase->timer_jiffies = jiffies; //当前正在处理的软件时钟到期时间 base->next_timer = base->timer_jiffies;return 0;
}

对于操作(3),open_softirq(TIMER_SOFTIRQ, run_timer_softirq):

void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
}

我们看到,定时器软中断所对应的action是run_timer_softirq,也就是当时钟中断到来,软中断启动时,就会调用这个函数,我们来看一下这个函数:

 
/** This function runs timers and the timer-tq in bottom half context.*/
static void run_timer_softirq(struct softirq_action *h)
{struct tvec_base *base = __this_cpu_read(tvec_bases);hrtimer_run_pending();//判断当前的jiffies是否大于等于最小的那个超时jiffies.是的话就进入定时器处理if (time_after_eq(jiffies, base->timer_jiffies))__run_timers(base);
}/** * __run_timers - run all expired timers (if any) on this CPU. * @base: the timer vector to be processed. * * This function cascades all vectors and executes all expired timer * vectors. */  static inline void __run_timers(struct tvec_base *base)  {  struct timer_list *timer;  spin_lock_irq(&base->lock);  while (time_after_eq(jiffies, base->timer_jiffies)) {  //处理所有从时间点timer_jiffies 到 时间点jiffies的事件。  struct list_head work_list;  struct list_head *head = &work_list;  int index = base->timer_jiffies & TVR_MASK; //计算第一组的索引位置  /* * Cascade timers: */  if (!index &&  (!cascade(base, &base->tv2, INDEX(0))) &&               //cascade用于从指定组取得定时器补充前一组。  (!cascade(base, &base->tv3, INDEX(1))) &&  !cascade(base, &base->tv4, INDEX(2)))  cascade(base, &base->tv5, INDEX(3));                    //如果前组都已经是空的了,那么就将第五组的向前移动(因为第五组的时间到期时间实在是太晚,因此一般都不会东它们。)      ++base->timer_jiffies;                 //timer_jiffiers记录的是一个时间点,这个时间点之前到期的定时器都已经处理过了。  list_replace_init(base->tv1.vec + index, &work_list); //第一组位于索引位置的所有定时器都转移到一个临时链表中,从原来的数据结构中删除。  while (!list_empty(head)) {                           //分别执行各个定时器的处理程序  void (*fn)(unsigned long);  unsigned long data;  timer = list_first_entry(head, struct timer_list,entry);  fn = timer->function;  data = timer->data;  timer_stats_account_timer(timer);  base->running_timer = timer;  detach_timer(timer, 1);  spin_unlock_irq(&base->lock);  call_timer_fn(timer, fn, data);  spin_lock_irq(&base->lock);  }  }  base->running_timer = NULL;  spin_unlock_irq(&base->lock);  }  




这篇关于init_timers();的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/721393

相关文章

4.15 版本内核调用 init_timer()函数出错

linux/include/linux/timer.h4.15 之前版本struct timer_list {14 /*15 * All fields that change during normal runtime grouped to the16 * same cacheline17 */18 struct hl

Python方法:__init__,__new__,__class__的使用详解

转自:https://blog.csdn.net/qq_26442553/article/details/82464682 因为python中所有类默认继承object类。而object类提供了了很多原始的内建属性和方法,所以用户自定义的类在Python中也会继承这些内建属性。可以使用dir()函数可以查看,虽然python提供了很多内建属性但实际开发中常用的不多。而很多系统提供的内建属性实际

_no_init的作用

__no_init用于禁止系统启动时的变量初始化,什么情况下需要用这个关键字使系统禁止变量的初始化,禁止变量初始化用在什么场合,为什么要这样做,有什么意义吗? 1、看门狗复位的现场恢复,如果初始化了就完全不可恢复了 2、使用nvram保存数据,需要连续记录的。    我有个变量,需要在系统意外复位时,这个变量值能保留,所以采用__no_init来实现,只是上电的时候这个值不是零

iOS中alloc与init

面向对象的3大特性,封装继承和多态. 我遇到过封装相关的问题,因为初级封装简单,常常暴露出被你封装的接口,进一步进行高级封装隐藏接口的时候才发现,封装是一门学问,而这门学问得从最基础的alloc与init讲起.   FatherModel.h #import <Foundation/Foundation.h>@interface FatherModel : NSObject@en

优雅的写init方法

怎么写出高质量的init方法,以下是demo可参考实现,代码实现。 public class BaseTestController {private UnitTest unitTest;public void init(String url, String accessToken){unitTest = UnitTest.getNewInstance();unitTest.setHost(ur

Android14音频进阶之定制ramdisk文件系统init服务(八十三)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧

cocos2dx场景切换中init、onEnter、onEnterTransitionDidFinish的调用顺序

这些方法调用的先后顺序如下(使用 replaceScene 方法): 1. 第2个场景的 scene 方法 2. 第2个场景的 init 方法 3. 第2个场景的 onEnter 方法 4. 转场 5. 第1个场景的 onExit 方法 6. 第2个场景的 onEnterTransitionDidFinish 方法 7. 第1个场景的 dealloc 方

深入理解jvm--Java中init和clinit区别完全解析

init和clinit区别 ①init和clinit方法执行时机不同 init是对象构造器方法,也就是说在程序执行 new 一个对象调用该对象类的 constructor 方法时才会执行init方法,而clinit是类构造器方法,也就是在jvm进行类加载—–验证—-解析—–初始化,中的初始化阶段jvm会调用clinit方法。 ②init和clinit方法执行目的不同 init is t

根文件系统init进程分析

U-boot:启动内核 内核 :启动应用程序 内核启动的第一个应用程序是/sbin/init,启动的最终目的是启动其他的应用程序。 init程序 (1)读取配置文件                (2)解析配置文件                (3)执行应用程序(根据配置文件) 配置文件:(1)指定应用程序(2)什么时候执行 busybody->init_main   (init进程本身就是bu

STM32CubeMX生成freertos默认设置卡死,卡在HAL_Init不动,裸机运行程序正常跑,解决方法

1、简介 最近通过STM32CubeMX生成freertos发现任务不执行,卡在HAL_Init不动,网上找很久不好使,刚开始怀疑硬件问题,但是裸机运行程序正常跑,然后怀疑软件有问题,但是对F1,F3系列都好使,仅仅对F4系列不行,然后通过对F4固件包升级得以解决。 2、解决办法 找到F4,点击Refresh刷新,然后安装。