Re: [patch 01/12] clockevents: Prevent timer interrupt starvation
From: Thomas Weißschuh
Date: Wed Apr 08 2026 - 10:00:28 EST
On Wed, Apr 08, 2026 at 02:41:20PM +0200, Thomas Weißschuh wrote:
> Hi Thomas,
>
> On Tue, Apr 07, 2026 at 10:54:17AM +0200, Thomas Gleixner wrote:
> > From: Thomas Gleixner <tglx@xxxxxxxxxx>
> >
> > Calvin reported an odd NMI watchdog lockup which claims that the CPU locked
> > up in user space. He provided a reproducer, which sets up a timerfd based
> > timer and then rearms it in a loop with an absolute expiry time of 1ns.
> >
> > As the expiry time is in the past, the timer ends up as the first expiring
> > timer in the per CPU hrtimer base and the clockevent device is programmed
> > with the minimum delta value. If the machine is fast enough, this ends up
> > in a endless loop of programming the delta value to the minimum value
> > defined by the clock event device, before the timer interrupt can fire,
> > which starves the interrupt and consequently triggers the lockup detector
> > because the hrtimer callback of the lockup mechanism is never invoked.
> >
> > As a first step to prevent this, avoid reprogramming the clock event device
> > when:
> > - a forced minimum delta event is pending
> > - the new expiry delta is less then or equal to the minimum delta
>
> with this patch now in the tip tree my QEMU/virtme-ng based machine
> fails to boot. The startup seems to freeze in:
> start_kernel() -> rest_init() -> schedule_preempt_disabled() -> schedule()
>
> CONFIG_GENERIC_CLOCKEVENTS=y
> CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
> CONFIG_GENERIC_CLOCKEVENTS_BROADCAST_IDLE=y
> CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
> CONFIG_HZ=1000
>
> CPU: i5-1135G7
> clock event device: lapic-deadline
>
> The clockevent device is still reprogrammed each millisecond,
> presumably for the tick.
>
> (...)
This fixes the issue for me:
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -369,7 +369,7 @@ int clockevents_program_event(struct clock_event_device *dev, ktime_t expires, b
if (dev->next_event_forced)
return 0;
- if (dev->set_next_event(dev->min_delta_ticks, dev)) {
+ if (dev->set_next_event(dev->min_delta_ns, dev)) {
if (!force || clockevents_program_min_delta(dev))
return -ETIME;
}
Thomas