Skip to content

Commit e71a415

Browse files
committed
hrtimer: Force clock_was_set() handling for the HIGHRES=n, NOHZ=y case
When CONFIG_HIGH_RES_TIMERS is disabled, but NOHZ is enabled then clock_was_set() is not doing anything. With HIGHRES=n the kernel relies on the periodic tick to update the clock offsets, but when NOHZ is enabled and active then CPUs which are in a deep idle sleep do not have a periodic tick which means the expiry of timers affected by clock_was_set() can be arbitrarily delayed up to the point where the CPUs are brought out of idle again. Make the clock_was_set() logic unconditionaly available so that idle CPUs are kicked out of idle to handle the update. Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 8c3b5e6 commit e71a415

File tree

1 file changed

+59
-28
lines changed

1 file changed

+59
-28
lines changed

kernel/time/hrtimer.c

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -739,23 +739,7 @@ static inline int hrtimer_is_hres_enabled(void)
739739
return hrtimer_hres_enabled;
740740
}
741741

742-
/*
743-
* Retrigger next event is called after clock was set
744-
*
745-
* Called with interrupts disabled via on_each_cpu()
746-
*/
747-
static void retrigger_next_event(void *arg)
748-
{
749-
struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases);
750-
751-
if (!__hrtimer_hres_active(base))
752-
return;
753-
754-
raw_spin_lock(&base->lock);
755-
hrtimer_update_base(base);
756-
hrtimer_force_reprogram(base, 0);
757-
raw_spin_unlock(&base->lock);
758-
}
742+
static void retrigger_next_event(void *arg);
759743

760744
/*
761745
* Switch to high resolution mode
@@ -781,9 +765,50 @@ static void hrtimer_switch_to_hres(void)
781765

782766
static inline int hrtimer_is_hres_enabled(void) { return 0; }
783767
static inline void hrtimer_switch_to_hres(void) { }
784-
static inline void retrigger_next_event(void *arg) { }
785768

786769
#endif /* CONFIG_HIGH_RES_TIMERS */
770+
/*
771+
* Retrigger next event is called after clock was set with interrupts
772+
* disabled through an SMP function call or directly from low level
773+
* resume code.
774+
*
775+
* This is only invoked when:
776+
* - CONFIG_HIGH_RES_TIMERS is enabled.
777+
* - CONFIG_NOHZ_COMMON is enabled
778+
*
779+
* For the other cases this function is empty and because the call sites
780+
* are optimized out it vanishes as well, i.e. no need for lots of
781+
* #ifdeffery.
782+
*/
783+
static void retrigger_next_event(void *arg)
784+
{
785+
struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases);
786+
787+
/*
788+
* When high resolution mode or nohz is active, then the offsets of
789+
* CLOCK_REALTIME/TAI/BOOTTIME have to be updated. Otherwise the
790+
* next tick will take care of that.
791+
*
792+
* If high resolution mode is active then the next expiring timer
793+
* must be reevaluated and the clock event device reprogrammed if
794+
* necessary.
795+
*
796+
* In the NOHZ case the update of the offset and the reevaluation
797+
* of the next expiring timer is enough. The return from the SMP
798+
* function call will take care of the reprogramming in case the
799+
* CPU was in a NOHZ idle sleep.
800+
*/
801+
if (!__hrtimer_hres_active(base) && !tick_nohz_active)
802+
return;
803+
804+
raw_spin_lock(&base->lock);
805+
hrtimer_update_base(base);
806+
if (__hrtimer_hres_active(base))
807+
hrtimer_force_reprogram(base, 0);
808+
else
809+
hrtimer_update_next_event(base);
810+
raw_spin_unlock(&base->lock);
811+
}
787812

788813
/*
789814
* When a timer is enqueued and expires earlier than the already enqueued
@@ -842,22 +867,28 @@ static void hrtimer_reprogram(struct hrtimer *timer, bool reprogram)
842867
}
843868

844869
/*
845-
* Clock realtime was set
846-
*
847-
* Change the offset of the realtime clock vs. the monotonic
848-
* clock.
870+
* Clock was set. This might affect CLOCK_REALTIME, CLOCK_TAI and
871+
* CLOCK_BOOTTIME (for late sleep time injection).
849872
*
850-
* We might have to reprogram the high resolution timer interrupt. On
851-
* SMP we call the architecture specific code to retrigger _all_ high
852-
* resolution timer interrupts. On UP we just disable interrupts and
853-
* call the high resolution interrupt code.
873+
* This requires to update the offsets for these clocks
874+
* vs. CLOCK_MONOTONIC. When high resolution timers are enabled, then this
875+
* also requires to eventually reprogram the per CPU clock event devices
876+
* when the change moves an affected timer ahead of the first expiring
877+
* timer on that CPU. Obviously remote per CPU clock event devices cannot
878+
* be reprogrammed. The other reason why an IPI has to be sent is when the
879+
* system is in !HIGH_RES and NOHZ mode. The NOHZ mode updates the offsets
880+
* in the tick, which obviously might be stopped, so this has to bring out
881+
* the remote CPU which might sleep in idle to get this sorted.
854882
*/
855883
void clock_was_set(void)
856884
{
857-
#ifdef CONFIG_HIGH_RES_TIMERS
885+
if (!hrtimer_hres_active() && !tick_nohz_active)
886+
goto out_timerfd;
887+
858888
/* Retrigger the CPU local events everywhere */
859889
on_each_cpu(retrigger_next_event, NULL, 1);
860-
#endif
890+
891+
out_timerfd:
861892
timerfd_clock_was_set();
862893
}
863894

0 commit comments

Comments
 (0)