diff options
Diffstat (limited to 'kernel/kernel/time/timer.c')
-rw-r--r-- | kernel/kernel/time/timer.c | 40 |
1 files changed, 37 insertions, 3 deletions
diff --git a/kernel/kernel/time/timer.c b/kernel/kernel/time/timer.c index fee8682c2..016a0bf52 100644 --- a/kernel/kernel/time/timer.c +++ b/kernel/kernel/time/timer.c @@ -1453,9 +1453,11 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) * the base lock to check when the next timer is pending and so * we assume the next jiffy. */ - return basem + TICK_NSEC; -#endif + if (!spin_do_trylock(&base->lock)) + return basem + TICK_NSEC; +#else spin_lock(&base->lock); +#endif if (base->active_timers) { if (time_before_eq(base->next_timer, base->timer_jiffies)) base->next_timer = __next_timer_interrupt(base); @@ -1465,7 +1467,11 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) else expires = basem + (nextevt - basej) * TICK_NSEC; } +#ifdef CONFIG_PREEMPT_RT_FULL + rt_spin_unlock(&base->lock); +#else spin_unlock(&base->lock); +#endif return cmp_next_hrtimer_event(basem, expires); } @@ -1509,8 +1515,36 @@ static void run_timer_softirq(struct softirq_action *h) */ void run_local_timers(void) { + struct tvec_base *base = this_cpu_ptr(&tvec_bases); + hrtimer_run_queues(); - raise_softirq(TIMER_SOFTIRQ); + /* + * We can access this lockless as we are in the timer + * interrupt. If there are no timers queued, nothing to do in + * the timer softirq. + */ +#ifdef CONFIG_PREEMPT_RT_FULL + if (irq_work_needs_cpu()) { + raise_softirq(TIMER_SOFTIRQ); + return; + } + if (!spin_do_trylock(&base->lock)) { + raise_softirq(TIMER_SOFTIRQ); + return; + } +#endif + if (!base->active_timers) + goto out; + + /* Check whether the next pending timer has expired */ + if (time_before_eq(base->next_timer, jiffies)) + raise_softirq(TIMER_SOFTIRQ); +out: +#ifdef CONFIG_PREEMPT_RT_FULL + rt_spin_unlock(&base->lock); +#endif + /* The ; ensures that gcc won't complain in the !RT case */ + ; } #ifdef __ARCH_WANT_SYS_ALARM |