mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
A samll set of timer related fixes:
- Plug a race between rearm and process tick in the posix CPU timers code - Make the optimization to avoid recalculation of the next timer interrupt work correctly when there are no timers pending. -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAmD9LLUTHHRnbHhAbGlu dXRyb25peC5kZQAKCRCmGPVMDXSYocqMD/9ciaE5J4gbsamavrPfMaQNo3c3mom1 3xoskHFKiz9fnYL/f3yNQ2OjXl+lxV0VLSwjJnc1TfhQM5g+X7uI4P/sCZzHtEmP F3jTCUX99DSlTEB4Fc3ssr/hZPQab9nXearek9eAEpLKQDe1U1q2p314Mr4dA+Kj awJUuOlkLt+NwRCajuZK6Ur0D1Zte56C/Nl3PeppgJY1U5tLCKTE8ZmRbdLo11zM BEMFL95on1a/wKzTkuYqhfSQn4JWZo4lLP9jVHueF2nbPbOGdC9VwvegRMtRKG/k 0I8n7mcXvzi9pDP08o96rzjdZ9KBpG2hLkL0PgCDjrXwlOBH7tDkOBajJ+x5AgAf 71Zi/XOfjaHbkm37uLTTeerG2pKilds7ukjnQ3VS3t/XfPw6Nr6r9ig5AyBxpnjk 8Shw8kfEOApLEnmYwKAXHCewjxppp9pDsR4J7sYIfiYoDZRfF56Xyr/pKa8cpZge 9ByK8Pul4J9RhTOgIgJNMBb78gmFxsKi5CMt6kj8O89omc4pIUVpEK0z3kWmbjrd m1mtcO2kS/ry+7TgAjkxHcrcm/QX+y/2SrvvLoqVLAJQfIrffsiGGehaIXS8rAKg jlCd3s0NET6yULyQwI7qUdS+ZgtYSQKfIkU38VVcXaplUOABWcCwNXRh0rk6+gBs +HK8UxQnAYRGrw== =Q6oh -----END PGP SIGNATURE----- Merge tag 'timers-urgent-2021-07-25' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull timer fixes from Thomas Gleixner: "A small set of timer related fixes: - Plug a race between rearm and process tick in the posix CPU timers code - Make the optimization to avoid recalculation of the next timer interrupt work correctly when there are no timers pending" * tag 'timers-urgent-2021-07-25' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: timers: Fix get_next_timer_interrupt() with no timers pending posix-cpu-timers: Fix rearm racing against process tick
This commit is contained in:
commit
12e9bd168c
2 changed files with 10 additions and 8 deletions
|
@ -991,6 +991,11 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)
|
||||||
if (!p)
|
if (!p)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
/* Protect timer list r/w in arm_timer() */
|
||||||
|
sighand = lock_task_sighand(p, &flags);
|
||||||
|
if (unlikely(sighand == NULL))
|
||||||
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fetch the current sample and update the timer's expiry time.
|
* Fetch the current sample and update the timer's expiry time.
|
||||||
*/
|
*/
|
||||||
|
@ -1001,11 +1006,6 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)
|
||||||
|
|
||||||
bump_cpu_timer(timer, now);
|
bump_cpu_timer(timer, now);
|
||||||
|
|
||||||
/* Protect timer list r/w in arm_timer() */
|
|
||||||
sighand = lock_task_sighand(p, &flags);
|
|
||||||
if (unlikely(sighand == NULL))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now re-arm for the new expiry time.
|
* Now re-arm for the new expiry time.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -207,6 +207,7 @@ struct timer_base {
|
||||||
unsigned int cpu;
|
unsigned int cpu;
|
||||||
bool next_expiry_recalc;
|
bool next_expiry_recalc;
|
||||||
bool is_idle;
|
bool is_idle;
|
||||||
|
bool timers_pending;
|
||||||
DECLARE_BITMAP(pending_map, WHEEL_SIZE);
|
DECLARE_BITMAP(pending_map, WHEEL_SIZE);
|
||||||
struct hlist_head vectors[WHEEL_SIZE];
|
struct hlist_head vectors[WHEEL_SIZE];
|
||||||
} ____cacheline_aligned;
|
} ____cacheline_aligned;
|
||||||
|
@ -595,6 +596,7 @@ static void enqueue_timer(struct timer_base *base, struct timer_list *timer,
|
||||||
* can reevaluate the wheel:
|
* can reevaluate the wheel:
|
||||||
*/
|
*/
|
||||||
base->next_expiry = bucket_expiry;
|
base->next_expiry = bucket_expiry;
|
||||||
|
base->timers_pending = true;
|
||||||
base->next_expiry_recalc = false;
|
base->next_expiry_recalc = false;
|
||||||
trigger_dyntick_cpu(base, timer);
|
trigger_dyntick_cpu(base, timer);
|
||||||
}
|
}
|
||||||
|
@ -1582,6 +1584,7 @@ static unsigned long __next_timer_interrupt(struct timer_base *base)
|
||||||
}
|
}
|
||||||
|
|
||||||
base->next_expiry_recalc = false;
|
base->next_expiry_recalc = false;
|
||||||
|
base->timers_pending = !(next == base->clk + NEXT_TIMER_MAX_DELTA);
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
@ -1633,7 +1636,6 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
|
||||||
struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
|
struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
|
||||||
u64 expires = KTIME_MAX;
|
u64 expires = KTIME_MAX;
|
||||||
unsigned long nextevt;
|
unsigned long nextevt;
|
||||||
bool is_max_delta;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pretend that there is no timer pending if the cpu is offline.
|
* Pretend that there is no timer pending if the cpu is offline.
|
||||||
|
@ -1646,7 +1648,6 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
|
||||||
if (base->next_expiry_recalc)
|
if (base->next_expiry_recalc)
|
||||||
base->next_expiry = __next_timer_interrupt(base);
|
base->next_expiry = __next_timer_interrupt(base);
|
||||||
nextevt = base->next_expiry;
|
nextevt = base->next_expiry;
|
||||||
is_max_delta = (nextevt == base->clk + NEXT_TIMER_MAX_DELTA);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have a fresh next event. Check whether we can forward the
|
* We have a fresh next event. Check whether we can forward the
|
||||||
|
@ -1664,7 +1665,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
|
||||||
expires = basem;
|
expires = basem;
|
||||||
base->is_idle = false;
|
base->is_idle = false;
|
||||||
} else {
|
} else {
|
||||||
if (!is_max_delta)
|
if (base->timers_pending)
|
||||||
expires = basem + (u64)(nextevt - basej) * TICK_NSEC;
|
expires = basem + (u64)(nextevt - basej) * TICK_NSEC;
|
||||||
/*
|
/*
|
||||||
* If we expect to sleep more than a tick, mark the base idle.
|
* If we expect to sleep more than a tick, mark the base idle.
|
||||||
|
@ -1947,6 +1948,7 @@ int timers_prepare_cpu(unsigned int cpu)
|
||||||
base = per_cpu_ptr(&timer_bases[b], cpu);
|
base = per_cpu_ptr(&timer_bases[b], cpu);
|
||||||
base->clk = jiffies;
|
base->clk = jiffies;
|
||||||
base->next_expiry = base->clk + NEXT_TIMER_MAX_DELTA;
|
base->next_expiry = base->clk + NEXT_TIMER_MAX_DELTA;
|
||||||
|
base->timers_pending = false;
|
||||||
base->is_idle = false;
|
base->is_idle = false;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue