⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tick-sched.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	ktime_t now, delta;	if (!ts->tick_stopped)		return;	/* Update jiffies first */	now = ktime_get();	local_irq_disable();	select_nohz_load_balancer(0);	tick_do_update_jiffies64(now);	cpu_clear(cpu, nohz_cpu_mask);	/* Account the idle time */	delta = ktime_sub(now, ts->idle_entrytime);	ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);	/*	 * We stopped the tick in idle. Update process times would miss the	 * time we slept as update_process_times does only a 1 tick	 * accounting. Enforce that this is accounted to idle !	 */	ticks = jiffies - ts->idle_jiffies;	/*	 * We might be one off. Do not randomly account a huge number of ticks!	 */	if (ticks && ticks < LONG_MAX) {		add_preempt_count(HARDIRQ_OFFSET);		account_system_time(current, HARDIRQ_OFFSET,				    jiffies_to_cputime(ticks));		sub_preempt_count(HARDIRQ_OFFSET);	}	/*	 * Cancel the scheduled timer and restore the tick	 */	ts->tick_stopped  = 0;	hrtimer_cancel(&ts->sched_timer);	ts->sched_timer.expires = ts->idle_tick;	while (1) {		/* Forward the time to expire in the future */		hrtimer_forward(&ts->sched_timer, now, tick_period);		if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {			hrtimer_start(&ts->sched_timer,				      ts->sched_timer.expires,				      HRTIMER_MODE_ABS);			/* Check, if the timer was already in the past */			if (hrtimer_active(&ts->sched_timer))				break;		} else {			if (!tick_program_event(ts->sched_timer.expires, 0))				break;		}		/* Update jiffies and reread time */		tick_do_update_jiffies64(now);		now = ktime_get();	}	local_irq_enable();}static int tick_nohz_reprogram(struct tick_sched *ts, ktime_t now){	hrtimer_forward(&ts->sched_timer, now, tick_period);	return tick_program_event(ts->sched_timer.expires, 0);}/* * The nohz low res interrupt handler */static void tick_nohz_handler(struct clock_event_device *dev){	struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);	struct pt_regs *regs = get_irq_regs();	int cpu = smp_processor_id();	ktime_t now = ktime_get();	dev->next_event.tv64 = KTIME_MAX;	/*	 * Check if the do_timer duty was dropped. We don't care about	 * concurrency: This happens only when the cpu in charge went	 * into a long sleep. If two cpus happen to assign themself to	 * this duty, then the jiffies update is still serialized by	 * xtime_lock.	 */	if (unlikely(tick_do_timer_cpu == -1))		tick_do_timer_cpu = cpu;	/* Check, if the jiffies need an update */	if (tick_do_timer_cpu == cpu)		tick_do_update_jiffies64(now);	/*	 * When we are idle and the tick is stopped, we have to touch	 * the watchdog as we might not schedule for a really long	 * time. This happens on complete idle SMP systems while	 * waiting on the login prompt. We also increment the "start	 * of idle" jiffy stamp so the idle accounting adjustment we	 * do when we go busy again does not account too much ticks.	 */	if (ts->tick_stopped) {		touch_softlockup_watchdog();		ts->idle_jiffies++;	}	update_process_times(user_mode(regs));	profile_tick(CPU_PROFILING);	/* Do not restart, when we are in the idle loop */	if (ts->tick_stopped)		return;	while (tick_nohz_reprogram(ts, now)) {		now = ktime_get();		tick_do_update_jiffies64(now);	}}/** * tick_nohz_switch_to_nohz - switch to nohz mode */static void tick_nohz_switch_to_nohz(void){	struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);	ktime_t next;	if (!tick_nohz_enabled)		return;	local_irq_disable();	if (tick_switch_to_oneshot(tick_nohz_handler)) {		local_irq_enable();		return;	}	ts->nohz_mode = NOHZ_MODE_LOWRES;	/*	 * Recycle the hrtimer in ts, so we can share the	 * hrtimer_forward with the highres code.	 */	hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);	/* Get the next period */	next = tick_init_jiffy_update();	for (;;) {		ts->sched_timer.expires = next;		if (!tick_program_event(next, 0))			break;		next = ktime_add(next, tick_period);	}	local_irq_enable();	printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n",	       smp_processor_id());}#elsestatic inline void tick_nohz_switch_to_nohz(void) { }#endif /* NO_HZ *//* * High resolution timer specific code */#ifdef CONFIG_HIGH_RES_TIMERS/* * We rearm the timer until we get disabled by the idle code * Called with interrupts disabled and timer->base->cpu_base->lock held. */static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer){	struct tick_sched *ts =		container_of(timer, struct tick_sched, sched_timer);	struct hrtimer_cpu_base *base = timer->base->cpu_base;	struct pt_regs *regs = get_irq_regs();	ktime_t now = ktime_get();	int cpu = smp_processor_id();#ifdef CONFIG_NO_HZ	/*	 * Check if the do_timer duty was dropped. We don't care about	 * concurrency: This happens only when the cpu in charge went	 * into a long sleep. If two cpus happen to assign themself to	 * this duty, then the jiffies update is still serialized by	 * xtime_lock.	 */	if (unlikely(tick_do_timer_cpu == -1))		tick_do_timer_cpu = cpu;#endif	/* Check, if the jiffies need an update */	if (tick_do_timer_cpu == cpu)		tick_do_update_jiffies64(now);	/*	 * Do not call, when we are not in irq context and have	 * no valid regs pointer	 */	if (regs) {		/*		 * When we are idle and the tick is stopped, we have to touch		 * the watchdog as we might not schedule for a really long		 * time. This happens on complete idle SMP systems while		 * waiting on the login prompt. We also increment the "start of		 * idle" jiffy stamp so the idle accounting adjustment we do		 * when we go busy again does not account too much ticks.		 */		if (ts->tick_stopped) {			touch_softlockup_watchdog();			ts->idle_jiffies++;		}		/*		 * update_process_times() might take tasklist_lock, hence		 * drop the base lock. sched-tick hrtimers are per-CPU and		 * never accessible by userspace APIs, so this is safe to do.		 */		spin_unlock(&base->lock);		update_process_times(user_mode(regs));		profile_tick(CPU_PROFILING);		spin_lock(&base->lock);	}	/* Do not restart, when we are in the idle loop */	if (ts->tick_stopped)		return HRTIMER_NORESTART;	hrtimer_forward(timer, now, tick_period);	return HRTIMER_RESTART;}/** * tick_setup_sched_timer - setup the tick emulation timer */void tick_setup_sched_timer(void){	struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);	ktime_t now = ktime_get();	u64 offset;	/*	 * Emulate tick processing via per-CPU hrtimers:	 */	hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);	ts->sched_timer.function = tick_sched_timer;	ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;	/* Get the next period (per cpu) */	ts->sched_timer.expires = tick_init_jiffy_update();	offset = ktime_to_ns(tick_period) >> 1;	do_div(offset, num_possible_cpus());	offset *= smp_processor_id();	ts->sched_timer.expires = ktime_add_ns(ts->sched_timer.expires, offset);	for (;;) {		hrtimer_forward(&ts->sched_timer, now, tick_period);		hrtimer_start(&ts->sched_timer, ts->sched_timer.expires,			      HRTIMER_MODE_ABS);		/* Check, if the timer was already in the past */		if (hrtimer_active(&ts->sched_timer))			break;		now = ktime_get();	}#ifdef CONFIG_NO_HZ	if (tick_nohz_enabled)		ts->nohz_mode = NOHZ_MODE_HIGHRES;#endif}void tick_cancel_sched_timer(int cpu){	struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);	if (ts->sched_timer.base)		hrtimer_cancel(&ts->sched_timer);	ts->tick_stopped = 0;	ts->nohz_mode = NOHZ_MODE_INACTIVE;}#endif /* HIGH_RES_TIMERS *//** * Async notification about clocksource changes */void tick_clock_notify(void){	int cpu;	for_each_possible_cpu(cpu)		set_bit(0, &per_cpu(tick_cpu_sched, cpu).check_clocks);}/* * Async notification about clock event changes */void tick_oneshot_notify(void){	struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);	set_bit(0, &ts->check_clocks);}/** * Check, if a change happened, which makes oneshot possible. * * Called cyclic from the hrtimer softirq (driven by the timer * softirq) allow_nohz signals, that we can switch into low-res nohz * mode, because high resolution timers are disabled (either compile * or runtime). */int tick_check_oneshot_change(int allow_nohz){	struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);	if (!test_and_clear_bit(0, &ts->check_clocks))		return 0;	if (ts->nohz_mode != NOHZ_MODE_INACTIVE)		return 0;	if (!timekeeping_is_continuous() || !tick_is_oneshot_available())		return 0;	if (!allow_nohz)		return 1;	tick_nohz_switch_to_nohz();	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -