hrtimers: Prevent hrtimer interrupt starvation
Subsystems (8)
Thomas Gleixner
maintainerv2 cover hrtimers: Prevent hrtimer interrupt starvation
This is a follow up to V1 which can be found here:
https://lore.kernel.org/lkml/[email protected]
Calvin reported an odd NMI watchdog lockup which claims that the CPU locked up in user space:
https://lore.kernel.org/lkml/[email protected]/
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.
The first patch in the V1 series changes the clockevent set next event mechanism to prevent reprogramming of the clockevent device when the minimum delta value was programmed unless the new delta is larger than that. It's a less convoluted variant of the patch which was posted in the above linked thread and was confirmed to prevent the starvation problem.
But that's only to be considered the last resort because it results in an insane amount of avoidable hrtimer interrupts. That patch has been merged into the tip tree already.
The problem of user controlled timers is that the input value is only sanity checked vs. validity of the provided timespec and clamped to be in the maximum allowable range. But for performance reasons for in kernel usage there is no check whether a to be armed timer might have been expired already at enqueue time.
This series addresses this by providing a separate interface to arm user controlled timers. This works the same way as the existing hrtimer_start_range_ns(), but in case that the timer ends up as the first timer in the clock base after enqueue it provides additional checks:
- Whether the timer becomes the first expiring timer in the CPU base.
If not the timer is considered to expire in the future as there is already an earlier event programmed.
- Whether the timer has expired already by comparing the expiry value against current time.
If it is expired, the timer is removed from the clock base and the function returns false, so that the caller can handle it. That's required because the function cannot invoke the callback as that might need to acquire a lock which is held by the caller.
This function is then used for the user controlled timer arming interfaces mainly by converting hrtimer sleeper over to it. That affects a few in kernel users too, but the overhead is minimal in that case and it spares a tedious whack the mole game all over the tree.
The other usage sites in posixtimers, alarmtimers and timerfd are converted as well, which should cover the vast majority of user space controllable timers as far as my investigation goes.
Changes vs. V1:
- Dropped the clockevents patch as it is already merged
- Rebased on tip timers/core
- Moved the user check into hrtimer_start_range_ns_user() - Peter
- Renamed alarmtimer_start() to alarm_start_timer() - Peter
- Picked up tags as appropriate
The series applies against tip timers/core and is also available from git:
git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git hrtimer-exp-v2
Thanks,
tglx
--- drivers/power/supply/charger-manager.c | 12 +- fs/timerfd.c | 117 ++++++++++++++++----------- include/linux/alarmtimer.h | 9 +- include/linux/hrtimer.h | 20 ++++ include/trace/events/timer.h | 13 +++ kernel/time/alarmtimer.c | 70 +++++++--------- kernel/time/hrtimer.c | 140 ++++++++++++++++++++++++++++----- kernel/time/posix-cpu-timers.c | 18 ++-- kernel/time/posix-timers.c | 35 +++++--- kernel/time/posix-timers.h | 4 net/netfilter/xt_IDLETIMER.c | 24 ++++- 11 files changed, 320 insertions(+), 142 deletions(-)
Thomas Gleixner
maintainerPATCH v2 1/11 hrtimer: Provide hrtimer_start_range_ns_user()
Calvin reported an odd NMI watchdog lockup which claims that the CPU locked up in user space. He provided a reproducer, which set's 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.
The clockevents code already has a last resort mechanism to prevent that, but it's sensible to catch such issues before trying to reprogram the clock event device.
Provide a variant of hrtimer_start_range_ns(), which sanity checks the timer after queueing it. It does not so before because the timer might be armed and therefore needs to be dequeued. also we optimize for the latest possible point to check, so that the clock event prevention is avoided as much as possible.
If the timer is already expired _before_ the clock event is reprogrammed, remove the timer from the queue and signal to the caller that the operation failed by returning false.
That allows the caller to take immediate action without going through the loops and hoops of the hrtimer interrupt.
The queueing code can't invoke the timer callback as the caller might hold a lock which is taken in the callback.
Add a tracepoint which allows to analyze the expired at start situation.
---
V2: Moved the user check into hrtimer_start_range_ns_user() and handled
the NONE case explictly. - PeterZ
Rebased on tip timers/core
--- include/linux/hrtimer.h | 20 +++++- include/trace/events/timer.h | 13 ++++ kernel/time/hrtimer.c | 134 +++++++++++++++++++++++++++++++++++++------ 3 files changed, 148 insertions(+), 19 deletions(-)
include/linux/hrtimer.h +17 -3
@@ -206,6 +206,9 @@ static inline void destroy_hrtimer_on_stextern void hrtimer_start_range_ns (struct hrtimer *timer,ktime_t tim,u64 range_ns,const enum hrtimer_mode mode); +extern bool hrtimer_start_range_ns_user (struct hrtimer *timer,ktime_t tim, +u64 range_ns,const enum hrtimer_mode mode); +/** * hrtimer_start - (re)start an hrtimer * @timer: the timer to be added
@@ -223,17 +226,28 @@ static inline void hrtimer_start(structextern int hrtimer_cancel (struct hrtimer *timer);extern int hrtimer_try_to_cancel (struct hrtimer *timer); -static inline void hrtimer_start_expires (struct hrtimer *timer, -enum hrtimer_mode mode) +static inline void hrtimer_start_expires (struct hrtimer *timer,enum hrtimer_mode mode) { -u64 delta;ktime_t soft, hard; +u64 delta; + soft =hrtimer_get_softexpires (timer); hard =hrtimer_get_expires (timer); delta =ktime_to_ns (ktime_sub (hard, soft));hrtimer_start_range_ns (timer, soft, delta, mode); } +static inline bool hrtimer_start_expires_user (struct hrtimer *timer,enum hrtimer_mode mode) +{ +ktime_t soft, hard; +u64 delta; + + soft =hrtimer_get_softexpires (timer); + hard =hrtimer_get_expires (timer); + delta =ktime_to_ns (ktime_sub (hard, soft)); +return hrtimer_start_range_ns_user (timer, soft, delta, mode); +} +void hrtimer_sleeper_start_expires (struct hrtimer_sleeper *sl,enum hrtimer_mode mode);
include/trace/events/timer.h +13 -0
@@ -299,6 +299,19 @@ DECLARE_EVENT_CLASS(hrtimer_class, );/** +* hrtimer_start_expired - Invoked when a expired timer was started +* @hrtimer: pointer to struct hrtimer +* +* Preceeded by a hrtimer_start tracepoint. +*/ +DEFINE_EVENT (hrtimer_class, hrtimer_start_expired, + + TP_PROTO(struct hrtimer *hrtimer), + +TP_ARGS (hrtimer) +); + +/** * hrtimer_expire_exit - called immediately after the hrtimer callback returns * @hrtimer: pointer to struct hrtimer *
kernel/time/hrtimer.c +118 -16
184 lines not on this page · raw message
Re: [patch V2 01/11] hrtimer: Provide hrtimer_start_range_ns_user()
Quoted 32 lines · Thomas Gleixner
Calvin reported an odd NMI watchdog lockup which claims that the CPU locked up in user space. He provided a reproducer, which set's 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.
The clockevents code already has a last resort mechanism to prevent that, but it's sensible to catch such issues before trying to reprogram the clock event device.
Provide a variant of
hrtimer_start_range_ns(), which sanity checks the timer after queueing it. It does not so before because the timer might be armed and therefore needs to be dequeued. also we optimize for the latest possible point to check, so that the clock event prevention is avoided as much as possible.If the timer is already expired _before_ the clock event is reprogrammed, remove the timer from the queue and signal to the caller that the operation failed by returning false.
That allows the caller to take immediate action without going through the loops and hoops of the hrtimer interrupt.
The queueing code can't invoke the timer callback as the caller might hold a lock which is taken in the callback.
Quoted 6 lines
Add a tracepoint which allows to analyze the expired at start situation.
Reported-by Calvin Owens <[email protected]>Signed-off-by Thomas Gleixner <[email protected]>Cc Anna-Maria Behnsen <[email protected]>Cc Frederic Weisbecker <[email protected]>
Signature · 2 lines
Frederic Weisbecker SUSE Labs
[tip: timers/core] hrtimer: Provide hrtimer_start_range_ns_user()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: bd5956166d20adbde3af0f6f265dc2f0ce5f4df9 Gitweb: https://git.kernel.org/tip/bd5956166d20adbde3af0f6f265dc2f0ce5f4df9 Author: Thomas Gleixner <[email protected]> AuthorDate: Wed, 08 Apr 2026 13:53:46 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Fri, 01 May 2026 21:36:11 +02:00
hrtimer: Provide hrtimer_start_range_ns_user()
Calvin reported an odd NMI watchdog lockup which claims that the CPU locked up in user space. He provided a reproducer, which set's 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.
The clockevents code already has a last resort mechanism to prevent that, but it's sensible to catch such issues before trying to reprogram the clock event device.
Provide a variant of hrtimer_start_range_ns(), which sanity checks the timer after queueing it. It does not so before because the timer might be armed and therefore needs to be dequeued. also we optimize for the latest possible point to check, so that the clock event prevention is avoided as much as possible.
If the timer is already expired _before_ the clock event is reprogrammed, remove the timer from the queue and signal to the caller that the operation failed by returning false.
That allows the caller to take immediate action without going through the loops and hoops of the hrtimer interrupt.
The queueing code can't invoke the timer callback as the caller might hold a lock which is taken in the callback.
Add a tracepoint which allows to analyze the expired at start situation.
--- include/linux/hrtimer.h | 20 ++++- include/trace/events/timer.h | 13 +++- kernel/time/hrtimer.c | 134 +++++++++++++++++++++++++++++----- 3 files changed, 148 insertions(+), 19 deletions(-)
include/linux/hrtimer.h +17 -3
@@ -206,6 +206,9 @@ static inline void destroy_hrtimer_on_stack(struct hrtimer *timer) { }extern void hrtimer_start_range_ns (struct hrtimer *timer,ktime_t tim,u64 range_ns,const enum hrtimer_mode mode); +extern bool hrtimer_start_range_ns_user (struct hrtimer *timer,ktime_t tim, +u64 range_ns,const enum hrtimer_mode mode); +/** * hrtimer_start - (re)start an hrtimer * @timer: the timer to be added
@@ -223,17 +226,28 @@ static inline void hrtimer_start(struct hrtimer *timer, ktime_t tim,extern int hrtimer_cancel (struct hrtimer *timer);extern int hrtimer_try_to_cancel (struct hrtimer *timer); -static inline void hrtimer_start_expires (struct hrtimer *timer, -enum hrtimer_mode mode) +static inline void hrtimer_start_expires (struct hrtimer *timer,enum hrtimer_mode mode) { -u64 delta;ktime_t soft, hard; +u64 delta; + soft =hrtimer_get_softexpires (timer); hard =hrtimer_get_expires (timer); delta =ktime_to_ns (ktime_sub (hard, soft));hrtimer_start_range_ns (timer, soft, delta, mode); } +static inline bool hrtimer_start_expires_user (struct hrtimer *timer,enum hrtimer_mode mode) +{ +ktime_t soft, hard; +u64 delta; + + soft =hrtimer_get_softexpires (timer); + hard =hrtimer_get_expires (timer); + delta =ktime_to_ns (ktime_sub (hard, soft)); +return hrtimer_start_range_ns_user (timer, soft, delta, mode); +} +void hrtimer_sleeper_start_expires (struct hrtimer_sleeper *sl,enum hrtimer_mode mode);
include/trace/events/timer.h +13 -0
@@ -299,6 +299,19 @@ DECLARE_EVENT_CLASS(hrtimer_class, );/** +* hrtimer_start_expired - Invoked when a expired timer was started +* @hrtimer: pointer to struct hrtimer +* +* Preceeded by a hrtimer_start tracepoint. +*/ +DEFINE_EVENT (hrtimer_class, hrtimer_start_expired, + + TP_PROTO(struct hrtimer *hrtimer), + +TP_ARGS (hrtimer) +); + +/** * hrtimer_expire_exit - called immediately after the hrtimer callback returns * @hrtimer: pointer to struct hrtimer *
kernel/time/hrtimer.c +118 -16
184 lines not on this page · raw message
Re: [patch V2 01/11] hrtimer: Provide hrtimer_start_range_ns_user()
In reply to Thomas Gleixnerkernel/time/hrtimer.c static inline bool hrtimer_keep_base(str · line 1362
Quoted 8 lines · Thomas Gleixner
kernel/time/hrtimer.c +6
-0+enum { +HRTIMER_REPROGRAM_NONE , +HRTIMER_REPROGRAM , +HRTIMER_REPROGRAM_FORCE , +}; +static bool __hrtimer_start_range_ns (struct hrtimer *timer,ktime_t tim,u64 delta_ns,const enum hrtimer_mode mode,struct hrtimer_clock_base *base)
The return type for this function needs to changed from bool to enum whatever... Otherwise HRTIMER_REPROGRAM and HRTIMER_REPROGRAM_FORCE are both just true.
Quoted 11 lines
{
kernel/time/hrtimer.c +1
-1@@ -1410,7 +1416,7 @@ static bool __hrtimer_start_range_ns(str/* If a deferred rearm is pending skip reprogramming the device */ if (cpu_base->deferred_rearm) { cpu_base->deferred_needs_update = true; -return false; +return HRTIMER_REPROGRAM_NONE ; }if (!was_first || cpu_base != this_cpu_base) {
kernel/time/hrtimer.c static bool __hrtimer_start_range_ns(str · line 1432
Quoted 5 lines
kernel/time/hrtimer.c +1
-1@@ -1423,7 +1429,7 @@ static bool __hrtimer_start_range_ns(str* callbacks. */ if (likely (hrtimer_base_is_online (this_cpu_base))) -return first; +return first ?HRTIMER_REPROGRAM :HRTIMER_REPROGRAM_NONE ;
regards,
dan carpenter
Thomas Gleixner
maintainerRe: [patch V2 01/11] hrtimer: Provide hrtimer_start_range_ns_user()
Quoted 13 lines · Dan Carpenter
kernel/time/hrtimer.c static inline bool hrtimer_keep_base(str · line 1362
Quoted 8 lines · Thomas Gleixner
kernel/time/hrtimer.c +6
-0+enum { +HRTIMER_REPROGRAM_NONE , +HRTIMER_REPROGRAM , +HRTIMER_REPROGRAM_FORCE , +}; +static bool __hrtimer_start_range_ns (struct hrtimer *timer,ktime_t tim,u64 delta_ns,const enum hrtimer_mode mode,struct hrtimer_clock_base *base)The return type for this function needs to changed from bool to enum whatever... Otherwise
HRTIMER_REPROGRAMandHRTIMER_REPROGRAM_FORCEare both just true.
Duh, yes.
Thomas Gleixner
maintainerPATCH v2 2/11 hrtimer: Use hrtimer_start_expires_user() for hrtimer sleepers
In reply to Thomas GleixnerMost hrtimer sleepers are user controlled and user space can hand arbitrary expiry values in as long as they are valid timespecs. If the expiry value is in the past then this requires a full loop through reprogramming the clock event device, taking the hrtimer interrupt, waking the task and reprogram again.
Use hrtimer_start_expires_user() which avoids the full round trip by checking the timer for expiry on enqueue.
--- kernel/time/hrtimer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
kernel/time/hrtimer.c +5 -1
@@ -2152,7 +2152,11 @@ void hrtimer_sleeper_start_expires(strucif (IS_ENABLED (CONFIG_PREEMPT_RT ) && sl->timer.is_hard) mode |=HRTIMER_MODE_HARD ; -hrtimer_start_expires (&sl->timer, mode); +/* If already expired, clear the task pointer and set current state to running */ +if (!hrtimer_start_expires_user (&sl->timer, mode)) { + sl->task =NULL ; +__set_current_state (TASK_RUNNING ); + } }EXPORT_SYMBOL_GPL (hrtimer_sleeper_start_expires);
Re: [patch V2 02/11] hrtimer: Use hrtimer_start_expires_user() for hrtimer sleepers
Quoted 6 lines · Thomas Gleixner
Most hrtimer sleepers are user controlled and user space can hand arbitrary expiry values in as long as they are valid timespecs. If the expiry value is in the past then this requires a full loop through reprogramming the clock event device, taking the hrtimer interrupt, waking the task and reprogram again.
Quoted 7 lines
Use
hrtimer_start_expires_user()which avoids the full round trip by checking the timer for expiry on enqueue.Signed-off-by Thomas Gleixner <[email protected]>Cc Anna-Maria Behnsen <[email protected]>Cc Frederic Weisbecker <[email protected]>
Signature · 2 lines
Frederic Weisbecker SUSE Labs
[tip: timers/core] hrtimer: Use hrtimer_start_expires_user() for hrtimer sleepers
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: b40c927345a91e687eac4c3c5ca03a99643cd0c4 Gitweb: https://git.kernel.org/tip/b40c927345a91e687eac4c3c5ca03a99643cd0c4 Author: Thomas Gleixner <[email protected]> AuthorDate: Wed, 08 Apr 2026 13:53:52 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Fri, 01 May 2026 21:36:11 +02:00
hrtimer: Use hrtimer_start_expires_user() for hrtimer sleepers
Most hrtimer sleepers are user controlled and user space can hand arbitrary expiry values in as long as they are valid timespecs. If the expiry value is in the past then this requires a full loop through reprogramming the clock event device, taking the hrtimer interrupt, waking the task and reprogram again.
Use hrtimer_start_expires_user() which avoids the full round trip by checking the timer for expiry on enqueue.
--- kernel/time/hrtimer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
kernel/time/hrtimer.c +5 -1
@@ -2315,7 +2315,11 @@ void hrtimer_sleeper_start_expires(struct hrtimer_sleeper *sl, enum hrtimer_modeif (IS_ENABLED (CONFIG_PREEMPT_RT ) && sl->timer.is_hard) mode |=HRTIMER_MODE_HARD ; -hrtimer_start_expires (&sl->timer, mode); +/* If already expired, clear the task pointer and set current state to running */ +if (!hrtimer_start_expires_user (&sl->timer, mode)) { + sl->task =NULL ; +__set_current_state (TASK_RUNNING ); + } }EXPORT_SYMBOL_GPL (hrtimer_sleeper_start_expires);
Thomas Gleixner
maintainerPATCH v2 3/11 posix-timers: Expand timer_[re]arm() callbacks with a boolean return value
In reply to Thomas GleixnerIn order to catch expiry times which are already in the past the timer_arm() and timer_rearm() callbacks need to be able to report back to the caller whether the timer has been queued or not.
Change the function signature and let all implementations return true for now. While at it simplify posix_cpu_timer_rearm().
No functional change intended.
--- kernel/time/alarmtimer.c | 6 ++++-- kernel/time/posix-cpu-timers.c | 18 ++++++++++-------- kernel/time/posix-timers.c | 6 ++++-- kernel/time/posix-timers.h | 4 ++-- 4 files changed, 20 insertions(+), 14 deletions(-)
kernel/time/alarmtimer.c +4 -2
@@ -527,12 +527,13 @@ static void alarm_handle_timer(struct al* alarm_timer_rearm - Posix timer callback for rearming timer * @timr: Pointer to the posixtimer data struct */ -static void alarm_timer_rearm (struct k_itimer *timr) +static bool alarm_timer_rearm (struct k_itimer *timr) {struct alarm *alarm = &timr->it.alarm.alarmtimer; timr->it_overrun +=alarm_forward_now (alarm, timr->it_interval);alarm_start (alarm, alarm->node.expires); +return true; }/**
@@ -588,7 +589,7 @@ static void alarm_timer_wait_running(str* @absolute: Expiry value is absolute time * @sigev_none: Posix timer does not deliver signals */ -static void alarm_timer_arm (struct k_itimer *timr,ktime_t expires, +static bool alarm_timer_arm (struct k_itimer *timr,ktime_t expires,bool absolute,bool sigev_none) {struct alarm *alarm = &timr->it.alarm.alarmtimer;
@@ -600,6 +601,7 @@ static void alarm_timer_arm(struct k_iti alarm->node.expires = expires; else alarm_start(&timr->it.alarm.alarmtimer, expires); +return true; }/**
kernel/time/posix-cpu-timers.c +10 -8
@@ -19,7 +19,7 @@#include "posix-timers.h" -static void posix_cpu_timer_rearm (struct k_itimer *timer); +static bool posix_cpu_timer_rearm (struct k_itimer *timer);void posix_cputimers_group_init (struct posix_cputimers *pct,u64 cpu_limit) {
@@ -1011,24 +1011,27 @@ static void check_process_timers(struct/* * This is called from the signal code (via posixtimer_rearm) * when the last timer signal was delivered and we have to reload the timer. +* +* Return true unconditionally so the core code assumes the timer to be +* armed. Otherwise it would requeue the signal. */ -static void posix_cpu_timer_rearm (struct k_itimer *timer) +static bool posix_cpu_timer_rearm (struct k_itimer *timer) {clockid_t clkid =CPUCLOCK_WHICH (timer->it_clock); -struct task_struct *p;struct sighand_struct *sighand; +struct task_struct *p;unsigned long flags;u64 now; -rcu_read_lock (); +guard (rcu)(); p =cpu_timer_task_rcu (timer);if (!p) - goto out; +return true;/* Protect timer list r/w in arm_timer() */ sighand =lock_task_sighand (p, &flags);if (unlikely (sighand ==NULL )) - goto out; +return true;/* * Fetch the current sample and update the timer's expiry time.
@@ -1045,8 +1048,7 @@ static void posix_cpu_timer_rearm(struct*/ arm_timer (timer, p);unlock_task_sighand (p, &flags); -out: -rcu_read_unlock (); +return true; }/**
kernel/time/posix-timers.c +4 -2
@@ -288,12 +288,13 @@ static inline int timer_overrun_to_int(sreturn (int )timr->it_overrun_last; } -static void common_hrtimer_rearm (struct k_itimer *timr) +static bool common_hrtimer_rearm (struct k_itimer *timr) {struct hrtimer *timer = &timr->it.real.timer; timr->it_overrun +=hrtimer_forward_now (timer, timr->it_interval);hrtimer_restart (timer); +return true; }static bool __posixtimer_deliver_signal (struct kernel_siginfo *info,struct k_itimer *timr)
@@ -795,7 +796,7 @@ SYSCALL_DEFINE1(timer_getoverrun, timer_return timer_overrun_to_int (scoped_timer); } -static void common_hrtimer_arm (struct k_itimer *timr,ktime_t expires, +static bool common_hrtimer_arm (struct k_itimer *timr,ktime_t expires,bool absolute,bool sigev_none) {struct hrtimer *timer = &timr->it.real.timer;
@@ -822,6 +823,7 @@ static void common_hrtimer_arm(struct k_if (!sigev_none)hrtimer_start_expires (timer,HRTIMER_MODE_ABS ); +return true; }static int common_hrtimer_try_to_cancel (struct k_itimer *timr)
kernel/time/posix-timers.h +2 -2
@@ -27,11 +27,11 @@ struct k_clock {int (*timer_del)(struct k_itimer *timr);void (*timer_get)(struct k_itimer *timr,struct itimerspec64 *cur_setting); -void (*timer_rearm)(struct k_itimer *timr); +bool (*timer_rearm)(struct k_itimer *timr);s64 (*timer_forward)(struct k_itimer *timr,ktime_t now);ktime_t (*timer_remaining)(struct k_itimer *timr,ktime_t now);int (*timer_try_to_cancel)(struct k_itimer *timr); -void (*timer_arm)(struct k_itimer *timr,ktime_t expires, +bool (*timer_arm)(struct k_itimer *timr,ktime_t expires,bool absolute,bool sigev_none);void (*timer_wait_running)(struct k_itimer *timr); };
Re: [patch V2 03/11] posix-timers: Expand timer_[re]arm() callbacks with a boolean return value
Quoted 7 lines · Thomas Gleixner
In order to catch expiry times which are already in the past the
timer_arm()andtimer_rearm()callbacks need to be able to report back to the caller whether the timer has been queued or not.Change the function signature and let all implementations return true for now. While at it simplify
posix_cpu_timer_rearm().
Quoted 8 lines
No functional change intended.
Signed-off-by Thomas Gleixner <[email protected]>Acked-by John Stultz <[email protected]>Cc Stephen Boyd <[email protected]>Cc Anna-Maria Behnsen <[email protected]>Cc Frederic Weisbecker <[email protected]>
Signature · 2 lines
Frederic Weisbecker SUSE Labs
[tip: timers/core] posix-timers: Expand timer_[re]arm() callbacks with a boolean return value
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 6fdb2677a594ab38eade927919bbd4d9688bfa1c Gitweb: https://git.kernel.org/tip/6fdb2677a594ab38eade927919bbd4d9688bfa1c Author: Thomas Gleixner <[email protected]> AuthorDate: Wed, 08 Apr 2026 13:53:56 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Fri, 01 May 2026 21:36:11 +02:00
posix-timers: Expand timer_[re]arm() callbacks with a boolean return value
In order to catch expiry times which are already in the past the timer_arm() and timer_rearm() callbacks need to be able to report back to the caller whether the timer has been queued or not.
Change the function signature and let all implementations return true for now. While at it simplify posix_cpu_timer_rearm().
No functional change intended.
--- kernel/time/alarmtimer.c | 6 ++++-- kernel/time/posix-cpu-timers.c | 18 ++++++++++-------- kernel/time/posix-timers.c | 6 ++++-- kernel/time/posix-timers.h | 4 ++-- 4 files changed, 20 insertions(+), 14 deletions(-)
kernel/time/alarmtimer.c +4 -2
@@ -527,12 +527,13 @@ static void alarm_handle_timer(struct alarm *alarm, ktime_t now)* alarm_timer_rearm - Posix timer callback for rearming timer * @timr: Pointer to the posixtimer data struct */ -static void alarm_timer_rearm (struct k_itimer *timr) +static bool alarm_timer_rearm (struct k_itimer *timr) {struct alarm *alarm = &timr->it.alarm.alarmtimer; timr->it_overrun +=alarm_forward_now (alarm, timr->it_interval);alarm_start (alarm, alarm->node.expires); +return true; }/**
@@ -588,7 +589,7 @@ static void alarm_timer_wait_running(struct k_itimer *timr)* @absolute: Expiry value is absolute time * @sigev_none: Posix timer does not deliver signals */ -static void alarm_timer_arm (struct k_itimer *timr,ktime_t expires, +static bool alarm_timer_arm (struct k_itimer *timr,ktime_t expires,bool absolute,bool sigev_none) {struct alarm *alarm = &timr->it.alarm.alarmtimer;
@@ -600,6 +601,7 @@ static void alarm_timer_arm(struct k_itimer *timr, ktime_t expires, alarm->node.expires = expires; else alarm_start(&timr->it.alarm.alarmtimer, expires); +return true; }/**
kernel/time/posix-cpu-timers.c +10 -8
@@ -19,7 +19,7 @@#include "posix-timers.h" -static void posix_cpu_timer_rearm (struct k_itimer *timer); +static bool posix_cpu_timer_rearm (struct k_itimer *timer);void posix_cputimers_group_init (struct posix_cputimers *pct,u64 cpu_limit) {
@@ -1011,24 +1011,27 @@ static void check_process_timers(struct task_struct *tsk,/* * This is called from the signal code (via posixtimer_rearm) * when the last timer signal was delivered and we have to reload the timer. +* +* Return true unconditionally so the core code assumes the timer to be +* armed. Otherwise it would requeue the signal. */ -static void posix_cpu_timer_rearm (struct k_itimer *timer) +static bool posix_cpu_timer_rearm (struct k_itimer *timer) {clockid_t clkid =CPUCLOCK_WHICH (timer->it_clock); -struct task_struct *p;struct sighand_struct *sighand; +struct task_struct *p;unsigned long flags;u64 now; -rcu_read_lock (); +guard (rcu)(); p =cpu_timer_task_rcu (timer);if (!p) - goto out; +return true;/* Protect timer list r/w in arm_timer() */ sighand =lock_task_sighand (p, &flags);if (unlikely (sighand ==NULL )) - goto out; +return true;/* * Fetch the current sample and update the timer's expiry time.
@@ -1045,8 +1048,7 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)*/ arm_timer (timer, p);unlock_task_sighand (p, &flags); -out: -rcu_read_unlock (); +return true; }/**
kernel/time/posix-timers.c +4 -2
@@ -288,12 +288,13 @@ static inline int timer_overrun_to_int(struct k_itimer *timr)return (int )timr->it_overrun_last; } -static void common_hrtimer_rearm (struct k_itimer *timr) +static bool common_hrtimer_rearm (struct k_itimer *timr) {struct hrtimer *timer = &timr->it.real.timer; timr->it_overrun +=hrtimer_forward_now (timer, timr->it_interval);hrtimer_restart (timer); +return true; }static bool __posixtimer_deliver_signal (struct kernel_siginfo *info,struct k_itimer *timr)
@@ -795,7 +796,7 @@ SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id)return timer_overrun_to_int (scoped_timer); } -static void common_hrtimer_arm (struct k_itimer *timr,ktime_t expires, +static bool common_hrtimer_arm (struct k_itimer *timr,ktime_t expires,bool absolute,bool sigev_none) {struct hrtimer *timer = &timr->it.real.timer;
@@ -822,6 +823,7 @@ static void common_hrtimer_arm(struct k_itimer *timr, ktime_t expires,if (!sigev_none)hrtimer_start_expires (timer,HRTIMER_MODE_ABS ); +return true; }static int common_hrtimer_try_to_cancel (struct k_itimer *timr)
kernel/time/posix-timers.h +2 -2
@@ -27,11 +27,11 @@ struct k_clock {int (*timer_del)(struct k_itimer *timr);void (*timer_get)(struct k_itimer *timr,struct itimerspec64 *cur_setting); -void (*timer_rearm)(struct k_itimer *timr); +bool (*timer_rearm)(struct k_itimer *timr);s64 (*timer_forward)(struct k_itimer *timr,ktime_t now);ktime_t (*timer_remaining)(struct k_itimer *timr,ktime_t now);int (*timer_try_to_cancel)(struct k_itimer *timr); -void (*timer_arm)(struct k_itimer *timr,ktime_t expires, +bool (*timer_arm)(struct k_itimer *timr,ktime_t expires,bool absolute,bool sigev_none);void (*timer_wait_running)(struct k_itimer *timr); };
Thomas Gleixner
maintainerPATCH v2 4/11 posix-timers: Handle the timer_[re]arm() return value
In reply to Thomas GleixnerThe [re]arm callbacks will return true when the timer was queued and false if it was already expired at enqueue time.
In both cases the call sites can trivially queue the signal right there, when the timer was already expired. That avoids a full round trip through the hrtimer interrupt.
--- kernel/time/posix-timers.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
kernel/time/posix-timers.c +17 -5
@@ -299,6 +299,8 @@ static bool common_hrtimer_rearm(structstatic bool __posixtimer_deliver_signal (struct kernel_siginfo *info,struct k_itimer *timr) { +bool queued; +guard (spinlock)(&timr->it_lock);/*
@@ -312,12 +314,18 @@ static bool __posixtimer_deliver_signal(if (!timr->it_interval ||WARN_ON_ONCE (timr->it_status !=POSIX_TIMER_REQUEUE_PENDING ))return true; - timr->kclock->timer_rearm (timr); - timr->it_status =POSIX_TIMER_ARMED ; +/* timer_rearm() updates timr::it_overrun */ + queued = timr->kclock->timer_rearm (timr); + timr->it_overrun_last = timr->it_overrun; timr->it_overrun =-1LL ; ++timr->it_signal_seq; info->si_overrun =timer_overrun_to_int (timr); + +if (queued) + timr->it_status =POSIX_TIMER_ARMED ; +else +posix_timer_queue_signal (timr);return true; }
@@ -905,9 +913,13 @@ int common_timer_set(struct k_itimer *ti expires =timens_ktime_to_host (timr->it_clock, expires); sigev_none = timr->it_sigev_notify ==SIGEV_NONE ; - kc->timer_arm (timr, expires, flags &TIMER_ABSTIME , sigev_none); -if (!sigev_none) - timr->it_status =POSIX_TIMER_ARMED ; +if (kc->timer_arm (timr, expires, flags &TIMER_ABSTIME , sigev_none)) { +if (!sigev_none) + timr->it_status =POSIX_TIMER_ARMED ; + }else { +/* Timer was already expired, queue the signal */ +posix_timer_queue_signal (timr); + }return 0 ; }
Re: [patch V2 04/11] posix-timers: Handle the timer_[re]arm() return value
Quoted 11 lines · Thomas Gleixner
The [re]arm callbacks will return true when the timer was queued and false if it was already expired at enqueue time.
In both cases the call sites can trivially queue the signal right there, when the timer was already expired. That avoids a full round trip through the hrtimer interrupt.
Signed-off-by Thomas Gleixner <[email protected]>Cc Anna-Maria Behnsen <[email protected]>Cc Frederic Weisbecker <[email protected]>
Signature · 2 lines
Frederic Weisbecker SUSE Labs
[tip: timers/core] posix-timers: Handle the timer_[re]arm() return value
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: cfb7fe3fdd4ca1d37da1ed15a1897d4a27c47a8a Gitweb: https://git.kernel.org/tip/cfb7fe3fdd4ca1d37da1ed15a1897d4a27c47a8a Author: Thomas Gleixner <[email protected]> AuthorDate: Wed, 08 Apr 2026 13:54:01 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Fri, 01 May 2026 21:36:12 +02:00
posix-timers: Handle the timer_[re]arm() return value
The [re]arm callbacks will return true when the timer was queued and false if it was already expired at enqueue time.
In both cases the call sites can trivially queue the signal right there, when the timer was already expired. That avoids a full round trip through the hrtimer interrupt.
--- kernel/time/posix-timers.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
kernel/time/posix-timers.c +17 -5
@@ -299,6 +299,8 @@ static bool common_hrtimer_rearm(struct k_itimer *timr)static bool __posixtimer_deliver_signal (struct kernel_siginfo *info,struct k_itimer *timr) { +bool queued; +guard (spinlock)(&timr->it_lock);/*
@@ -312,12 +314,18 @@ static bool __posixtimer_deliver_signal(struct kernel_siginfo *info, struct k_itif (!timr->it_interval ||WARN_ON_ONCE (timr->it_status !=POSIX_TIMER_REQUEUE_PENDING ))return true; - timr->kclock->timer_rearm (timr); - timr->it_status =POSIX_TIMER_ARMED ; +/* timer_rearm() updates timr::it_overrun */ + queued = timr->kclock->timer_rearm (timr); + timr->it_overrun_last = timr->it_overrun; timr->it_overrun =-1LL ; ++timr->it_signal_seq; info->si_overrun =timer_overrun_to_int (timr); + +if (queued) + timr->it_status =POSIX_TIMER_ARMED ; +else +posix_timer_queue_signal (timr);return true; }
@@ -905,9 +913,13 @@ int common_timer_set(struct k_itimer *timr, int flags, expires =timens_ktime_to_host (timr->it_clock, expires); sigev_none = timr->it_sigev_notify ==SIGEV_NONE ; - kc->timer_arm (timr, expires, flags &TIMER_ABSTIME , sigev_none); -if (!sigev_none) - timr->it_status =POSIX_TIMER_ARMED ; +if (kc->timer_arm (timr, expires, flags &TIMER_ABSTIME , sigev_none)) { +if (!sigev_none) + timr->it_status =POSIX_TIMER_ARMED ; + }else { +/* Timer was already expired, queue the signal */ +posix_timer_queue_signal (timr); + }return 0 ; }
Thomas Gleixner
maintainerPATCH v2 5/11 posix-timers: Switch to hrtimer_start_expires_user()
In reply to Thomas GleixnerSwitch the arm and rearm callbacks for hrtimer based posix timers over to hrtimer_start_expires_user() so that already expired timers are not queued. Hand the result back to the caller, which then queues the signal.
--- kernel/time/posix-timers.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
kernel/time/posix-timers.c +6 -5
@@ -293,8 +293,7 @@ static bool common_hrtimer_rearm(structstruct hrtimer *timer = &timr->it.real.timer; timr->it_overrun +=hrtimer_forward_now (timer, timr->it_interval); -hrtimer_restart (timer); -return true; +return hrtimer_start_expires_user (timer,HRTIMER_MODE_ABS ); }static bool __posixtimer_deliver_signal (struct kernel_siginfo *info,struct k_itimer *timr)
@@ -829,9 +828,11 @@ static bool common_hrtimer_arm(struct k_ expires =ktime_add_safe (expires,hrtimer_cb_get_time (timer));hrtimer_set_expires (timer, expires); -if (!sigev_none) -hrtimer_start_expires (timer,HRTIMER_MODE_ABS ); -return true; +/* For sigev_none pretend that the timer is queued */ +if (sigev_none) +return true; + +return hrtimer_start_expires_user (timer,HRTIMER_MODE_ABS ); }static int common_hrtimer_try_to_cancel (struct k_itimer *timr)
Re: [patch V2 05/11] posix-timers: Switch to hrtimer_start_expires_user()
Quoted 8 lines · Thomas Gleixner
Switch the arm and rearm callbacks for hrtimer based posix timers over to
hrtimer_start_expires_user()so that already expired timers are not queued. Hand the result back to the caller, which then queues the signal.Signed-off-by Thomas Gleixner <[email protected]>Cc Anna-Maria Behnsen <[email protected]>Cc Frederic Weisbecker <[email protected]>
Signature · 2 lines
Frederic Weisbecker SUSE Labs
[tip: timers/core] posix-timers: Switch to hrtimer_start_expires_user()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: acc071343d29c2361619b05ad50ea3de9ef9a3ac Gitweb: https://git.kernel.org/tip/acc071343d29c2361619b05ad50ea3de9ef9a3ac Author: Thomas Gleixner <[email protected]> AuthorDate: Wed, 08 Apr 2026 13:54:06 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Fri, 01 May 2026 21:36:12 +02:00
posix-timers: Switch to hrtimer_start_expires_user()
Switch the arm and rearm callbacks for hrtimer based posix timers over to hrtimer_start_expires_user() so that already expired timers are not queued. Hand the result back to the caller, which then queues the signal.
--- kernel/time/posix-timers.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
kernel/time/posix-timers.c +6 -5
@@ -293,8 +293,7 @@ static bool common_hrtimer_rearm(struct k_itimer *timr)struct hrtimer *timer = &timr->it.real.timer; timr->it_overrun +=hrtimer_forward_now (timer, timr->it_interval); -hrtimer_restart (timer); -return true; +return hrtimer_start_expires_user (timer,HRTIMER_MODE_ABS ); }static bool __posixtimer_deliver_signal (struct kernel_siginfo *info,struct k_itimer *timr)
@@ -829,9 +828,11 @@ static bool common_hrtimer_arm(struct k_itimer *timr, ktime_t expires, expires =ktime_add_safe (expires,hrtimer_cb_get_time (timer));hrtimer_set_expires (timer, expires); -if (!sigev_none) -hrtimer_start_expires (timer,HRTIMER_MODE_ABS ); -return true; +/* For sigev_none pretend that the timer is queued */ +if (sigev_none) +return true; + +return hrtimer_start_expires_user (timer,HRTIMER_MODE_ABS ); }static int common_hrtimer_try_to_cancel (struct k_itimer *timr)
Thomas Gleixner
maintainerPATCH v2 6/11 alarmtimer: Provide alarm_start_timer()
In reply to Thomas GleixnerAlarm timers utilize hrtimers for normal operation and only switch to the RTC on suspend. In order to catch already expired timers early and without going through a timer interrupt cycle, provide a new start function which internally uses hrtimer_start_range_ns_user().
If hrtimer_start_range_ns_user() detects an already expired timer, it does not queue it. In that case remove the timer from the alarm base as well.
Return the status queued or not back to the caller to handle the early expiry.
---
V2: Rename to alarm_start_timer() - Peter
--- include/linux/alarmtimer.h | 6 ++++++ kernel/time/alarmtimer.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+)
include/linux/alarmtimer.h +6 -0
@@ -42,8 +42,14 @@ struct alarm {void *data; }; +static __always_inline ktime_t alarm_get_expires(struct alarm *alarm) +{ +return alarm->node.expires; +} +void alarm_init (struct alarm *alarm,enum alarmtimer_type type,void (*function)(struct alarm *,ktime_t )); +bool alarm_start_timer (struct alarm *alarm,ktime_t expires,bool relative);void alarm_start (struct alarm *alarm,ktime_t start);void alarm_start_relative (struct alarm *alarm,ktime_t start);void alarm_restart (struct alarm *alarm);
kernel/time/alarmtimer.c +28 -0
@@ -365,6 +365,34 @@ void alarm_start_relative(struct alarm * }EXPORT_SYMBOL_GPL (alarm_start_relative); +/** +* alarm_start_timer - Sets an alarm to fire +* @alarm: Pointer to alarm to set +* @expires: Expiry time +* @relative: True if @expires is relative +* +* Returns: True if the alarm was queued. False if it already expired +*/ +bool alarm_start_timer (struct alarm *alarm,ktime_t expires,bool relative) +{ +struct alarm_base *base = &alarm_bases[alarm->type]; + +if (relative) + expires =ktime_add_safe (expires, base->get_ktime ()); + +trace_alarmtimer_start (alarm, base->get_ktime ()); + +guard (spinlock_irqsave)(&base->lock); + alarm->node.expires = expires; +alarmtimer_enqueue (base, alarm); +if (!hrtimer_start_range_ns_user (&alarm->timer, expires,0 ,HRTIMER_MODE_ABS )) { +alarmtimer_dequeue (base, alarm); +return false; + } +return true; +} +EXPORT_SYMBOL_GPL (alarm_start_timer); +void alarm_restart (struct alarm *alarm) {struct alarm_base *base = &alarm_bases[alarm->type];
Re: [patch V2 06/11] alarmtimer: Provide alarm_start_timer()
Quoted 8 lines · Thomas Gleixner
Alarm timers utilize hrtimers for normal operation and only switch to the RTC on suspend. In order to catch already expired timers early and without going through a timer interrupt cycle, provide a new start function which internally uses
hrtimer_start_range_ns_user().If
hrtimer_start_range_ns_user()detects an already expired timer, it does not queue it. In that case remove the timer from the alarm base as well.
Quoted 6 lines
Return the status queued or not back to the caller to handle the early expiry.
Signed-off-by Thomas Gleixner <[email protected]>Acked-by John Stultz <[email protected]>Cc Stephen Boyd <[email protected]>
Signature · 2 lines
Frederic Weisbecker SUSE Labs
[tip: timers/core] alarmtimer: Provide alarm_start_timer()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 183d00b727139cf3b4be78d66a5602ce71a3acec Gitweb: https://git.kernel.org/tip/183d00b727139cf3b4be78d66a5602ce71a3acec Author: Thomas Gleixner <[email protected]> AuthorDate: Wed, 08 Apr 2026 13:54:11 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Fri, 01 May 2026 21:36:12 +02:00
alarmtimer: Provide alarm_start_timer()
Alarm timers utilize hrtimers for normal operation and only switch to the RTC on suspend. In order to catch already expired timers early and without going through a timer interrupt cycle, provide a new start function which internally uses hrtimer_start_range_ns_user().
If hrtimer_start_range_ns_user() detects an already expired timer, it does not queue it. In that case remove the timer from the alarm base as well.
Return the status queued or not back to the caller to handle the early expiry.
--- include/linux/alarmtimer.h | 6 ++++++ kernel/time/alarmtimer.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+)
include/linux/alarmtimer.h +6 -0
@@ -42,8 +42,14 @@ struct alarm {void *data; }; +static __always_inline ktime_t alarm_get_expires(struct alarm *alarm) +{ +return alarm->node.expires; +} +void alarm_init (struct alarm *alarm,enum alarmtimer_type type,void (*function)(struct alarm *,ktime_t )); +bool alarm_start_timer (struct alarm *alarm,ktime_t expires,bool relative);void alarm_start (struct alarm *alarm,ktime_t start);void alarm_start_relative (struct alarm *alarm,ktime_t start);void alarm_restart (struct alarm *alarm);
kernel/time/alarmtimer.c +28 -0
@@ -369,6 +369,34 @@ void alarm_start_relative(struct alarm *alarm, ktime_t start) }EXPORT_SYMBOL_GPL (alarm_start_relative); +/** +* alarm_start_timer - Sets an alarm to fire +* @alarm: Pointer to alarm to set +* @expires: Expiry time +* @relative: True if @expires is relative +* +* Returns: True if the alarm was queued. False if it already expired +*/ +bool alarm_start_timer (struct alarm *alarm,ktime_t expires,bool relative) +{ +struct alarm_base *base = &alarm_bases[alarm->type]; + +if (relative) + expires =ktime_add_safe (expires, base->get_ktime ()); + +trace_alarmtimer_start (alarm, base->get_ktime ()); + +guard (spinlock_irqsave)(&base->lock); + alarm->node.expires = expires; +alarmtimer_enqueue (base, alarm); +if (!hrtimer_start_range_ns_user (&alarm->timer, expires,0 ,HRTIMER_MODE_ABS )) { +alarmtimer_dequeue (base, alarm); +return false; + } +return true; +} +EXPORT_SYMBOL_GPL (alarm_start_timer); +void alarm_restart (struct alarm *alarm) {struct alarm_base *base = &alarm_bases[alarm->type];
Thomas Gleixner
maintainerPATCH v2 7/11 alarmtimer: Convert posix timer functions to alarm_start_timer()
In reply to Thomas GleixnerUse the new alarm_start_timer() for arming and rearming posix interval timers and for clock_nanosleep() so that already expired timers do not go through the full timer interrupt cycle.
---
V2: Rename to alarm_start_timer()
--- kernel/time/alarmtimer.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
kernel/time/alarmtimer.c +13 -7
@@ -560,8 +560,7 @@ static bool alarm_timer_rearm(struct k_istruct alarm *alarm = &timr->it.alarm.alarmtimer; timr->it_overrun +=alarm_forward_now (alarm, timr->it_interval); -alarm_start (alarm, alarm->node.expires); -return true; +return alarm_start_timer (alarm, alarm->node.expires, false); }/**
@@ -625,11 +624,16 @@ static bool alarm_timer_arm(struct k_itiif (!absolute) expires =ktime_add_safe (expires, base->get_ktime ()); -if (sigev_none) + +/* +* sigev_none needs to update the expires value and pretend +* that the timer is queued +*/ +if (sigev_none) { alarm->node.expires = expires; -else -alarm_start (&timr->it.alarm.alarmtimer, expires); -return true; +return true; + } +return alarm_start_timer (&timr->it.alarm.alarmtimer, expires, false); }/**
@@ -736,7 +740,9 @@ static int alarmtimer_do_nsleep(struct a alarm->data = (void *)current; do { set_current_state(TASK_INTERRUPTIBLE); - alarm_start(alarm, absexp); + if (!alarm_start_timer(alarm, absexp, false)) + alarm->data = NULL; + if (likely(alarm->data)) schedule();
Re: [patch V2 07/11] alarmtimer: Convert posix timer functions to alarm_start_timer()
Quoted 7 lines · Thomas Gleixner
Use the new
alarm_start_timer()for arming and rearming posix interval timers and forclock_nanosleep()so that already expired timers do not go through the full timer interrupt cycle.Signed-off-by Thomas Gleixner <[email protected]>Acked-by John Stultz <[email protected]>Cc Stephen Boyd <[email protected]>
Signature · 2 lines
Frederic Weisbecker SUSE Labs
[tip: timers/core] alarmtimer: Convert posix timer functions to alarm_start_timer()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: f4b58f61da79032b03d25f8f1a5a697db84a46f3 Gitweb: https://git.kernel.org/tip/f4b58f61da79032b03d25f8f1a5a697db84a46f3 Author: Thomas Gleixner <[email protected]> AuthorDate: Wed, 08 Apr 2026 13:54:16 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Fri, 01 May 2026 21:36:13 +02:00
alarmtimer: Convert posix timer functions to alarm_start_timer()
Use the new alarm_start_timer() for arming and rearming posix interval timers and for clock_nanosleep() so that already expired timers do not go through the full timer interrupt cycle.
--- kernel/time/alarmtimer.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
kernel/time/alarmtimer.c +13 -7
@@ -560,8 +560,7 @@ static bool alarm_timer_rearm(struct k_itimer *timr)struct alarm *alarm = &timr->it.alarm.alarmtimer; timr->it_overrun +=alarm_forward_now (alarm, timr->it_interval); -alarm_start (alarm, alarm->node.expires); -return true; +return alarm_start_timer (alarm, alarm->node.expires, false); }/**
@@ -625,11 +624,16 @@ static bool alarm_timer_arm(struct k_itimer *timr, ktime_t expires,if (!absolute) expires =ktime_add_safe (expires, base->get_ktime ()); -if (sigev_none) + +/* +* sigev_none needs to update the expires value and pretend +* that the timer is queued +*/ +if (sigev_none) { alarm->node.expires = expires; -else -alarm_start (&timr->it.alarm.alarmtimer, expires); -return true; +return true; + } +return alarm_start_timer (&timr->it.alarm.alarmtimer, expires, false); }/**
@@ -736,7 +740,9 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp, alarm->data = (void *)current; do { set_current_state(TASK_INTERRUPTIBLE); - alarm_start(alarm, absexp); + if (!alarm_start_timer(alarm, absexp, false)) + alarm->data = NULL; + if (likely(alarm->data)) schedule();
Thomas Gleixner
maintainerPATCH v2 8/11 fs/timerfd: Use the new alarm/hrtimer functions
In reply to Thomas GleixnerLike any other user controlled interface, timerfd based timers can be programmed with expiry times in the past or vary small intervals.
Both hrtimer and alarmtimer provide new interfaces which return the queued state of the timer. If the timer was already expired, then let the callsite handle the timerfd context update so that the full round trip through the hrtimer interrupt is avoided.
---
V2: Rename to alarm_timer_start() and add a comment explaining the -1 in
the tick accounting. - Peter
--- fs/timerfd.c | 117 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 68 insertions(+), 49 deletions(-)
fs/timerfd.c +68 -49
@@ -55,6 +55,15 @@ static inline bool isalarm(struct timerf ctx->clockid ==CLOCK_BOOTTIME_ALARM ; } +static void __timerfd_triggered (struct timerfd_ctx *ctx) +{ +lockdep_assert_held (&ctx->wqh.lock); + + ctx->expired =1 ; + ctx->ticks++; +wake_up_locked_poll (&ctx->wqh,EPOLLIN ); +} +/* * This gets called when the timer event triggers. We set the "expired" * flag, but we do not re-arm the timer (in case it's necessary,
@@ -62,13 +71,8 @@ static inline bool isalarm(struct timerf*/ static void timerfd_triggered (struct timerfd_ctx *ctx) { -unsigned long flags; - -spin_lock_irqsave (&ctx->wqh.lock, flags); - ctx->expired =1 ; - ctx->ticks++; -wake_up_locked_poll (&ctx->wqh,EPOLLIN ); -spin_unlock_irqrestore (&ctx->wqh.lock, flags); +guard (spinlock_irqsave)(&ctx->wqh.lock); +__timerfd_triggered (ctx); }static enum hrtimer_restart timerfd_tmrproc (struct hrtimer *htmr)
@@ -184,15 +188,54 @@ static ktime_t timerfd_get_remaining(strreturn remaining <0 ?0 : remaining; } +static void timerfd_alarm_start (struct timerfd_ctx *ctx,ktime_t exp,bool relative) +{ +/* Start the timer. If it's expired already, handle the callback. */ +if (!alarm_start_timer (&ctx->t.alarm, exp, relative)) +__timerfd_triggered (ctx); +} + +static u64 timerfd_alarm_restart (struct timerfd_ctx *ctx) +{ +/* -1 to account for ctx->ticks++ in __timerfd_triggered() */ +u64 ticks =alarm_forward_now (&ctx->t.alarm, ctx->tintv) -1 ; + +timerfd_alarm_start (ctx,alarm_get_expires (&ctx->t.alarm), false); +return ticks; +} + +static void timerfd_hrtimer_start (struct timerfd_ctx *ctx,ktime_t exp, +const enum hrtimer_mode mode) +{ +/* Start the timer. If it's expired already, handle the callback. */ +if (!hrtimer_start_range_ns_user (&ctx->t.tmr, exp,0 , mode)) +__timerfd_triggered (ctx); +} + +static u64 timerfd_hrtimer_restart (struct timerfd_ctx *ctx) +{ +/* -1 to account for ctx->ticks++ in __timerfd_triggered() */ +u64 ticks =hrtimer_forward_now (&ctx->t.tmr, ctx->tintv) -1 ; + +timerfd_hrtimer_start (ctx,hrtimer_get_expires (&ctx->t.tmr),HRTIMER_MODE_ABS ); +return ticks; +} + +static u64 timerfd_restart (struct timerfd_ctx *ctx) +{ +if (isalarm (ctx)) +return timerfd_alarm_restart (ctx); +return timerfd_hrtimer_restart (ctx); +} +static int timerfd_setup (struct timerfd_ctx *ctx,int flags,const struct itimerspec64 *ktmr) { +int clockid = ctx->clockid;enum hrtimer_mode htmode;ktime_t texp; -int clockid = ctx->clockid; - htmode = (flags &TFD_TIMER_ABSTIME ) ? -HRTIMER_MODE_ABS :HRTIMER_MODE_REL ; + htmode = (flags &TFD_TIMER_ABSTIME ) ?HRTIMER_MODE_ABS :HRTIMER_MODE_REL ; texp =timespec64_to_ktime (ktmr->it_value); ctx->expired =0 ;
@@ -206,20 +249,15 @@ static int timerfd_setup(struct timerfd_ timerfd_alarmproc); }else {hrtimer_setup (&ctx->t.tmr, timerfd_tmrproc, clockid, htmode); -hrtimer_set_expires (&ctx->t.tmr, texp); }if (texp !=0 ) {if (flags &TFD_TIMER_ABSTIME ) texp =timens_ktime_to_host (clockid, texp); -if (isalarm (ctx)) { -if (flags &TFD_TIMER_ABSTIME ) -alarm_start (&ctx->t.alarm, texp); -else -alarm_start_relative (&ctx->t.alarm, texp); - }else { -hrtimer_start (&ctx->t.tmr, texp, htmode); - } +if (isalarm (ctx)) +timerfd_alarm_start (ctx, texp, !(flags &TFD_TIMER_ABSTIME )); +else +timerfd_hrtimer_start (ctx, texp, htmode);if (timerfd_canceled (ctx))return -ECANCELED ;
@@ -287,27 +325,19 @@ static ssize_t timerfd_read_iter(struct }if (ctx->ticks) { - ticks = ctx->ticks; +unsigned int expired = ctx->expired; -if (ctx->expired && ctx->tintv) { -/* -* If tintv != 0, this is a periodic timer that -* needs to be re-armed. We avoid doing it in the timer -* callback to avoid DoS attacks specifying a very -* short timer period. -*/ -if (isalarm (ctx)) { - ticks +=alarm_forward_now ( - &ctx->t.alarm, ctx->tintv) -1 ; -alarm_restart (&ctx->t.alarm); - }else { - ticks +=hrtimer_forward_now (&ctx->t.tmr, - ctx->tintv) -1 ; -hrtimer_restart (&ctx->t.tmr); - } - } + ticks = ctx->ticks; ctx->expired =0 ; ctx->ticks =0 ; + +/* +* If tintv != 0, this is a periodic timer that needs to be +* re-armed. We avoid doing it in the timer callback to avoid +* DoS attacks specifying a very short timer period. +*/ +if (expired && ctx->tintv) + ticks +=timerfd_restart (ctx); }spin_unlock_irq (&ctx->wqh.lock);if (ticks) {
@@ -526,18 +556,7 @@ static int do_timerfd_gettime(int ufd, sspin_lock_irq (&ctx->wqh.lock);if (ctx->expired && ctx->tintv) { ctx->expired =0 ; - -if (isalarm (ctx)) { - ctx->ticks += -alarm_forward_now ( - &ctx->t.alarm, ctx->tintv) -1 ; -alarm_restart (&ctx->t.alarm); - }else { - ctx->ticks += -hrtimer_forward_now (&ctx->t.tmr, ctx->tintv) - -1 ; -hrtimer_restart (&ctx->t.tmr); - } + ctx->ticks +=timerfd_restart (ctx); } t->it_value =ktime_to_timespec64 (timerfd_get_remaining (ctx)); t->it_interval =ktime_to_timespec64 (ctx->tintv);
Re: [patch V2 08/11] fs/timerfd: Use the new alarm/hrtimer functions
Quoted 8 lines · Thomas Gleixner
Like any other user controlled interface, timerfd based timers can be programmed with expiry times in the past or vary small intervals.
Both hrtimer and alarmtimer provide new interfaces which return the queued state of the timer. If the timer was already expired, then let the callsite handle the timerfd context update so that the full round trip through the hrtimer interrupt is avoided.
Quoted 7 lines
Signed-off-by Thomas Gleixner <[email protected]>Cc Alexander Viro <[email protected]>Cc Christian Brauner <[email protected]>Cc Jan Kara <[email protected]>Cc Anna-Maria Behnsen <[email protected]>Cc Frederic Weisbecker <[email protected]>
Signature · 2 lines
Frederic Weisbecker SUSE Labs
[tip: timers/core] fs/timerfd: Use the new alarm/hrtimer functions
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 7dda99952cede01e1225f8c4c856369a2cfda6ca Gitweb: https://git.kernel.org/tip/7dda99952cede01e1225f8c4c856369a2cfda6ca Author: Thomas Gleixner <[email protected]> AuthorDate: Wed, 08 Apr 2026 13:54:20 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Fri, 01 May 2026 21:36:13 +02:00
fs/timerfd: Use the new alarm/hrtimer functions
Like any other user controlled interface, timerfd based timers can be programmed with expiry times in the past or vary small intervals.
Both hrtimer and alarmtimer provide new interfaces which return the queued state of the timer. If the timer was already expired, then let the callsite handle the timerfd context update so that the full round trip through the hrtimer interrupt is avoided.
--- fs/timerfd.c | 117 +++++++++++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 49 deletions(-)
fs/timerfd.c +68 -49
@@ -55,6 +55,15 @@ static inline bool isalarm(struct timerfd_ctx *ctx) ctx->clockid ==CLOCK_BOOTTIME_ALARM ; } +static void __timerfd_triggered (struct timerfd_ctx *ctx) +{ +lockdep_assert_held (&ctx->wqh.lock); + + ctx->expired =1 ; + ctx->ticks++; +wake_up_locked_poll (&ctx->wqh,EPOLLIN ); +} +/* * This gets called when the timer event triggers. We set the "expired" * flag, but we do not re-arm the timer (in case it's necessary,
@@ -62,13 +71,8 @@ static inline bool isalarm(struct timerfd_ctx *ctx)*/ static void timerfd_triggered (struct timerfd_ctx *ctx) { -unsigned long flags; - -spin_lock_irqsave (&ctx->wqh.lock, flags); - ctx->expired =1 ; - ctx->ticks++; -wake_up_locked_poll (&ctx->wqh,EPOLLIN ); -spin_unlock_irqrestore (&ctx->wqh.lock, flags); +guard (spinlock_irqsave)(&ctx->wqh.lock); +__timerfd_triggered (ctx); }static enum hrtimer_restart timerfd_tmrproc (struct hrtimer *htmr)
@@ -184,15 +188,54 @@ static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)return remaining <0 ?0 : remaining; } +static void timerfd_alarm_start (struct timerfd_ctx *ctx,ktime_t exp,bool relative) +{ +/* Start the timer. If it's expired already, handle the callback. */ +if (!alarm_start_timer (&ctx->t.alarm, exp, relative)) +__timerfd_triggered (ctx); +} + +static u64 timerfd_alarm_restart (struct timerfd_ctx *ctx) +{ +/* -1 to account for ctx->ticks++ in __timerfd_triggered() */ +u64 ticks =alarm_forward_now (&ctx->t.alarm, ctx->tintv) -1 ; + +timerfd_alarm_start (ctx,alarm_get_expires (&ctx->t.alarm), false); +return ticks; +} + +static void timerfd_hrtimer_start (struct timerfd_ctx *ctx,ktime_t exp, +const enum hrtimer_mode mode) +{ +/* Start the timer. If it's expired already, handle the callback. */ +if (!hrtimer_start_range_ns_user (&ctx->t.tmr, exp,0 , mode)) +__timerfd_triggered (ctx); +} + +static u64 timerfd_hrtimer_restart (struct timerfd_ctx *ctx) +{ +/* -1 to account for ctx->ticks++ in __timerfd_triggered() */ +u64 ticks =hrtimer_forward_now (&ctx->t.tmr, ctx->tintv) -1 ; + +timerfd_hrtimer_start (ctx,hrtimer_get_expires (&ctx->t.tmr),HRTIMER_MODE_ABS ); +return ticks; +} + +static u64 timerfd_restart (struct timerfd_ctx *ctx) +{ +if (isalarm (ctx)) +return timerfd_alarm_restart (ctx); +return timerfd_hrtimer_restart (ctx); +} +static int timerfd_setup (struct timerfd_ctx *ctx,int flags,const struct itimerspec64 *ktmr) { +int clockid = ctx->clockid;enum hrtimer_mode htmode;ktime_t texp; -int clockid = ctx->clockid; - htmode = (flags &TFD_TIMER_ABSTIME ) ? -HRTIMER_MODE_ABS :HRTIMER_MODE_REL ; + htmode = (flags &TFD_TIMER_ABSTIME ) ?HRTIMER_MODE_ABS :HRTIMER_MODE_REL ; texp =timespec64_to_ktime (ktmr->it_value); ctx->expired =0 ;
@@ -206,20 +249,15 @@ static int timerfd_setup(struct timerfd_ctx *ctx, int flags, timerfd_alarmproc); }else {hrtimer_setup (&ctx->t.tmr, timerfd_tmrproc, clockid, htmode); -hrtimer_set_expires (&ctx->t.tmr, texp); }if (texp !=0 ) {if (flags &TFD_TIMER_ABSTIME ) texp =timens_ktime_to_host (clockid, texp); -if (isalarm (ctx)) { -if (flags &TFD_TIMER_ABSTIME ) -alarm_start (&ctx->t.alarm, texp); -else -alarm_start_relative (&ctx->t.alarm, texp); - }else { -hrtimer_start (&ctx->t.tmr, texp, htmode); - } +if (isalarm (ctx)) +timerfd_alarm_start (ctx, texp, !(flags &TFD_TIMER_ABSTIME )); +else +timerfd_hrtimer_start (ctx, texp, htmode);if (timerfd_canceled (ctx))return -ECANCELED ;
@@ -287,27 +325,19 @@ static ssize_t timerfd_read_iter(struct kiocb *iocb, struct iov_iter *to) }if (ctx->ticks) { - ticks = ctx->ticks; +unsigned int expired = ctx->expired; -if (ctx->expired && ctx->tintv) { -/* -* If tintv != 0, this is a periodic timer that -* needs to be re-armed. We avoid doing it in the timer -* callback to avoid DoS attacks specifying a very -* short timer period. -*/ -if (isalarm (ctx)) { - ticks +=alarm_forward_now ( - &ctx->t.alarm, ctx->tintv) -1 ; -alarm_restart (&ctx->t.alarm); - }else { - ticks +=hrtimer_forward_now (&ctx->t.tmr, - ctx->tintv) -1 ; -hrtimer_restart (&ctx->t.tmr); - } - } + ticks = ctx->ticks; ctx->expired =0 ; ctx->ticks =0 ; + +/* +* If tintv != 0, this is a periodic timer that needs to be +* re-armed. We avoid doing it in the timer callback to avoid +* DoS attacks specifying a very short timer period. +*/ +if (expired && ctx->tintv) + ticks +=timerfd_restart (ctx); }spin_unlock_irq (&ctx->wqh.lock);if (ticks) {
@@ -526,18 +556,7 @@ static int do_timerfd_gettime(int ufd, struct itimerspec64 *t)spin_lock_irq (&ctx->wqh.lock);if (ctx->expired && ctx->tintv) { ctx->expired =0 ; - -if (isalarm (ctx)) { - ctx->ticks += -alarm_forward_now ( - &ctx->t.alarm, ctx->tintv) -1 ; -alarm_restart (&ctx->t.alarm); - }else { - ctx->ticks += -hrtimer_forward_now (&ctx->t.tmr, ctx->tintv) - -1 ; -hrtimer_restart (&ctx->t.tmr); - } + ctx->ticks +=timerfd_restart (ctx); } t->it_value =ktime_to_timespec64 (timerfd_get_remaining (ctx)); t->it_interval =ktime_to_timespec64 (ctx->tintv);
Thomas Gleixner
maintainerPATCH v2 9/11 power: supply: charger-manager: Switch to alarm_start_timer()
In reply to Thomas GleixnerThe existing alarm_start() interface is replaced with the new alarm_start_timer() mechanism, which does not longer queue an already expired timer and returns the state. Adjust the code to utilize this.
No functional change intended.
---
V2: Rename to alarm_start_timer()
--- drivers/power/supply/charger-manager.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/power/supply/charger-manager.c +7 -5
@@ -881,7 +881,7 @@ static bool cm_setup_timer(void)mutex_unlock (&cm_list_mtx);if (timer_req && cm_timer) { -ktime_t now, add; +ktime_t exp;/* * Set alarm with the polling interval (wakeup_ms)
@@ -893,14 +893,16 @@ static bool cm_setup_timer(void)pr_info ("Charger Manager wakeup timer: %u ms\n" , wakeup_ms); - now =ktime_get_boottime (); - add =ktime_set (wakeup_ms /MSEC_PER_SEC , + exp =ktime_set (wakeup_ms /MSEC_PER_SEC , (wakeup_ms %MSEC_PER_SEC ) *NSEC_PER_MSEC ); -alarm_start (cm_timer,ktime_add (now, add)); cm_suspend_duration_ms = wakeup_ms; -return true; +/* +* The timer should always be queued as the timeout is at least +* two seconds out. Handle it correctly nevertheless. +*/ +return alarm_start_timer (cm_timer, exp, true); }return false; }
Re: [patch V2 09/11] power: supply: charger-manager: Switch to alarm_start_timer()
Hi,
Quoted 4 lines · Thomas Gleixner
The existing
alarm_start()interface is replaced with the newalarm_start_timer()mechanism, which does not longer queue an already expired timer and returns the state. Adjust the code to utilize this.
Quoted 8 lines
No functional change intended.
Signed-off-by Thomas Gleixner <[email protected]>Cc Sebastian Reichel <[email protected]>---
V2: Rename toalarm_start_timer()
---
Greetings,
-- Sebastian
Quoted 35 lines
drivers/power/supply/charger-manager.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)drivers/power/supply/charger-manager.c +7
-5@@ -881,7 +881,7 @@ static bool cm_setup_timer(void)mutex_unlock (&cm_list_mtx);if (timer_req && cm_timer) { -ktime_t now, add; +ktime_t exp;/* * Set alarm with the polling interval (wakeup_ms) @@ -893,14 +893,16 @@ static bool cm_setup_timer(void)pr_info ("Charger Manager wakeup timer: %u ms\n" , wakeup_ms); - now =ktime_get_boottime (); - add =ktime_set (wakeup_ms /MSEC_PER_SEC , + exp =ktime_set (wakeup_ms /MSEC_PER_SEC , (wakeup_ms %MSEC_PER_SEC ) *NSEC_PER_MSEC ); -alarm_start (cm_timer,ktime_add (now, add)); cm_suspend_duration_ms = wakeup_ms; -return true; +/* +* The timer should always be queued as the timeout is at least +* two seconds out. Handle it correctly nevertheless. +*/ +return alarm_start_timer (cm_timer, exp, true); }return false; }
[tip: timers/core] power: supply: charger-manager: Switch to alarm_start_timer()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 9fa2e38ab749f3966d9141da3c2cb6ce3a9a8e35 Gitweb: https://git.kernel.org/tip/9fa2e38ab749f3966d9141da3c2cb6ce3a9a8e35 Author: Thomas Gleixner <[email protected]> AuthorDate: Wed, 08 Apr 2026 13:54:24 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Fri, 01 May 2026 21:36:13 +02:00
power: supply: charger-manager: Switch to alarm_start_timer()
The existing alarm_start() interface is replaced with the new alarm_start_timer() mechanism, which does not longer queue an already expired timer and returns the state. Adjust the code to utilize this.
No functional change intended.
--- drivers/power/supply/charger-manager.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-)
drivers/power/supply/charger-manager.c +6 -10
@@ -881,26 +881,22 @@ static bool cm_setup_timer(void)mutex_unlock (&cm_list_mtx);if (timer_req && cm_timer) { -ktime_t now, add; -/* * Set alarm with the polling interval (wakeup_ms) * The alarm time should be NOW + CM_RTC_SMALL or later. */ -if (wakeup_ms ==UINT_MAX || - wakeup_ms <CM_RTC_SMALL *MSEC_PER_SEC ) +if (wakeup_ms ==UINT_MAX || wakeup_ms <CM_RTC_SMALL *MSEC_PER_SEC ) wakeup_ms =2 *CM_RTC_SMALL *MSEC_PER_SEC ;pr_info ("Charger Manager wakeup timer: %u ms\n" , wakeup_ms); - now =ktime_get_boottime (); - add =ktime_set (wakeup_ms /MSEC_PER_SEC , - (wakeup_ms %MSEC_PER_SEC ) *NSEC_PER_MSEC ); -alarm_start (cm_timer,ktime_add (now, add)); - cm_suspend_duration_ms = wakeup_ms; -return true; +/* +* The timer should always be queued as the timeout is at least +* two seconds out. Handle it correctly nevertheless. +*/ +return alarm_start_timer (cm_timer,ktime_add_ms (0 , wakeup_ms), true); }return false; }
Thomas Gleixner
maintainerPATCH v2 10/11 netfilter: xt_IDLETIMER: Switch to alarm_start_timer()
In reply to Thomas GleixnerThe existing alarm_start() interface is replaced with the new alarm_start_timer() mechanism, which does not longer queue an already expired timer and returns the state.
Adjust the code to utilize this so it schedules the work in the case that the timer was already expired. Unlikely to happen as the timeout is at least a second, but not impossible especially with virtualization.
No functional change intended
--- net/netfilter/xt_IDLETIMER.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-)
net/netfilter/xt_IDLETIMER.c +18 -6
@@ -115,6 +115,21 @@ static void idletimer_tg_alarmproc(strucschedule_work (&timer->work); } +static void idletimer_start_alarm_ktime (struct idletimer_tg *timer,ktime_t timeout) +{ +/* +* The timer should always be queued as @tout it should be least one +* second, but handle it correctly in any case. Virt will manage! +*/ +if (!alarm_start_timer (&timer->alarm, timeout, true)) +schedule_work (&timer->work); +} + +static void idletimer_start_alarm_sec (struct idletimer_tg *timer,unsigned int seconds) +{ +idletimer_start_alarm_ktime (timer,ktime_set (seconds,0 )); +} +static int idletimer_check_sysfs_name (const char *name,unsigned int size) {int ret;
@@ -220,12 +235,10 @@ static int idletimer_tg_create_v1(structINIT_WORK (&info->timer->work, idletimer_tg_work);if (info->timer->timer_type &XT_IDLETIMER_ALARM ) { -ktime_t tout;alarm_init (&info->timer->alarm,ALARM_BOOTTIME , idletimer_tg_alarmproc); info->timer->alarm.data = info->timer; - tout =ktime_set (info->timeout,0 ); -alarm_start_relative (&info->timer->alarm, tout); +idletimer_start_alarm_sec (info->timer, info->timeout); }else {timer_setup (&info->timer->timer, idletimer_tg_expired,0 ); mod_timer(&info->timer->timer,
@@ -271,8 +284,7 @@ static unsigned int idletimer_tg_target_ info->label, info->timeout);if (info->timer->timer_type &XT_IDLETIMER_ALARM ) { -ktime_t tout =ktime_set (info->timeout,0 ); -alarm_start_relative (&info->timer->alarm, tout); +idletimer_start_alarm_sec (info->timer, info->timeout); }else {mod_timer (&info->timer->timer,secs_to_jiffies (info->timeout) + jiffies);
@@ -378,7 +390,7 @@ static int idletimer_tg_checkentry_v1(coif (ktimespec.tv_sec >0 ) {pr_debug ("time_expiry_remaining %lld\n" , ktimespec.tv_sec); -alarm_start_relative (&info->timer->alarm, tout); +idletimer_start_alarm_ktime (info->timer, tout); } }else { mod_timer(&info->timer->timer,
[tip: timers/core] netfilter: xt_IDLETIMER: Switch to alarm_start_timer()
The following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 12e4311aa5b2dda3cb59e42b3f518e1c57fb1469 Gitweb: https://git.kernel.org/tip/12e4311aa5b2dda3cb59e42b3f518e1c57fb1469 Author: Thomas Gleixner <[email protected]> AuthorDate: Wed, 08 Apr 2026 13:54:29 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Fri, 01 May 2026 21:36:14 +02:00
netfilter: xt_IDLETIMER: Switch to alarm_start_timer()
The existing alarm_start() interface is replaced with the new alarm_start_timer() mechanism, which does not longer queue an already expired timer and returns the state.
Adjust the code to utilize this so it schedules the work in the case that the timer was already expired. Unlikely to happen as the timeout is at least a second, but not impossible especially with virtualization.
No functional change intended
--- net/netfilter/xt_IDLETIMER.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-)
net/netfilter/xt_IDLETIMER.c +18 -6
@@ -115,6 +115,21 @@ static void idletimer_tg_alarmproc(struct alarm *alarm, ktime_t now)schedule_work (&timer->work); } +static void idletimer_start_alarm_ktime (struct idletimer_tg *timer,ktime_t timeout) +{ +/* +* The timer should always be queued as @tout it should be least one +* second, but handle it correctly in any case. Virt will manage! +*/ +if (!alarm_start_timer (&timer->alarm, timeout, true)) +schedule_work (&timer->work); +} + +static void idletimer_start_alarm_sec (struct idletimer_tg *timer,unsigned int seconds) +{ +idletimer_start_alarm_ktime (timer,ktime_set (seconds,0 )); +} +static int idletimer_check_sysfs_name (const char *name,unsigned int size) {int ret;
@@ -220,12 +235,10 @@ static int idletimer_tg_create_v1(struct idletimer_tg_info_v1 *info)INIT_WORK (&info->timer->work, idletimer_tg_work);if (info->timer->timer_type &XT_IDLETIMER_ALARM ) { -ktime_t tout;alarm_init (&info->timer->alarm,ALARM_BOOTTIME , idletimer_tg_alarmproc); info->timer->alarm.data = info->timer; - tout =ktime_set (info->timeout,0 ); -alarm_start_relative (&info->timer->alarm, tout); +idletimer_start_alarm_sec (info->timer, info->timeout); }else {timer_setup (&info->timer->timer, idletimer_tg_expired,0 ); mod_timer(&info->timer->timer,
@@ -271,8 +284,7 @@ static unsigned int idletimer_tg_target_v1(struct sk_buff *skb, info->label, info->timeout);if (info->timer->timer_type &XT_IDLETIMER_ALARM ) { -ktime_t tout =ktime_set (info->timeout,0 ); -alarm_start_relative (&info->timer->alarm, tout); +idletimer_start_alarm_sec (info->timer, info->timeout); }else {mod_timer (&info->timer->timer,secs_to_jiffies (info->timeout) + jiffies);
@@ -384,7 +396,7 @@ static int idletimer_tg_checkentry_v1(const struct xt_tgchk_param *par)if (ktimespec.tv_sec >0 ) {pr_debug ("time_expiry_remaining %lld\n" , ktimespec.tv_sec); -alarm_start_relative (&info->timer->alarm, tout); +idletimer_start_alarm_ktime (info->timer, tout); } }else { mod_timer(&info->timer->timer,
Thomas Gleixner
maintainerPATCH v2 11/11 alarmtimer: Remove unused interfaces
In reply to Thomas GleixnerAll alarmtimer users are converted to alarm_start_timer(). Remove the now unused interfaces.
--- include/linux/alarmtimer.h | 3 --- kernel/time/alarmtimer.c | 44 -------------------------------------------- 2 files changed, 47 deletions(-)
include/linux/alarmtimer.h +0 -3
@@ -50,9 +50,6 @@ static __always_inline ktime_t alarm_getvoid alarm_init (struct alarm *alarm,enum alarmtimer_type type,void (*function)(struct alarm *,ktime_t ));bool alarm_start_timer (struct alarm *alarm,ktime_t expires,bool relative); -void alarm_start (struct alarm *alarm,ktime_t start); -void alarm_start_relative (struct alarm *alarm,ktime_t start); -void alarm_restart (struct alarm *alarm);int alarm_try_to_cancel (struct alarm *alarm);int alarm_cancel (struct alarm *alarm);
kernel/time/alarmtimer.c +0 -44
56 lines not on this page · raw message
Re: [patch V2 11/11] alarmtimer: Remove unused interfaces
Quoted 6 lines · Thomas Gleixner
All alarmtimer users are converted to
alarm_start_timer(). Remove the now unused interfaces.Signed-off-by Thomas Gleixner <[email protected]>Cc John Stultz <[email protected]>Cc Stephen Boyd <[email protected]>
Signature · 2 lines
Frederic Weisbecker SUSE Labs
[tip: timers/core] alarmtimer: Remove unused interfaces
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: ed78a701941999635389c41ddd638e8e7ea2470f Gitweb: https://git.kernel.org/tip/ed78a701941999635389c41ddd638e8e7ea2470f Author: Thomas Gleixner <[email protected]> AuthorDate: Wed, 08 Apr 2026 13:54:33 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Fri, 01 May 2026 21:36:14 +02:00
alarmtimer: Remove unused interfaces
All alarmtimer users are converted to alarm_start_timer(). Remove the now unused interfaces.
--- include/linux/alarmtimer.h | 3 +--- kernel/time/alarmtimer.c | 44 +------------------------------------- 2 files changed, 47 deletions(-)
include/linux/alarmtimer.h +0 -3
@@ -50,9 +50,6 @@ static __always_inline ktime_t alarm_get_expires(struct alarm *alarm)void alarm_init (struct alarm *alarm,enum alarmtimer_type type,void (*function)(struct alarm *,ktime_t ));bool alarm_start_timer (struct alarm *alarm,ktime_t expires,bool relative); -void alarm_start (struct alarm *alarm,ktime_t start); -void alarm_start_relative (struct alarm *alarm,ktime_t start); -void alarm_restart (struct alarm *alarm);int alarm_try_to_cancel (struct alarm *alarm);int alarm_cancel (struct alarm *alarm);
kernel/time/alarmtimer.c +0 -44
56 lines not on this page · raw message