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.

timers: Fix nextevt calculation when no timers are pending

When no timer is queued into an empty timer base, the next_expiry will not
be updated. It was originally calculated as

base->clk + NEXT_TIMER_MAX_DELTA

When the timer base stays empty long enough (> NEXT_TIMER_MAX_DELTA), the
next_expiry value of the empty base suggests that there is a timer pending
soon. This might be more a kind of a theoretical problem, but the fix
doesn't hurt.

Use only base->next_expiry value as nextevt when timers are
pending. Otherwise nextevt will be jiffies + NEXT_TIMER_MAX_DELTA. As all
information is in place, update base->next_expiry value of the empty timer
base as well.

Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Link: https://lore.kernel.org/r/20231201092654.34614-13-anna-maria@linutronix.de

authored by

Anna-Maria Behnsen and committed by
Thomas Gleixner
da65f29d bb8caad5

+11 -2
+11 -2
kernel/time/timer.c
··· 1922 1922 u64 get_next_timer_interrupt(unsigned long basej, u64 basem) 1923 1923 { 1924 1924 struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); 1925 + unsigned long nextevt = basej + NEXT_TIMER_MAX_DELTA; 1925 1926 u64 expires = KTIME_MAX; 1926 - unsigned long nextevt; 1927 1927 bool was_idle; 1928 1928 1929 1929 /* ··· 1936 1936 raw_spin_lock(&base->lock); 1937 1937 if (base->next_expiry_recalc) 1938 1938 next_expiry_recalc(base); 1939 - nextevt = base->next_expiry; 1940 1939 1941 1940 /* 1942 1941 * We have a fresh next event. Check whether we can forward the ··· 1944 1945 __forward_timer_base(base, basej); 1945 1946 1946 1947 if (base->timers_pending) { 1948 + nextevt = base->next_expiry; 1949 + 1947 1950 /* If we missed a tick already, force 0 delta */ 1948 1951 if (time_before(nextevt, basej)) 1949 1952 nextevt = basej; 1950 1953 expires = basem + (u64)(nextevt - basej) * TICK_NSEC; 1954 + } else { 1955 + /* 1956 + * Move next_expiry for the empty base into the future to 1957 + * prevent a unnecessary raise of the timer softirq when the 1958 + * next_expiry value will be reached even if there is no timer 1959 + * pending. 1960 + */ 1961 + base->next_expiry = nextevt; 1951 1962 } 1952 1963 1953 1964 /*