]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
alarmtimer: Provide alarm_start_timer()
authorThomas Gleixner <tglx@kernel.org>
Wed, 8 Apr 2026 11:54:11 +0000 (13:54 +0200)
committerThomas Gleixner <tglx@kernel.org>
Fri, 1 May 2026 19:36:12 +0000 (21:36 +0200)
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.

Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: John Stultz <jstultz@google.com>
Link: https://patch.msgid.link/20260408114952.332822525@kernel.org
include/linux/alarmtimer.h
kernel/time/alarmtimer.c

index 3ffa5341dce21440f5822d726475bc8635a3dc4d..14d729fe0fd6f46fa4e003b7265d3e53d84338cb 100644 (file)
@@ -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);
index e10021be190fd3941370a226a8a7a2372cae4c33..2348b0839114cf3a60f75f736d0e64929311553a 100644 (file)
@@ -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];