]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
posix-timers: Handle the timer_[re]arm() return value
authorThomas Gleixner <tglx@kernel.org>
Wed, 8 Apr 2026 11:54:01 +0000 (13:54 +0200)
committerThomas Gleixner <tglx@kernel.org>
Fri, 1 May 2026 19:36:12 +0000 (21:36 +0200)
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 <tglx@kernel.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260408114952.198028466@kernel.org
kernel/time/posix-timers.c

index da04ed42bf82452346566e152b8b51a51e2b2cd5..db62cfac169d36f207801e62b2b77b55978a3333 100644 (file)
@@ -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_it
        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 *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;
 }