Loading include/linux/timer.h +3 −0 Original line number Diff line number Diff line Loading @@ -190,6 +190,9 @@ extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires); extern void set_timer_slack(struct timer_list *time, int slack_hz); #ifdef CONFIG_SMP extern bool check_pending_deferrable_timers(int cpu); #endif #define TIMER_NOT_PINNED 0 #define TIMER_PINNED 1 Loading kernel/time/tick-sched.c +6 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <linux/percpu.h> #include <linux/profile.h> #include <linux/sched.h> #include <linux/timer.h> #include <linux/module.h> #include <linux/irq_work.h> #include <linux/posix-timers.h> Loading Loading @@ -829,6 +830,11 @@ static void __tick_nohz_idle_enter(struct tick_sched *ts) now = tick_nohz_start_idle(ts); #ifdef CONFIG_SMP if (check_pending_deferrable_timers(cpu)) raise_softirq_irqoff(TIMER_SOFTIRQ); #endif if (can_stop_idle_tick(cpu, ts)) { int was_stopped = ts->tick_stopped; Loading kernel/time/timer.c +32 −3 Original line number Diff line number Diff line Loading @@ -97,6 +97,7 @@ EXPORT_SYMBOL(boot_tvec_bases); static DEFINE_PER_CPU(struct tvec_base *, tvec_bases) = &boot_tvec_bases; #ifdef CONFIG_SMP struct tvec_base tvec_base_deferrable; static atomic_t deferrable_pending; #endif static inline void __run_timers(struct tvec_base *base); Loading Loading @@ -676,9 +677,13 @@ static inline bool is_deferrable_timer_base(struct tvec_base *base) static inline void __run_deferrable_timers(void) { if (smp_processor_id() == tick_do_timer_cpu && time_after_eq(jiffies, tvec_base_deferrable.timer_jiffies)) if (time_after_eq(jiffies, tvec_base_deferrable.timer_jiffies)) { if ((atomic_cmpxchg(&deferrable_pending, 1, 0) && tick_do_timer_cpu == TICK_DO_TIMER_NONE) || tick_do_timer_cpu == smp_processor_id()) __run_timers(&tvec_base_deferrable); } } static inline void init_deferrable_timer(void) Loading Loading @@ -1402,6 +1407,30 @@ static unsigned long cmp_next_hrtimer_event(unsigned long now, return expires; } #ifdef CONFIG_SMP /* * check_pending_deferrable_timers - Check for unbound deferrable timer expiry. * @cpu - Current CPU * * The function checks whether any global deferrable pending timers * are exipired or not. This function does not check cpu bounded * diferrable pending timers expiry. * * The function returns true when a cpu unbounded deferrable timer is expired. */ bool check_pending_deferrable_timers(int cpu) { if (cpu == tick_do_timer_cpu || tick_do_timer_cpu == TICK_DO_TIMER_NONE) { if (time_after_eq(jiffies, tvec_base_deferrable.timer_jiffies) && !atomic_cmpxchg(&deferrable_pending, 0, 1)) { return true; } } return false; } #endif /** * get_next_timer_interrupt - return the jiffy of the next pending timer * @now: current time (in jiffies) Loading Loading
include/linux/timer.h +3 −0 Original line number Diff line number Diff line Loading @@ -190,6 +190,9 @@ extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires); extern void set_timer_slack(struct timer_list *time, int slack_hz); #ifdef CONFIG_SMP extern bool check_pending_deferrable_timers(int cpu); #endif #define TIMER_NOT_PINNED 0 #define TIMER_PINNED 1 Loading
kernel/time/tick-sched.c +6 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <linux/percpu.h> #include <linux/profile.h> #include <linux/sched.h> #include <linux/timer.h> #include <linux/module.h> #include <linux/irq_work.h> #include <linux/posix-timers.h> Loading Loading @@ -829,6 +830,11 @@ static void __tick_nohz_idle_enter(struct tick_sched *ts) now = tick_nohz_start_idle(ts); #ifdef CONFIG_SMP if (check_pending_deferrable_timers(cpu)) raise_softirq_irqoff(TIMER_SOFTIRQ); #endif if (can_stop_idle_tick(cpu, ts)) { int was_stopped = ts->tick_stopped; Loading
kernel/time/timer.c +32 −3 Original line number Diff line number Diff line Loading @@ -97,6 +97,7 @@ EXPORT_SYMBOL(boot_tvec_bases); static DEFINE_PER_CPU(struct tvec_base *, tvec_bases) = &boot_tvec_bases; #ifdef CONFIG_SMP struct tvec_base tvec_base_deferrable; static atomic_t deferrable_pending; #endif static inline void __run_timers(struct tvec_base *base); Loading Loading @@ -676,9 +677,13 @@ static inline bool is_deferrable_timer_base(struct tvec_base *base) static inline void __run_deferrable_timers(void) { if (smp_processor_id() == tick_do_timer_cpu && time_after_eq(jiffies, tvec_base_deferrable.timer_jiffies)) if (time_after_eq(jiffies, tvec_base_deferrable.timer_jiffies)) { if ((atomic_cmpxchg(&deferrable_pending, 1, 0) && tick_do_timer_cpu == TICK_DO_TIMER_NONE) || tick_do_timer_cpu == smp_processor_id()) __run_timers(&tvec_base_deferrable); } } static inline void init_deferrable_timer(void) Loading Loading @@ -1402,6 +1407,30 @@ static unsigned long cmp_next_hrtimer_event(unsigned long now, return expires; } #ifdef CONFIG_SMP /* * check_pending_deferrable_timers - Check for unbound deferrable timer expiry. * @cpu - Current CPU * * The function checks whether any global deferrable pending timers * are exipired or not. This function does not check cpu bounded * diferrable pending timers expiry. * * The function returns true when a cpu unbounded deferrable timer is expired. */ bool check_pending_deferrable_timers(int cpu) { if (cpu == tick_do_timer_cpu || tick_do_timer_cpu == TICK_DO_TIMER_NONE) { if (time_after_eq(jiffies, tvec_base_deferrable.timer_jiffies) && !atomic_cmpxchg(&deferrable_pending, 0, 1)) { return true; } } return false; } #endif /** * get_next_timer_interrupt - return the jiffy of the next pending timer * @now: current time (in jiffies) Loading