Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

hrtimer: Re-arrange hrtimer_interrupt()

Rework hrtimer_interrupt() such that reprogramming is split out into an
independent function at the end of the interrupt.

This prepares for reprogramming getting delayed beyond the end of
hrtimer_interrupt().

Notably, this changes the hang handling to always wait 100ms instead of
trying to keep it proportional to the actual delay. This simplifies the
state, also this really shouldn't be happening.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260224163430.870639266@kernel.org

+44 -49
+44 -49
kernel/time/hrtimer.c
··· 690 690 cpu_base->hres_active : 0; 691 691 } 692 692 693 + static inline void hrtimer_rearm_event(ktime_t expires_next, bool deferred) 694 + { 695 + trace_hrtimer_rearm(expires_next, deferred); 696 + tick_program_event(expires_next, 1); 697 + } 698 + 693 699 static void __hrtimer_reprogram(struct hrtimer_cpu_base *cpu_base, struct hrtimer *next_timer, 694 700 ktime_t expires_next) 695 701 { ··· 721 715 if (!hrtimer_hres_active(cpu_base) || cpu_base->hang_detected) 722 716 return; 723 717 724 - tick_program_event(expires_next, 1); 718 + hrtimer_rearm_event(expires_next, false); 725 719 } 726 720 727 721 /* ··· 1946 1940 #ifdef CONFIG_HIGH_RES_TIMERS 1947 1941 1948 1942 /* 1943 + * Very similar to hrtimer_force_reprogram(), except it deals with 1944 + * in_hrtirq and hang_detected. 1945 + */ 1946 + static void hrtimer_rearm(struct hrtimer_cpu_base *cpu_base, ktime_t now) 1947 + { 1948 + ktime_t expires_next = hrtimer_update_next_event(cpu_base); 1949 + 1950 + cpu_base->expires_next = expires_next; 1951 + cpu_base->in_hrtirq = false; 1952 + 1953 + if (unlikely(cpu_base->hang_detected)) { 1954 + /* 1955 + * Give the system a chance to do something else than looping 1956 + * on hrtimer interrupts. 1957 + */ 1958 + expires_next = ktime_add_ns(now, 100 * NSEC_PER_MSEC); 1959 + cpu_base->hang_detected = false; 1960 + } 1961 + hrtimer_rearm_event(expires_next, false); 1962 + } 1963 + 1964 + /* 1949 1965 * High resolution timer interrupt 1950 1966 * Called with interrupts disabled 1951 1967 */ ··· 2002 1974 2003 1975 __hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD); 2004 1976 2005 - /* Reevaluate the clock bases for the [soft] next expiry */ 2006 - expires_next = hrtimer_update_next_event(cpu_base); 2007 - /* 2008 - * Store the new expiry value so the migration code can verify 2009 - * against it. 2010 - */ 2011 - cpu_base->expires_next = expires_next; 2012 - cpu_base->in_hrtirq = false; 2013 - raw_spin_unlock_irqrestore(&cpu_base->lock, flags); 2014 - 2015 - /* Reprogramming necessary ? */ 2016 - if (!tick_program_event(expires_next, 0)) { 2017 - cpu_base->hang_detected = false; 2018 - return; 2019 - } 2020 - 2021 1977 /* 2022 1978 * The next timer was already expired due to: 2023 1979 * - tracing 2024 1980 * - long lasting callbacks 2025 1981 * - being scheduled away when running in a VM 2026 1982 * 2027 - * We need to prevent that we loop forever in the hrtimer 2028 - * interrupt routine. We give it 3 attempts to avoid 2029 - * overreacting on some spurious event. 2030 - * 2031 - * Acquire base lock for updating the offsets and retrieving 2032 - * the current time. 1983 + * We need to prevent that we loop forever in the hrtiner interrupt 1984 + * routine. We give it 3 attempts to avoid overreacting on some 1985 + * spurious event. 2033 1986 */ 2034 - raw_spin_lock_irqsave(&cpu_base->lock, flags); 2035 1987 now = hrtimer_update_base(cpu_base); 2036 - cpu_base->nr_retries++; 2037 - if (++retries < 3) 2038 - goto retry; 2039 - /* 2040 - * Give the system a chance to do something else than looping 2041 - * here. We stored the entry time, so we know exactly how long 2042 - * we spent here. We schedule the next event this amount of 2043 - * time away. 2044 - */ 2045 - cpu_base->nr_hangs++; 2046 - cpu_base->hang_detected = true; 2047 - raw_spin_unlock_irqrestore(&cpu_base->lock, flags); 1988 + expires_next = hrtimer_update_next_event(cpu_base); 1989 + if (expires_next < now) { 1990 + if (++retries < 3) 1991 + goto retry; 2048 1992 2049 - delta = ktime_sub(now, entry_time); 2050 - if ((unsigned int)delta > cpu_base->max_hang_time) 2051 - cpu_base->max_hang_time = (unsigned int) delta; 2052 - /* 2053 - * Limit it to a sensible value as we enforce a longer 2054 - * delay. Give the CPU at least 100ms to catch up. 2055 - */ 2056 - if (delta > 100 * NSEC_PER_MSEC) 2057 - expires_next = ktime_add_ns(now, 100 * NSEC_PER_MSEC); 2058 - else 2059 - expires_next = ktime_add(now, delta); 2060 - tick_program_event(expires_next, 1); 2061 - pr_warn_once("hrtimer: interrupt took %llu ns\n", ktime_to_ns(delta)); 1993 + delta = ktime_sub(now, entry_time); 1994 + cpu_base->max_hang_time = max_t(unsigned int, cpu_base->max_hang_time, delta); 1995 + cpu_base->nr_hangs++; 1996 + cpu_base->hang_detected = true; 1997 + } 1998 + 1999 + hrtimer_rearm(cpu_base, now); 2000 + raw_spin_unlock_irqrestore(&cpu_base->lock, flags); 2062 2001 } 2063 2002 #endif /* !CONFIG_HIGH_RES_TIMERS */ 2064 2003