Re: [patch 02/12] hrtimer: Provide hrtimer_start_range_ns_user()

From: Peter Zijlstra

Date: Tue Apr 07 2026 - 05:58:14 EST


On Tue, Apr 07, 2026 at 10:54:22AM +0200, Thomas Gleixner wrote:

> +static inline bool hrtimer_check_user_timer(struct hrtimer *timer)
> +{
> + struct hrtimer_cpu_base *cpu_base = timer->base->cpu_base;
> + ktime_t expires;
> +
> + /*
> + * This uses soft expires because that's the user provided
> + * expiry time, while expires can be further in the past
> + * due to a slack value added to the user expiry time.
> + */
> + expires = hrtimer_get_softexpires(timer);
> +
> + /* Convert to monotonic */
> + expires = ktime_sub(expires, timer->base->offset);
> +
> + /*
> + * Check whether this timer will end up as the first expiring timer in
> + * the CPU base. If not, no further checks required as it's then
> + * guaranteed to expire in the future.
> + */
> + if (expires >= cpu_base->expires_next)
> + return true;
> +
> + /* Validate that the expiry time is in the future. */
> + if (expires > ktime_get())
> + return true;
> +
> + debug_deactivate(timer);
> + __remove_hrtimer(timer, timer->base, HRTIMER_STATE_INACTIVE, false);
> + trace_hrtimer_start_expired(timer);
> + return false;
> +}
> +
> +static bool hrtimer_reprogram_user(struct hrtimer *timer)
> +{
> + if (!hrtimer_check_user_timer(timer))
> + return false;
> + hrtimer_reprogram(timer, true);
> + return true;
> +}
> +
> +static bool hrtimer_force_reprogram_user(struct hrtimer *timer)
> +{
> + bool ret = hrtimer_check_user_timer(timer);
> +
> + /*
> + * The base must always be reevaluated, independent of the result
> + * above because the timer was the first pending timer.
> + */
> + hrtimer_force_reprogram(timer->base->cpu_base, 1);
> + return ret;
> +}
> +
> +/**
> + * hrtimer_start_range_ns_user - (re)start an user controlled hrtimer
> + * @timer: the timer to be added
> + * @tim: expiry time
> + * @delta_ns: "slack" range for the timer
> + * @mode: timer mode: absolute (HRTIMER_MODE_ABS) or
> + * relative (HRTIMER_MODE_REL), and pinned (HRTIMER_MODE_PINNED);
> + * softirq based mode is considered for debug purpose only!
> + *
> + * Returns: True when the timer was queued, false if it was already expired
> + *
> + * This function cannot invoke the timer callback for expired timers as it might
> + * be called under a lock which the timer callback needs to acquire. So the
> + * caller has to handle that case.
> + */
> +bool hrtimer_start_range_ns_user(struct hrtimer *timer, ktime_t tim,
> + u64 delta_ns, const enum hrtimer_mode mode)
> +{
> + struct hrtimer_clock_base *base;
> + unsigned long flags;
> + bool ret = true;
> +
> + base = lock_hrtimer_base(timer, &flags);
> + switch (hrtimer_start_range_ns_common(timer, tim, delta_ns, mode, base)) {
> + case HRTIMER_REPROGRAM:
> + ret = hrtimer_reprogram_user(timer);
> + break;
> + case HRTIMER_REPROGRAM_FORCE:
> + ret = hrtimer_force_reprogram_user(timer);
> + break;
> + }
> + unlock_hrtimer_base(timer, &flags);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(hrtimer_start_range_ns_user);

Can we do that hrtimer_check_user_timer() in
hrtimer_start_range_ns_user() and then not duplicate
hrtimer_*reprogram() ?