时间子系统13_clockevent周期触发模式

//	设置clockevent周期处理函数
//	函数参数:
//		broadcast,指示此设备是否为全局广播设备
//	调用路径:tick_setup_periodic->tick_set_periodic_handler
1.1 void tick_set_periodic_handler(struct clock_event_device *dev, int broadcast)
{
	if (!broadcast)
		dev->event_handler = tick_handle_periodic;
	else
		dev->event_handler = tick_handle_periodic_broadcast;
}

//	clockevent周期处理函数(非广播设备)
//	函数任务:
//		1.执行周期任务
//		2.如果设备为单触发模式
//			2.1 重编程下一次事件到期时间
2.1 void tick_handle_periodic(struct clock_event_device *dev)
{
	int cpu = smp_processor_id();
	ktime_t next;
	//执行do_timer更新全局事件,更新进程时间
	tick_periodic(cpu);
	//周期模式不需要手动设置下次到期时间,直接退出
	if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
		return;
	//计算下次到期时间
	next = ktime_add(dev->next_event, tick_period);
	for (;;) {
		//重编程设备事件到期
		if (!clockevents_program_event(dev, next, ktime_get()))
			return;
		//重新编程设备失败,说明已经经过一个tick周期,此时执行tick周期任务
		if (timekeeping_valid_for_hres())
			tick_periodic(cpu);
		//更新下次到期时间
		next = ktime_add(next, tick_period);
	}
}
//	周期处理函数
//	函数任务:
//		1.如果本cpu负责更新全局时间
//			1.1 执行do_timer
//		2.更新进程运行时间
//			2.1 通知调度器更新其虚拟时钟
//			2.2 更新进程cpu上执行时间
//	调用路径:tick_handle_periodic->tick_periodic
2.2 static void tick_periodic(int cpu)
{
	//本cpu负责更新全局时间
	if (tick_do_timer_cpu == cpu) {
		write_seqlock(&xtime_lock);
		//计算下个周期
		tick_next_period = ktime_add(tick_next_period, tick_period);
		//执行do_timer
		do_timer(1);
		write_sequnlock(&xtime_lock);
	}
	//更新进程时间
	update_process_times(user_mode(get_irq_regs()));
}
//	更新全局时间
//	函数任务:
//		1.更新jiffies
//		2.更新墙上时间
//		3.cpu间负载均衡
//	调用路径:tick_periodic->do_timer
2.3 void do_timer(unsigned long ticks)
{
	jiffies_64 += ticks;
	update_wall_time();
	calc_global_load();
}

//	clockevent周期处理函数(广播设备)
//	函数任务:
//		1.执行本cpu的事件处理函数
//		2.通过ipi通知代理的cpu,执行时间处理函数
//		3.重新编程下次事件的到期时间
3.1 static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
{
	ktime_t next;
	//执行事件处理函数
	tick_do_periodic_broadcast();
	//重编程下次事件的到期时间
	if (dev->mode == CLOCK_EVT_MODE_PERIODIC)
		return;
	for (next = dev->next_event; ;) {
		next = ktime_add(next, tick_period);

		if (!clockevents_program_event(dev, next, ktime_get()))
			return;
		tick_do_periodic_broadcast();
	}
}
//	执行事件处理函数
//	函数任务:
//		1.通过tick_broadcast_mask掩码获取代理的cpu
//		2.执行事件处理函数
//	调用路径:tick_handle_periodic_broadcast->tick_do_periodic_broadcast
3.2 static void tick_do_periodic_broadcast(void)
{
	raw_spin_lock(&tick_broadcast_lock);
	//通过tick_broadcast_mask掩码获取代理的cpu
	cpumask_and(to_cpumask(tmpmask),
		    cpu_online_mask, tick_get_broadcast_mask());
	//对代理的cpu执行事件处理函数
	tick_do_broadcast(to_cpumask(tmpmask));
	raw_spin_unlock(&tick_broadcast_lock);
}
//	执行事件处理函数
//	函数任务:
//		1.执行本cpu的事件处理函数
//		2.通过ipi通知代理的cpu,执行事件处理函数
//	调用路径:tick_handle_periodic_broadcast->...->tick_do_broadcast
3.3 static void tick_do_broadcast(struct cpumask *mask)
{
	int cpu = smp_processor_id();
	struct tick_device *td;
	//检查当前cpu是否在掩码
	if (cpumask_test_cpu(cpu, mask)) {
		//从掩码中清除本cpu
		cpumask_clear_cpu(cpu, mask);
		td = &per_cpu(tick_cpu_device, cpu);
		//执行事件处理函数
		td->evtdev->event_handler(td->evtdev);
	}
	//检查是否有其他cpu需要被代理
	if (!cpumask_empty(mask)) {
		//通过ipi通知其他cpu执行时钟事件处理函数
		td = &per_cpu(tick_cpu_device, cpumask_first(mask));
		td->evtdev->broadcast(mask);
	}
}
//	x86下lapic,clockevent->broadcast函数
//	函数任务:
//		通过ipi通知目标cpu执行事件处理函数
3.4 static void lapic_timer_broadcast(const struct cpumask *mask)
{
#ifdef CONFIG_SMP
	//所有需要通知的cpu均在mask掩码中
	apic->send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
#endif
}
时间: 2025-01-30 15:59:50

时间子系统13_clockevent周期触发模式的相关文章

Linux时间子系统之八:动态时钟框架(CONFIG_NO_HZ、tickless)【转】

转自:http://blog.csdn.net/droidphone/article/details/8112948 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] 数据结构 低分辨率下的动态时钟 1  切换至动态时钟模式 2  低分辨率动态时钟下的事件中断处理函数 3  动态时钟停止周期tick时钟事件 3  动态时钟重新开启周期tick时钟事件 高精度模式下的动态时钟 动态时钟对中断的影响   在前面章节的讨论中,我们一直基于一个假设:Linux中的时钟事件都是由

时间子系统2_tick device管理机制

// 1.每个cpu都具有一个tick_device,维护周期时钟. // 2.tick_device依赖一个clockevent设备,提供周期事件. // 3.cpu电源状态的改变会影响tick_device,通过tick_notifier监听电源状态. // 4.全局广播设备接管进入省电模式cpu的周期时间维护. // 4.broadcast_mask保存开启广播模式的cpu, broadcast_oneshot_mask保存进入省电模式的cpu. // 监听clockevent设备状态 /

时间子系统12_clockevent设备注册

// 向系统注册时钟事件设备 // 函数任务: // 1.添加设备到clockevent_devices链表 // 2.通知tick device管理机制有clockevent设备注册 1.1 void clockevents_register_device(struct clock_event_device *dev) { unsigned long flags; raw_spin_lock_irqsave(&clockevents_lock, flags); //将设备添加到clockeve

时间子系统10_hpet时钟初始化

// 时钟mult :mult/2^shift = ns/cyc // 参考:http://www.bluezd.info/archives/reg_clock_event_device_1 // x86平台初始化 // 注:arch/x86/kernel/x86_init.c 1.1 struct x86_init_ops x86_init __initdata = { ... //时钟初始化 .timers = { .setup_percpu_clockev = setup_boot_API

时间子系统5_低分辨率切换高分辨率

// 切换低分辨率动态时钟模式.或高分辨率模式 // 调用路径:run_timer_softirq->hrtimer_run_pending // 函数任务: // 1.如果高分辨率定时器框架已经激活,则直接返回 // 2.切换到高分辨率模式的条件: // 2.1 没有开启低分辨率动态时钟 // 2.2 有高分辨率的clocksource // 2.3 clockevent设备支持单触发模式 // 3.切换到低分辨率动态时钟的条件: // 3.1 启动时,没有激活高分辨率率定时框架 // 3.2

最近的时间间隔-Android闹钟 自定义重复周期 怎样计算当前时间与自定义周期的最近的那一天的时间间隔

问题描述 Android闹钟 自定义重复周期 怎样计算当前时间与自定义周期的最近的那一天的时间间隔 如果重复周期是 "只有一次" 或者 "每天",算法很好写,只要计算 当前时间 与 给定时间 的时间差就可以,如果 当前时间 < 给定时间,加上一天就ok! 现在问题是:假设 我 自定义了一个重复周期,设定 每周三,每周五7:30 AM的闹铃. 那么如果今天是在周三设定的时间之前,那么要计算与周三的时间差. 如果是周三设定的时间之后,周五设定的时间之前,那么要计算

如何监测倒计时,时间一结束马上触发事件。

问题描述 如题:如何监测倒计时,时间一结束马上触发事件.数据库表存着开始时间和结束时间,如何在结束时间一到,马上自动就进行一些操作.不用说等到页面访问了才触发. 解决方案 解决方案二:开一个线程,设置线程的休眠时间,到了就自动调用了,!解决方案三:引用1楼a475372067的回复: 开一个线程,设置线程的休眠时间,到了就自动调用了,! 可如果要监测很多条数据呢,比如几千或者一万以上的的.解决方案四:检测倒计时?我想起我做的秒杀活动了settimeout?具体是什么要求能说说嘛?解决方案五:懂你

Linux时间子系统之七:定时器的应用--msleep(),hrtimer_nanosleep()【转】

  转自:http://blog.csdn.net/droidphone/article/details/8104433 我们已经在前面几章介绍了低分辨率定时器和高精度定时器的实现原理,内核为了方便其它子系统,在时间子系统中提供了一些用于延时或调度的API,例如msleep,hrtimer_nanosleep等等,这些API基于低分辨率定时器或高精度定时器来实现,本章的内容就是讨论这些方便.好用的API是如何利用定时器系统来完成所需的功能的. /*************************

时间子系统4_低分辨率定时器处理

// 触发低分辨率定时器软中断 // 调用路径:update_process_times->run_local_timers // 注: // 1.update_process_times以HZ频率被调用,因此低分辨率定时器的分辨率为HZ // 2.当未激活高分辨率定时器框架时,高分辨率定时器在时钟中断被运行,因此高分辨率定时器的分辨率也HZ 1.1 void run_local_timers(void) { //如果高分辨率定时器框架未激活,则在周期时钟中断中运行高分辨率率定时器 hrtime